ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

TypeGraphQL 启动指南:从 buildSchema 构建可执行 Schema 到发布 HTTP GraphQL 端点

TypeGraphQL 启动指南:从 buildSchema 构建可执行 Schema 到发布 HTTP GraphQL 端点 后端GraphQLAPI设计【免费下载链接】type-graphqlCreate GraphQL schema and resolvers with TypeScript, using classes and decorators!项目地址https://gitcode.com/gh_mirrors/ty/type-graphql点击查看免费下载本篇技术指南围绕 TypeGraphQL 的 Bootstrapping启动装配流程展开系统讲解如何把编写好的 Resolver 类与类型类通过buildSchema转化为可执行的GraphQLSchema再借助apollo/server等 HTTP 服务器对外提供 GraphQL 端点并覆盖orphanedTypes、as const、路径通配加载、buildTypeDefsAndResolvers等进阶用法。读完本文你将能够从零搭建一个完整可运行的 TypeGraphQL 服务端入口并理解 schema 生成底层的元数据流转与类型注册机制。一、为什么需要 Bootstrap 环节当我们完成业务代码的编写——包括 Resolver 类Resolver修饰、对象类型类ObjectType、输入类型类InputType以及其他装饰器标注的类之后TypeScript 代码本身并不能直接对外提供服务。TypeGraphQL 的工作方式是运行时从装饰器元数据中读取类型与 Resolver 定义再统一生成一份标准的 GraphQL schema。因此启动阶段的核心任务有两步使用buildSchema从类型与 Resolver 定义构建出可执行的GraphQLSchema将该 schema 暴露给外部客户端常见载体包括 HTTP 服务器、WebSockets 订阅通道甚至 MQTT 协议。本文所在的仓库中examples/simple-usage/index.ts 就是一个典型的完整启动入口它同时演示了 schema 构建与 Apollo Server 挂载的全过程可作为本文所有示例的对照实现。二、使用 buildSchema 创建可执行 Schema2.1 基本用法要创建可执行的 schema需要使用buildSchema函数。它接收一个配置对象作为参数返回一个PromiseGraphQLSchema。配置对象中必须提供resolvers属性其值为一个由 Resolver 类组成的数组import { FirstResolver, SecondResolver } from ../app/src/resolvers; // ... const schema await buildSchema({ resolvers: [FirstResolver, SecondResolver], });从源码实现看src/utils/buildSchema.ts 中buildSchema会先将配置与 Resolver 数组交给SchemaGenerator.generateFromMetadata生成GraphQLSchema随后在设置了emitSchemaFile时把 SDL 写入磁盘文件。底层SchemaGenerator在 src/schema/schema-generator.ts 中完成了元数据克隆、错误检查、根查询/变更/订阅类型构建、孤儿类型补全最后还会用一次graphqlSync的 introspection 查询校验 schema 正确性可通过skipCheck跳过。2.2 resolvers 的作用域只有被引用的才会进入 schema需要特别注意只有 Resolver 类中定义的操作查询、变更、订阅等以及与其直接关联的类型才会被发射emit到最终 schema 中。这意味着一个ObjectType类如果既不是某个 Resolver 方法的返回类型、不是某个字段的类型、也不是联合类型Union的成员、更没有被接口类型引用那么它默认不会出现在 schema 里对于实现了接口类型且禁用了自动注册的对象类型同样存在无人引用即被忽略的风险。此时需要借助orphanedTypes选项手动把这些类型补齐进 schemaimport { FirstResolver, SecondResolver } from ../app/src/resolvers; import { FirstObject } from ../app/src/types; // ... const schema await buildSchema({ resolvers: [FirstResolver, SecondResolver], // 这里提供所有 schema 中缺失的类型 orphanedTypes: [FirstObject], });在 src/schema/schema-generator.ts 的SchemaGeneratorOptions中orphanedTypes被定义为可选的Function[]其生成流程位于buildOtherTypes(orphanedTypes)阶段即在根类型构建完成后单独把这些类型注册进最终的GraphQLSchema。2.3 单独定义 resolvers 数组时使用 as const如果 Resolver 数组不是内联写在buildSchema调用中而是先定义在别的模块里需要借助as const语法让 TypeScript 编译器将数组字面量推断为元组类型从而满足NonEmptyArrayT约束// resolvers.ts export const resolvers [FirstResolver, SecondResolver] as const; // schema.ts import { resolvers } from ./resolvers; const schema await buildSchema({ resolvers });NonEmptyArray的类型定义位于 src/typings/utils/NonEmptyArray.ts即readonly [T, ...T[]] | [T, ...T[]]——它要求数组至少有一个元素。不过类型约束只是编译期保障运行时仍有兜底校验buildSchema内部的loadResolverssrc/utils/buildSchema.ts会在resolvers.length 0时抛出Empty \resolvers array property found in buildSchema options! 错误。2.4 使用路径与通配符批量加载 Resolver当 Resolver 类数量较多时逐个手动 import 会非常繁琐。此时可以直接给resolvers传入模块文件路径数组路径中支持 glob 通配符const schema await buildSchema({ resolvers: [__dirname /modules/**/*.resolver.{ts,js}, __dirname /resolvers/**/*.{ts,js}], });注意当以文件路径形式提供 Resolver 时TypeGraphQL 会发射该 Resolver 文件及其依赖中所导入的全部操作与类型。因此文件路径模式适合目录结构清晰、按模块组织 Resolver 的项目如果依赖关系复杂请留意被意外纳入 schema 的类型。2.5 更多高级选项buildSchema的配置对象不仅包含resolvers与orphanedTypes。从源码来看BuildSchemaOptionssrc/utils/buildSchema.ts还包含emitSchemaFile并继承了SchemaGeneratorOptions与BuildContextOptions的全部字段。结合 src/schema/build-context.ts 可整理出常用选项选项类型作用emitSchemaFilestring \| boolean \| object将生成的 SDL 写入文件传true时写入当前工作目录下的schema.graphql传字符串则指定输出路径传对象可附带sortedSchema等打印选项skipCheckboolean跳过构建时基于 introspection 的 schema 正确性校验directivesGraphQLDirective[]传入自定义 GraphQL 指令scalarsMapScalarsTypeMap[]为自定义类型映射标量validateboolean \| ValidatorOptions是否使用class-validator自动校验注入参数validateFnValidatorFn自定义的参数校验函数authChecker/authModeAuthChecker/AuthMode授权相关配置pubSubPubSub订阅发布器配置globalMiddlewaresMiddleware[]全局中间件containerContainerType依赖注入容器nullableByDefaultboolean字段默认可空disableInferringDefaultValuesboolean禁止从属性初始值推断默认值其中与校验相关的validate、validateFn的详细说明可参阅验证文档。2.6 async 入口的完整骨架由于buildSchema返回 Promise必须在其外层声明async函数才能使用await。一个典型的main.ts入口文件如下import { buildSchema } from type-graphql; async function bootstrap() { const schema await buildSchema({ resolvers: [__dirname /**/*.resolver.{ts,js}], }); // 其他初始化代码比如创建 http server } bootstrap(); // 实际执行 async 函数为了捕获异步错误更稳健的写法是bootstrap().catch(console.error);这与仓库中 examples/simple-usage/index.ts 的做法一致。三、创建 HTTP GraphQL 端点大多数场景下 GraphQL 应用通过 HTTP 服务器对外提供访问。schema 构建完成后可以使用多种工具挂载端点常见的有graphql-yoga、apollo-server/apollo/server、express-graphql中间件等。下面以目前主流的apollo/server为例import { ApolloServer } from apollo/server; import { startStandaloneServer } from apollo/server/standalone; const PORT process.env.PORT || 4000; async function bootstrap() { // ... 在前面构建 schema // 创建 GraphQL server const server new ApolloServer({ schema }); // 启动 server const { url } await startStandaloneServer(server, { listen: { port: PORT } }); console.log(GraphQL server ready at ${url}); } bootstrap();需要提醒apollo/server或旧版的apollo-server是独立于 TypeGraphQL 的 npm 包需要自行安装它并不会随 TypeGraphQL 一起捆绑。完整的可运行版本可参考仓库示例 examples/simple-usage/index.ts它把emitSchemaFile、ApolloServer与startStandaloneServer组合在一起开箱即用。如果你的技术栈更偏好轻量方案也可以改用express-graphql中间件、graphql-yoga或任何你认为合适的 HTTP 集成方式——buildSchema的输出是标准GraphQLSchema对任何服务端框架都保持兼容。四、第二种方案buildTypeDefsAndResolvers 生成 typeDefs 与 resolvers 映射除了直接产出可执行的GraphQLSchemaTypeGraphQL 还提供了第二种 schema 生成方式——buildTypeDefsAndResolvers。它接受与buildSchema完全相同的BuildSchemaOptions配置但返回值不是GraphQLSchema而是一对typeDefsSDL 字符串与 resolversMapresolver 映射对象适合交给graphql-tools/schema等工具再组装import { makeExecutableSchema } from graphql-tools/schema; const { typeDefs, resolvers } await buildTypeDefsAndResolvers({ resolvers: [FirstResolver, SecondResolver], }); const schema makeExecutableSchema({ typeDefs, resolvers });该方案也可以与期望typeDefs resolvers形状的客户端状态库配合例如apollo-link-stateimport { withClientState } from apollo-link-state; const { typeDefs, resolvers } await buildTypeDefsAndResolvers({ resolvers: [FirstResolver, SecondResolver], }); const stateLink withClientState({ // ...其他选项如 cache typeDefs, resolvers, }); // ...其余 ApolloClient 初始化代码从实现上看src/utils/buildTypeDefsAndResolvers.ts 内部先调用buildSchema或其同步版本拿到 schema再通过printSchema序列化出 SDL并通过createResolversMap生成映射对象。createResolversMapsrc/utils/createResolversMap.ts按类型种类分别处理Object 类型收集isTypeOf与各字段的resolve有subscribe时同时保留订阅与解析Interface 类型生成__resolveType解析器优先复用类型自身的resolveType否则基于isTypeOf遍历可能的具体类型Scalar 类型直接映射为标量实例Enum 类型将枚举值名映射为底层值Union 类型生成__resolveType解析器。4.1 同步版本 buildTypeDefsAndResolversSync如果你希望完全同步地完成这一过程例如在无 async 上下文的初始化流程中可以使用buildTypeDefsAndResolversSyncconst { typeDefs, resolvers } buildTypeDefsAndResolversSync({ resolvers: [FirstResolver, SecondResolver], });与之对应buildSchema同样存在同步版本buildSchemaSync见 src/utils/buildSchema.ts两者内部通过SchemaGenerator.generateFromMetadata同步构建 schema仅当设置了emitSchemaFile时才使用同步或异步的文件写入分支src/utils/emitSchemaDefinitionFile.ts。4.2 使用限制部分高级特性不适用需要留意的是部分 TypeGraphQL 特性在buildTypeDefsAndResolvers方案下可能无法正常工作例如查询复杂度限制query complexity。原因在于这类特性依赖graphql-js的底层能力如GraphQLSchema原生的字段级配置与执行期钩子而 typeDefs resolvers 映射的组装方式会丢失这部分 schema 内建信息。因此若项目主要使用graphql-tools/schema或客户端 state 库的集成形态优先评估是否用到了复杂度限制等低层特性若对这类能力有强需求建议直接采用buildSchema方案以获得最完整的 TypeGraphQL 能力集。五、小结两种启动路径的选型对比维度buildSchemabuildTypeDefsAndResolvers返回值可执行的GraphQLSchema{ typeDefs, resolvers }对典型搭配Apollo Server、graphql-yoga、express-graphqlgraphql-tools/schema、apollo-link-state同步变体buildSchemaSyncbuildTypeDefsAndResolversSync高级特性支持完整含 query complexity部分底层特性如复杂度限制可能不生效使用前提需保证resolvers为非空数组必要时配orphanedTypes与as const同上且接受 typeDefs/resolvers 组装形态无论选择哪条路径启动装配的本质都是让 TypeGraphQL 读取装饰器元数据、生成标准 GraphQL 类型系统、再由你选择的服务端把 schema 暴露出去。从 examples/simple-usage/index.ts 出发动手实践是掌握 TypeGraphQL 启动流程最直接的方式。赞分享后端GraphQLAPI设计【免费下载链接】type-graphqlCreate GraphQL schema and resolvers with TypeScript, using classes and decorators!项目地址https://gitcode.com/gh_mirrors/ty/type-graphql点击查看免费下载相关推荐TypeGraphQL 应用引导启动实战从 buildSchema 构建 Schema 到部署 HTTP GraphQL 端点TypeGraphQL 应用引导启动实战从 buildSchema 构建 Schema 到部署 HTTP GraphQL 端点 导读 在完成 resolver后端GraphQLAPI设计TypeGraphQL 应用启动Bootstrapping完全指南从 buildSchema 到 HTTP 端点与 typeDefs 生成TypeGraphQL 应用启动Bootstrapping完全指南从 buildSchema 到 HTTP 端点与 typeDefs 生成 导读 在完成后端GraphQLAPI设计graphile-build 模块深入指南从 buildSchema 到 getBuilder 的插件化 GraphQL Schema 构建graphile build 模块深入指南从 buildSchema 到 getBuilder 的插件化 GraphQL Schema 构建 graphile后端API网关上一篇ncmdump30 秒无损解密 NCM网易云音乐直接转成 MP3/FLAC下一篇BilibiliDown一键下载B站视频与批量保存的完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表