尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

TypeGraphQL 示例详解:从类型定义、Resolver 到第三方库集成实战指南

发布时间:2026/9/27 21:10:27

资讯中心
01
ARTICLE

TypeGraphQL 示例详解:从类型定义、Resolver 到第三方库集成实战指南

TypeGraphQL 示例详解:从类型定义、Resolver 到第三方库集成实战指南
后端GraphQLAPI设计【免费下载链接】type-graphqlCreate GraphQL schema and resolvers with TypeScript, using classes and decorators!项目地址https://gitcode.com/gh_mirrors/ty/type-graphql点击查看免费下载本文以 TypeGraphQL 官方仓库中的examples目录为线索系统梳理该框架从基础用法到进阶特性、再到第三方库集成的完整实践路径。无论你是刚接触 classes decorators 式 GraphQL 开发的新手还是准备把 TypeGraphQL 接入 TypeORM、Apollo Federation、Redis 等生态的老手都可以在本文中找到可直接照搬的运行方式、配置要点与源码级原理佐证。示例仓库概览从哪里看、怎么跑TypeGraphQL 仓库在 examples 目录下维护了数十个独立可运行的示例工程每个子目录都是一个完整的、带index.ts入口的服务专门演示某一类或某几类框架特性的用法以及框架与第三方库的集成方式。所有示例都遵循统一的运行模式详见 examples/README.md进入目标示例目录例如cd ./simple-usage启动服务npx ts-node ./index.ts每个子目录中都包含一个examples.graphql文件里面预置了可直接执行的 query / mutation / subscription 示例可以粘贴到 Apollo Studio默认地址http://localhost:4000中运行并通过修改查询形态与数据来加深理解。需要特别说明的是master 分支上的示例与最新可能尚未发布的代码库保持同步如果你正在使用某个已发布版本如 1.0.0应按照对应版本 tag 下的 examples 来对照学习。此外部分示例依赖本地外部服务运行前需要按需提供环境变量——以当前仓库为准涉及数据库的示例TypeORM、MikroORM、Typegoose需要设置DATABASE_URL指向本地数据库Redis 订阅示例需要设置REDIS_URL指向本地 Redis 实例。基础入门字段、基本类型与 Resolversimple-usage是整个 examples 目录的起点完整展示了 TypeGraphQL 的核心工作流用类声明 GraphQL 类型用装饰器声明字段与操作最后用buildSchema一键生成可执行 Schema。启动入口buildSchema Apollo Serverexamples/simple-usage/index.ts 中的引导逻辑是所有示例的标准模板import reflect-metadata; import path from node:path; import { ApolloServer } from apollo/server; import { startStandaloneServer } from apollo/server/standalone; import { buildSchema } from type-graphql; import { RecipeResolver } from ./recipe.resolver; async function bootstrap() { // Build TypeGraphQL executable schema const schema await buildSchema({ // Array of resolvers resolvers: [RecipeResolver], // Create schema.graphql file with schema definition in current directory emitSchemaFile: path.resolve(__dirname, schema.graphql), }); // Create GraphQL server const server new ApolloServer({ schema }); // Start server const { url } await startStandaloneServer(server, { listen: { port: 4000 } }); console.log(GraphQL server ready at ${url}); } bootstrap().catch(console.error);注意几个关键点必须import reflect-metadataTypeGraphQL 依赖 reflect-metadata 的装饰器元数据能力所有示例的入口文件都会先引入它buildSchema的resolvers数组集中登记所有 Resolver 类emitSchemaFile会在当前目录生成schema.graphql本仓库源码中为src/utils/buildSchema.ts内的 Schema 生成流程所支持方便你直接查看最终的 SDL 定义端口统一为4000配合 Apollo Studio 使用。用类与装饰器定义 ObjectTypeexamples/simple-usage/recipe.type.ts 展示了 ObjectType 的声明方式几乎覆盖了所有基础字段形态import { Field, Float, Int, ObjectType } from type-graphql; ObjectType({ description: Object representing cooking recipe }) export class Recipe { Field() title!: string; Field(_type String, { nullable: true, deprecationReason: Use description field instead }) get specification(): string | undefined { return this.description; } Field({ nullable: true, description: The recipe description with preparation info }) description?: string; Field(_type [Int]) ratings!: number[]; Field() creationDate!: Date; Field(_type Int) ratingsCount!: number; Field(_type Float, { nullable: true }) get averageRating(): number | null { // ... 计算逻辑 } }值得逐条拆解类型推断与显式声明title!: string这类字段TypeGraphQL 通过反射自动映射为 GraphQL 的StringDate默认映射为内置的DateTime标量而[Int]、Float等则需要通过_type Int/_type [Int]/_type Float的箭头函数显式声明这既是 TS 与 GraphQL 类型系统之间的桥接也是框架在 src/helpers/findType.ts 等底层实现中解析类型的依据字段选项nullable控制可空性description会写入 Schema 描述deprecationReason对应 GraphQL 的deprecated指令getter 也能成为字段specification、averageRating都是类上的 getterTypeGraphQL 会把它们识别为普通字段这避免了为每个计算属性手写 FieldResolver 的样板代码。定义输入类型 InputTypeexamples/simple-usage/recipe.input.ts 演示了 mutation 输入对象的标准写法import { Field, InputType } from type-graphql; import { type Recipe } from ./recipe.type; InputType() export class RecipeInput implements PartialRecipe { Field() title!: string; Field({ nullable: true }) description?: string; }通过implements PartialRecipe建立 TS 层面的类型关联字段与 ObjectType 一一对应GraphQL 侧会生成等价的input RecipeInput类型。编写 ResolverQuery / Mutation / FieldResolverexamples/simple-usage/recipe.resolver.ts 是功能最完整的入门示例Resolver(_of Recipe) export class RecipeResolver implements ResolverInterfaceRecipe { private readonly items: Recipe[] createRecipeSamples(); Query(_returns Recipe, { nullable: true }) async recipe(Arg(title) title: string): PromiseRecipe | undefined { return this.items.find(recipe recipe.title title); } Query(_returns [Recipe], { description: Get all the recipes from around the world }) async recipes(): PromiseRecipe[] { return this.items; } Mutation(_returns Recipe) async addRecipe(Arg(recipe) recipeInput: RecipeInput): PromiseRecipe { const recipe Object.assign(new Recipe(), { description: recipeInput.description, title: recipeInput.title, ratings: [], creationDate: new Date(), }); await this.items.push(recipe); return recipe; } FieldResolver() ratingsCount( Root() recipe: Recipe, Arg(minRate, _type Int, { defaultValue: 0 }) minRate: number, ): number { return recipe.ratings.filter(rating rating minRate).length; } }要点Resolver(_of Recipe)把类标记为针对Recipe类型的 Resolver是FieldResolver生效的前提参数注入Arg(title)注入单个参数Root()注入父对象FieldResolver 的宿主实例Arg(..., { defaultValue: 0 })还能为参数声明默认值——ratingsCount(minRate: 2)这类带默认值参数的字段查询在 examples/simple-usage/examples.graphql 中有现成的调用示例数据来自 examples/simple-usage/recipe.data.ts 中预置的 3 条内存样本无需数据库即可跑通。进阶特性枚举、联合、订阅与扩展元数据枚举与联合类型examples/enums-and-unions/difficulty.enum.ts 展示了 TS 枚举注册为 GraphQL 枚举的方式import { registerEnumType } from type-graphql; export enum Difficulty { Beginner, Easy, Medium, Hard, MasterChef, } registerEnumType(Difficulty, { name: Difficulty, description: All possible preparation difficulty levels, });registerEnumType是枚举进入 Schema 的唯一入口name决定在 SDL 中的枚举名description写入枚举描述。联合类型的用法见 examples/enums-and-unions/resolver.tssearchQuery 返回[SearchResult]其中SearchResult是由Recipe与Cook通过createUnionType组合而成的联合对应文件 examples/enums-and-unions/search-result.union.ts同时该 Query 还演示了把Difficulty枚举作为可选过滤参数Arg(difficulty, _type Difficulty, { nullable: true })。订阅从简单 PubSub 到 Redis 与动态 Topicexamples/simple-subscriptions/notification.resolver.ts 是订阅特性的集中展示覆盖了四种典型场景基础订阅Subscription({ topics: Topic.NOTIFICATIONS })由pubSub.publish触发对应文件 examples/simple-subscriptions/pubsub.ts基于 graphql-subscriptions 的PubSub实例过滤订阅通过filter选项在SubscriptionHandlerData上按 payload 条件过滤例如payload.id % 2 0多 Topic 订阅topics传入数组[Topic.NOTIFICATIONS, NOTIFICATIONS_2]动态 Topic / 动态 Topic IDtopics: ({ args }) args.topic按查询参数动态选择 TopictopicId选项支持按参数动态订阅带 ID 的 Topic。当需要跨进程/多实例共享事件时使用 examples/redis-subscriptions 示例它在 examples/redis-subscriptions/index.ts 中通过buildSchema({ ..., pubSub, validate: false })把 Redis 驱动的 PubSub 实例注入框架并使用graphql-yoga承载订阅的 WebSocket 传输运行前需提供REDIS_URL环境变量。接口与继承examples/interfaces-inheritance 演示了两层能力接口定义IPerson与接口的多种实现类型Student、Employee。在 examples/interfaces-inheritance/resolver.ts 中persons()Query 返回[IPerson]——GraphQL 需要运行时识别每个条目的具体类型因此示例里强调必须创建真实的类实例Object.assign(new Student(), {...})而不是返回裸对象。同一个示例还覆盖了输入类型层面的继承EmployeeInput、StudentInput对应 docs/interfaces.md 中讲解的接口与继承完整规则。Extensions向 Schema 注入自定义元数据examples/extensions 示例展示Extensions装饰器它允许你为字段/类型附加自定义元数据键值对这些元数据最终写入 Schema 的 extensions 字段供上层工具读取。该示例还配套了自定义的 examples/extensions/log-message.decorator.ts基于createMethodDecorator以及一个全局中间件 examples/extensions/logger.middleware.ts后者通过buildSchema({ globalMiddlewares: [LoggerMiddleware] })挂载见 examples/extensions/index.ts。特性实战容器、鉴权、验证与类型复用依赖注入IoC 容器与作用域容器TypeGraphQL 本身不提供 DI但buildSchema的container选项可以桥接任意第三方 IoC 容器。两个示例分别演示了两种容器examples/using-container基于typedi。在 examples/using-container/index.ts 中通过Container.set({ id: SAMPLE_RECIPES, factory: () sampleRecipes.slice() })注册数据buildSchema({ container: Container })注册容器Resolver 侧examples/using-container/recipe.resolver.ts用Service()标记可注入类、用Inject()注入RecipeServiceQuery / Mutation 只做参数转发业务逻辑全部沉淀在 service 中examples/tsyringe同样的模式换用tsyringe。由于 tsyringe 不直接兼容 TypeGraphQL 的容器接口需要做适配层container: { get: cls container.resolve(cls) }见 examples/tsyringe/index.ts。对于每次请求独立实例的需求参考 examples/using-scoped-container它通过按请求创建容器实例的方式让每个请求获得独立的 service 状态适合需要请求级上下文如日志、追踪的场合。授权Authorized 与 authCheckerexamples/authorization 是权限控制的完整示例。核心用法在 examples/authorization/recipe.resolver.tsAuthorized() // Only authenticated users can add new recipe Mutation() addRecipe(...) { ... } Authorized(ADMIN) // Only ADMIN users can remove published recipe Mutation() deleteRecipe(...) { ... }Authorized()不带参数表示只要通过鉴权即可Authorized(ADMIN)带参数则要求用户角色匹配。鉴权判定逻辑由 examples/authorization/auth-checker.ts 中的authChecker函数实现并通过buildSchema({ authChecker })启用参考 docs/authorization.md。注意被Authorized保护的字段必须显式标记为nullable或在buildSchema中设置authMode: null否则未授权请求会直接抛错。自动验证与自定义验证自动验证examples/automatic-validation 演示 TypeGraphQL 内置的、基于class-validator的自动校验在 InputType / ArgsType 的字段上用MinLength、IsInt等校验装饰器标注规则见 examples/automatic-validation/recipe.input.ts框架会在参数解析时自动执行校验不合法则抛出ArgumentValidationError自定义验证examples/custom-validation 在此基础上展示自定义校验函数与更细粒度的控制对应 docs/validation.md。类型复用三件套类型继承、Resolver 继承、泛型与 Mixinexamples 目录中有四个示例专门解决如何复用类型与逻辑类型继承 / 接口继承interfaces-inheritance上文已述类型通过ObjectType({ implements: ... })继承接口或父类Resolver 继承examples/resolvers-inheritance/recipe/recipe.resolver.ts 中RecipeResolver extends ResourceResolver(Recipe, recipes)——基类ResourceResolver是一个返回类的工厂函数预先实现了通用的getOne、getAll、delete等操作子类只需补充资源专属逻辑如averageRatingFieldResolver大幅减少跨资源的重复代码泛型类型examples/generic-types/paginated-response.type.ts 定义了分页响应工厂export function PaginatedResponseTItemsFieldValue extends object( itemsFieldValue: ClassTypeTItemsFieldValue | string | number | boolean, ) { ObjectType() abstract class PaginatedResponseClass { Field(_type [itemsFieldValue]) items!: TItemsFieldValue[]; Field(_type Int) total!: number; Field() hasMore!: boolean; } return PaginatedResponseClass; }由于 TS 装饰器无法直接表达泛型必须用工厂函数返回临时类的模式实例化见 examples/generic-types/recipe.resolver.ts 中的class RecipesResponse extends PaginatedResponse(Recipe) {}对应 docs/generic-types.md。Mixin 类examples/mixin-classes 通过with.id、with.password等 mixin 工厂按需组合字段。它在输入层区分了CreateUserInput含密码与AmendUserInput只读密码、可改其他字段见 examples/mixin-classes/resolver.ts 中的createUser/amendUser两个 mutation 如何共用 mixin 字段又保持权限边界。中间件与自定义装饰器examples/middlewares-custom-decorators 是组合拳示例同时演示了三个能力类级/方法级中间件UseMiddleware(ResolveTimeMiddleware)既可以用在类上覆盖全部操作也可以用在单个方法上参数装饰器CurrentUser()通过 examples/middlewares-custom-decorators/decorators/current-user.ts 中的createParameterDecorator从 context 提取当前用户RandomIdArg则用createParameterDecorator在参数层做随机值注入可复用的中间件类examples/middlewares-custom-decorators/middlewares/log-access.ts 实现MiddlewareInterfaceContext在use({ context, info }, next)中记录访问日志后调用next()展示了面向切面的日志/统计中间件标准写法。Query Complexity防滥用查询examples/query-complexity/index.ts 演示了如何用graphql-query-complexity库给 Schema 计算查询复杂度并拦截超限请求const MAX_COMPLEXITY 20; // 在 Apollo plugin 的 didResolveOperation 钩子中 const complexity getComplexity({ schema, operationName: request.operationName, query: document, variables: request.variables, estimators: [ // Using fieldExtensionsEstimator is mandatory to make it work with type-graphql fieldExtensionsEstimator(), // 兜底每个字段默认复杂度为 1 simpleEstimator({ defaultComplexity: 1 }), ], }); if (complexity MAX_COMPLEXITY) { throw new Error( Sorry, too complicated query! ${complexity} exceeded the maximum allowed complexity of ${MAX_COMPLEXITY}, ); }关键点fieldExtensionsEstimator会读取 TypeGraphQL 通过Extensions({ complexity: n })写入的复杂度元数据因此它是让复杂度计算与 TypeGraphQL 协同工作的必备估计器simpleEstimator作为兜底为每个字段赋值 1。这套方案能有效抵御深度嵌套/高扇出查询带来的资源耗尽与 DoS 风险对应 docs/complexity.md。第三方库集成ORM、联邦与工具链TypeORM手动同步与懒加载关系TypeORM 有两个示例对应两种数据访问风格手动同步examples/typeorm-basic-usage 在 examples/typeorm-basic-usage/index.ts 中先await dataSource.initialize()建立连接seedDatabase()预置数据再buildSchema。实体examples/typeorm-basic-usage/entities/recipe.ts 等同时作为 TypeGraphQL 的 ObjectType通过ObjectType()Field()与 TypeORM 的Entity()Column()叠加使用Resolvers 则通过注入 DataSource 或 Repository 手写查询examples/typeorm-basic-usage/resolvers/recipe.resolver.ts自动懒加载examples/typeorm-lazy-relations 利用 TypeORM 的懒加载关系PromiseT字段与 TypeGraphQL 的FieldResolver配合让关系字段按需加载避免 N1 式的整表预取。两个示例都通过dotenv/config读取DATABASE_URL见 examples/typeorm-basic-usage/index.ts 中的import dotenv/config运行前需按本地数据库修改连接串。MikroORMexamples/mikro-orm 是 MikroORM 的集成示例结构上与 TypeORM 示例平行实体examples/mikro-orm/entities/recipe.ts上叠加Entity()与ObjectType()通过 examples/mikro-orm/helpers.ts 完成初始化与播种同样依赖DATABASE_URL环境变量。TypegooseMongooseexamples/typegoose 把 TypeGraphQL 与 Mongoose/Typegoose 集成。由于 Mongoose 返回的是Model文档实例而非普通类实例示例专门实现了一个转换中间件 examples/typegoose/typegoose.middleware.tsfunction convertDocument(doc: Document) { const convertedDocument doc.toObject(); const DocumentClass getClass(doc)!; Object.setPrototypeOf(convertedDocument, DocumentClass.prototype); return convertedDocument; } export const TypegooseMiddleware: MiddlewareFn async (_, next) { const result await next(); if (Array.isArray(result)) { return result.map(item (item instanceof Model ? convertDocument(item) : item)); } if (result instanceof Model) { return convertDocument(result); } return result; };它把 Mongoose 文档转换为原型链指向 TypeGraphQL 类的普通对象从而让FieldResolver与 getter 字段正常工作。另外还配套了一个自定义 ObjectId 标量 examples/typegoose/object-id.scalar.ts说明自定义标量如何落地参考 docs/scalars.md。Apollo Federation 与 Federation 2联邦是多服务组成统一 Schema的 GraphQL 架构方案examples 提供了两代实现examples/apollo-federation经典版联邦包含 accounts、inventory、products、reviews 四个子图服务。核心桥梁是 examples/apollo-federation/helpers/buildFederatedSchema.tsconst schema await buildSchema({ ...options, // Disable check to allow schemas without query, etc... skipCheck: true, }); const federatedSchema buildSubgraphSchema({ typeDefs: gql(printSchemaWithDirectives(schema)), resolvers: deepMerge(createResolversMap(schema) as any, referenceResolvers), });它先用skipCheck: true允许子图没有独立的 Query 根再通过printSchemaWithDirectives导出 SDL、用createResolversMap把 TypeGraphQL 的解析器还原为普通 Resolver Map最后交给buildSubgraphSchema生成联邦子图。ReferenceResolver装饰器用于实现实体的引用解析见 examples/apollo-federation/accounts/user.reference.ts 这类文件examples/apollo-federation-2Federation 2 版本除了上述四类子图外还加入了 Dining、Seating 等实体展示联邦 2 的实体扩展写法对应 docs/resolvers.md 中关于ReferenceResolver的说明。Apollo Cache Control 与 GraphQL Scalarsexamples/apollo-cache演示 Apollo Cache Control 的缓存提示。核心是 examples/apollo-cache/cache-control.ts 中基于 TypeGraphQLDirective封装的自定义装饰器CacheControl({ maxAge, scope })——它把参数拼装为cacheControl(maxAge: ..., scope: ...)SDL 指令并注入字段从而让 Apollo 的缓存层读取到精确的缓存策略examples/graphql-scalars集成graphql-scalars库把DateTime、PositiveInt等额外标量注册进 TypeGraphQL Schema对应 docs/scalars.md解决框架内置标量覆盖不足的问题。快速对照表按需求选择示例目标需求推荐示例目录入门类型、字段、Query/Mutation/FieldResolverexamples/simple-usage枚举与联合类型examples/enums-and-unions订阅内存 PubSub / Redis / 动态 Topicexamples/simple-subscriptions、examples/redis-subscriptions接口、继承、泛型、Mixin 复用examples/interfaces-inheritance、examples/resolvers-inheritance、examples/generic-types、examples/mixin-classes依赖注入typedi / tsyringe / scopedexamples/using-container、examples/using-scoped-container、examples/tsyringe鉴权、验证、中间件、扩展元数据examples/authorization、examples/automatic-validation、examples/custom-validation、examples/middlewares-custom-decorators、examples/extensions查询复杂度防护examples/query-complexity数据库 ORMTypeORM / MikroORM / Typegooseexamples/typeorm-basic-usage、examples/typeorm-lazy-relations、examples/mikro-orm、examples/typegooseApollo Federation / 缓存控制 / 额外标量examples/apollo-federation、examples/apollo-federation-2、examples/apollo-cache、examples/graphql-scalars结语examples 目录是学习 TypeGraphQL 最直接、最贴近实战的资料库每一个特性都有独立可运行的最小工程每一个工程都配套了examples.graphql预置查询和schema.graphql生成结果可以边改边跑、对照验证。本文依据的版本为 1.0.0 文档快照见 website/versioned_docs/version-1.0.0/examples.md而当前仓库的 examples/README.md 已同步更新到最新的示例清单如新增的 MikroORM、Federation 2、TSyringe 等若需与某个具体发布版本严格对齐建议按对应版本 tag 浏览 examples。在此基础上再配合 docs 目录中的专项文档如 docs/middlewares.md、docs/subscriptions.md、docs/dependency-injection.md即可系统性地掌握 TypeGraphQL 从入门到生产落地的全部要点。赞分享后端GraphQLAPI设计【免费下载链接】type-graphqlCreate GraphQL schema and resolvers with TypeScript, using classes and decorators!项目地址https://gitcode.com/gh_mirrors/ty/type-graphql点击查看免费下载相关推荐TypeGraphQL 示例仓库完全指南从快速启动到第三方集成实战TypeGraphQL 示例仓库完全指南从快速启动到第三方集成实战 导读 本指南以 TypeGraphQL 仓库中 docs/examples.md 所整理的后端GraphQLAPI设计TypeGraphQL 官方示例全览从基础字段到 TypeORM、Redis 订阅与第三方库集成实战TypeGraphQL 官方示例全览从基础字段到 TypeORM、Redis 订阅与第三方库集成实战 本篇技术指南基于 TypeGraphQL 仓库 exam后端GraphQLAPI设计TypeGraphQL 继承指南复用类型定义与 Resolver 基类的完整实践TypeGraphQL 继承指南复用类型定义与 Resolver 基类的完整实践 TypeGraphQL 的核心思想是用 TypeScript 类来定义 G后端GraphQLAPI设计上一篇如何实现多设备无缝连接Gadgetbridge设备协调器模式深度解析下一篇clawdbot跨平台同步技巧在所有设备上保持一致体验创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。