后端GraphQLAPI设计【免费下载链接】type-graphqlCreate GraphQL schema and resolvers with TypeScript, using classes and decorators!项目地址https://gitcode.com/gh_mirrors/ty/type-graphql点击查看免费下载本篇技术指南聚焦 TypeGraphQL 中 GraphQL Union Type联合类型的完整实现方案从定义ObjectType类、通过createUnionType组装联合、到在Query中使用并解决运行时的类型判定问题。读完本文你将掌握如何让一个查询灵活返回多种对象类型如电影站点同时返回Movie或Actor、如何利用resolveType让 resolver 返回普通对象以及底层 Schema 生成器与元数据存储的实现原理。什么是 Union Type为什么需要它在真实 API 场景中一个查询的返回值往往不是单一、固定的类型而是一组可能类型中的某一种。比如电影网站的搜索功能用户输入关键词后数据库里既可能匹配到电影也可能匹配到演员因此搜索查询需要返回Movie | Actor这类结果。GraphQL 规范为此提供了Union Type联合类型——它表示返回的类型是以下类型之一客户端可以通过内联片段inline fragment按需选取字段。在 TypeGraphQL 中联合类型完全基于类与装饰器声明式构建无需手写 SDLSchema Definition Language类型安全由 TypeScript 编译期保证。第一步定义作为联合成员的对象类型联合类型的成员必须是ObjectType()装饰的类。沿用上文电影搜索的例子先创建两个对象类型ObjectType() class Movie { Field() name: string; Field() rating: number; }ObjectType() class Actor { Field() name: string; Field(type Int) age: number; }注意两点每个成员类必须用ObjectType()标记字段用Field()标记否则无法进入 Schema 生成流程Field(type Int)用于显式声明非推断的标量类型如number对应的 GraphQLInt确保生成的 SDL 准确。仓库中的官方示例 examples/enums-and-unions/cook.type.ts 展示了同样的写法Cook类使用Field(_type Int)声明yearsOfExperience。第二步用createUnionType组装联合类型TypeGraphQL 通过createUnionType函数将一组对象类型类声明为联合类型。这里用到了比较少见的[ ] as const语法——它的作用是告知 TypeScript 编译器这是一个元组tuple从而获得更精确的 TS 联合类型推断import { createUnionType } from type-graphql; const SearchResultUnion createUnionType({ name: SearchResult, // Name of the GraphQL union types: () [Movie, Actor] as const, // function that returns tuple of object types classes });配置对象的核心字段name联合类型在 GraphQL Schema 中的名称必填types返回对象类型类元组的函数必填。之所以设计为函数thunk而非直接传数组是为了解决循环引用问题——延迟到 Schema 构建阶段再解析具体类description可选的描述文本会写入生成的 GraphQL 描述resolveType可选的自定义类型判定函数详见下文Resolving Type小节。从源码看createUnionType的定义位于 src/decorators/unions.ts其泛型签名UnionTypeConfigTClassTypes extends readonly ClassType[]保证了传入types的类数组类型安全返回值为UnionFromClassesT工具类型。UnionFromClasses会把类元组映射为对应的 TS 联合类型如Movie | Actor因此后续typeof SearchResultUnion在编译期就等于Movie | Actor。底层上函数内部调用getMetadataStorage().collectUnionMetadata({ name, description, getClassTypes: types, resolveType })收集元数据并返回一个以name命名的 Symbol 作为该联合类型的标识见 src/metadata/metadata-storage.ts。联合类型元数据的结构定义在 src/metadata/definitions/union-metadata.ts包含getClassTypes、name、description?与resolveType?。第三步在 Query 中返回联合类型创建好联合后即可把它作为Query的返回类型。注意必须显式使用装饰器的返回类型标注returns ...因为 TypeScript 的反射emitDecoratorMetadata无法推断装饰器标注之外的泛型信息同时为了编译期类型安全方法返回类型应写为typeof SearchResultUnionResolver() class SearchResolver { Query(returns [SearchResultUnion]) async search(Arg(phrase) phrase: string): PromiseArraytypeof SearchResultUnion { const movies await Movies.findAll(phrase); const actors await Actors.findAll(phrase); return [...movies, ...actors]; } }这里[SearchResultUnion]表示返回的是联合类型的列表。官方示例 examples/enums-and-unions/resolver.ts 中search查询也采用了完全一致的写法Query(_returns [SearchResult]) async search(Arg(cookName) cookName: string): PromiseArraytypeof SearchResult { const recipes this.recipesData.filter(recipe recipe.cook.name.match(cookName)); const cooks this.cooks.filter(cook cook.name.match(cookName)); return [...recipes, ...cooks]; }联合类型同样可以出现在对象类型字段上在Field()中传入联合值即可测试用例 tests/functional/unions.ts 演示了Field(() OneTwoThreeUnion)的用法。Resolving Type运行时如何判定返回的具体类型这是联合类型使用中最容易踩坑的地方。当查询/变更的返回类型或字段类型是联合类型时resolver 必须返回对象类型类的具体实例。如果返回的是普通 JS 对象plain objectgraphql-js将无法确定底层 GraphQL 类型。默认行为基于instanceof的判定如果不提供resolveTypeTypeGraphQL 在 Schema 生成时会使用默认判定逻辑遍历联合的成员类用instance instanceof ObjectClassType判断返回值属于哪个类再映射到对应的 GraphQL 类型。从源码 src/schema/schema-generator.ts 可以看到若遍历后找不到匹配的类会抛出UnionResolveTypeError错误定义于 src/errors/UnionResolveTypeError.ts提示信息为Cannot resolve type for unionxxx! You need to return instance of object type class, not a plain object!对应的测试用例 tests/functional/unions.ts 专门验证了这一行为当 resolver 返回普通对象{ fieldTwo: fieldTwo }时查询结果报错错误消息包含 resolve、instance、plain 等关键词。自定义resolveType允许返回普通对象如果希望 resolver 返回普通对象例如直接返回 ORM 查询到的数据实体而不手动new类实例可以向createUnionType传入自定义的resolveType函数。此时由你根据数据对象的形状shape自行判定其类型const SearchResultUnion createUnionType({ name: SearchResult, types: () [Movie, Actor] as const, // Implementation of detecting returned object type resolveType: value { if (rating in value) { return Movie; // Return object type class (the one with ObjectType()) } if (age in value) { return Actor; // Or the schema name of the type as a string } return undefined; }, });resolveType的返回值支持两种形式见 src/typings/TypeResolver.ts 中TypeResolver类型定义MaybePromiseMaybestring | ClassType返回对象类型类本身如return MovieTypeGraphQL 会解析该类对应的 GraphQL 类型返回 Schema 中的类型名字符串如return Actor直接以字符串指定类型名。两相对照测试用例 tests/functional/unions.ts 分别构造了返回字符串UnionWithStringResolveType和返回类UnionWithClassResolveType的两种联合并验证在 resolver 返回普通对象时都能正确解析出__typename。此外测试还覆盖了resolveType返回undefined的边界情况——此时graphql-js会报出 Abstract type ... must resolve to an Object type at runtime 的标准错误见 tests/functional/unions.ts。底层原理Schema 生成器如何构建GraphQLUnionType在 Schema 构建阶段src/schema/schema-generator.tsTypeGraphQL 遍历metadataStorage.unions为每个联合创建一个GraphQLUnionTypetypes通过 thunk 延迟求值在对象类型全部构建完成后再从objectTypesInfoMap中取出成员类的GraphQLObjectType若配置了自定义resolveType则包装为getResolveTypeFunction否则使用默认的instanceof判定逻辑找不到匹配类时抛出UnionResolveTypeError。联合类型标识 Symbol 被记录在unionTypesInfoMap中供字段/查询类型解析时查表src/schema/schema-generator.ts。客户端查询示例Schema 构建完成后客户端可以这样发起查询利用内联片段按类型取字段query { search(phrase: Holmes) { ... on Actor { # Maybe Katie Holmes? name age } ... on Movie { # For sure Sherlock Holmes! name rating } } }... on Actor与... on Movie是 GraphQL 标准的内联片段语法客户端在拿到响应后可通过__typename区分具体类型。进阶参考完整示例与测试官方可运行示例更进阶的联合类型与枚举组合用法见 examples/enums-and-unions 目录其中 search-result.union.ts 定义了Recipe与Cook的联合SearchResultresolver.ts 展示了完整的查询实现schema.graphql为生成后的 SDL 参考功能测试联合类型的全部行为默认 instanceof 判定、字符串/类形式的resolveType、普通对象报错、同一联合用于多 Schema 构建等由 tests/functional/unions.ts 覆盖可作为验证和理解行为边界的权威依据。小结在 TypeGraphQL 中使用联合类型只需四步定义ObjectType成员类 → 用createUnionType组装并传入types元组 → 在Query的返回类型标注中引用联合值 → 确保 resolver 返回类实例或提供自定义resolveType以便返回普通对象。掌握resolveType的类/字符串两种返回形式与默认instanceof判定机制即可在实际项目中灵活设计多形态返回的查询接口。赞分享后端GraphQLAPI设计【免费下载链接】type-graphqlCreate GraphQL schema and resolvers with TypeScript, using classes and decorators!项目地址https://gitcode.com/gh_mirrors/ty/type-graphql点击查看免费下载相关推荐TypeGraphQL 中的联合类型Union Types用 createUnionType 构建灵活的多类型查询返回TypeGraphQL 中的联合类型Union Types用 createUnionType 构建灵活的多类型查询返回 GraphQL 的联合类型Uni后端GraphQLAPI设计type-graphql 联合类型Union Types实战用 createUnionType 构建可返回多类型结果的 GraphQL 查询type graphql 联合类型Union Types实战用 createUnionType 构建可返回多类型结果的 GraphQL 查询 本篇指南围绕后端GraphQLAPI设计type-graphql Union 类型实战指南用 createUnionType 构建灵活的多类型查询返回type graphql Union 类型实战指南用 createUnionType 构建灵活的多类型查询返回 在 GraphQL 服务开发中接口有时必须返后端GraphQLAPI设计上一篇F´ 遥测打包组件 Svc::TlmPacketizer 深入解析基于哈希槽的分组遥测架构与调优指南下一篇7个Riko流处理引擎实战痛点解决方案从入门到精通创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考