ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

TypeGraphQL 0.17 FAQ 实战指南:字段解析器、全局错误处理与类型定义的核心难题

TypeGraphQL 0.17 FAQ 实战指南:字段解析器、全局错误处理与类型定义的核心难题 后端GraphQLAPI设计【免费下载链接】type-graphqlCreate GraphQL schema and resolvers with TypeScript, using classes and decorators!项目地址https://gitcode.com/gh_mirrors/ty/type-graphql点击查看免费下载本篇技术指南以 TypeGraphQL 0.17.0 版本的官方 FAQ见 website/versioned_docs/version-0.17.0/faq.md以及同步维护的 docs/faq.md为骨架聚焦开发者在使用 TypeScript 类与装饰器构建 GraphQL Schema 时最常遇到的几类问题字段解析器应该写成 getter、对象类型方法还是解析器类方法如何用中间件实现全局错误处理InputType与ArgsType有何本质区别为什么会出现[object Object]与 “from another module or realm” 这类报错读完本文你将掌握这些问题的判定原则、修复步骤与底层原理并能在自己的 TypeGraphQL 项目中直接套用。Resolvers如何组织字段解析逻辑getter、对象类型方法与解析器类方法应该选哪个官方 FAQ 给出的决策原则可以归纳为三条它们分别对应 TypeGraphQL 中三种不同的字段解析实现载体如果你的解析逻辑只需要访问根/对象值root/object value优先使用 getter。例如在对象类型类中写get fullName(): string { return ... }此时解析逻辑与类型定义合并在同一处代码最简洁。如果字段带有参数arguments再分两种情况参数处理需要执行副作用side effect比如发起数据库调用则使用解析器类的方法并借助依赖注入dependency injection机制获取服务实例否则使用对象类型的方法把它当作纯函数仅基于对象值与参数计算结果。如果你希望把业务逻辑与类型定义彻底分离则使用解析器类的方法。从源码角度可以印证这三种载体的实现位置。TypeGraphQL 用 Field 装饰器收集类字段与“内部”字段解析器元数据而独立的解析器方法则通过 FieldResolver 以kind: external的形式注册两者都会在 schema 生成时被合并为 GraphQL 字段解析器。选择解析器类方法时依赖注入机制由 src/utils/container.ts 中的IOCContainer提供默认的DefaultContainer会缓存并复用类实例而传入自定义容器后getInstance()会把ResolverData含 context、root、args 等一并交给容器的get()方法这正是服务注入能感知每一次请求上下文的底层原因。有没有全局错误处理器能统一捕获 resolver 或 service 抛出的错误官方 FAQ 明确表示没有内置的全局错误处理器但你可以用中间件实现同样的效果。做法是把await next()包进 try-catch 块在 catch 里做你想要的处理记录日志、转换错误、统一返回格式等然后将该中间件注册为第一个全局中间件这样它就能覆盖所有后续解析逻辑。import { MiddlewareFn } from type-graphql; export const ErrorLogger: MiddlewareFn async ({}, next) { try { return await next(); } catch (err) { // 在这里统一处理错误例如打印日志或包装错误信息 throw err; } };注册为全局中间件时可以通过buildSchema({ globalMiddlewares: [ErrorLogger] })传入也可以把它当作第一个中间件传入其他全局中间件数组。中间件机制由 UseMiddleware 装饰器支撑——它既能作用于解析器类类级也能作用于单个字段方法级源码中通过collectResolverMiddlewareMetadata与collectMiddlewareMetadata分别收集这两类元数据。注意该装饰器在属性键为symbol时会抛出SymbolKeysNotSupportedError因此字段名需使用字符串。GraphQLError: Expected value of type MyType but got: [object Object]是怎么回事这条报错的含义是你的 resolver查询、变更或字段的返回类型是 interface 或 union但你返回了一个普通对象。graphql-js无法仅凭一个普通对象推断它对应哪个具体对象类型。解决办法很简单在 resolver 中返回所选对象类型类的实例。例如联合类型SearchResult由Recipe与Cook组成解析器里就必须return new Recipe(...)或return new Cook(...)而不是return { ... }。底层原因可以从 TypeGraphQL 的类型解析机制看出联合类型与接口的resolveType函数会在 schema 生成阶段被装配到对应节点见 src/schema/schema-generator.ts 中unionMetadata.resolveType、interfaceType.resolveType的接线逻辑其签名由 src/typings/TypeResolver.ts 定义最终resolveType会收到 GraphQL 的 (value, context, info) 参数并返回类型名或类。若返回的是普通对象graphql-js的默认类型解析逻辑无法匹配到任何具体类型自然就抛出[object Object]。同理若你自定义了resolveType函数也应确保它依据传入的值能稳定返回正确的类或类型名。Bootstrapping解决依赖版本冲突Cannot use GraphQLSchema [object Object] from another module or realm如何修复这个报错的根源几乎总是项目里存在多个版本的graphql-js。最常见的情形是某个间接依赖锁定了不同版本的graphql——例如 TypeGraphQL 使用v14.0.2而apollo-server-express却依赖v0.13.2两个版本各占一份node_modules实例schema 对象跨模块校验便失败。官方推荐的排查与修复步骤运行npm ls graphql或 yarn 等价命令yarn why graphql打印依赖树定位出哪些包引入了不匹配的版本对这些依赖执行升级或降级直到它们对graphql的 semver 范围一致例如统一为^14.0.0必要时做依赖扁平化让所有包共享node_modules下唯一一份graphql模块——直接运行npm dedupe或 yarn 等价命令即可。同样的处理规则也适用于另一条 TS 类型报错node_modules/type-graphql/node_modules/types/graphql/type/schema).GraphQLSchema is not assignable to type import(node_modules/types/graphql/type/schema).GraphQLSchema。此时只需把排查对象换成types/graphql模块重复上述三步。这一系列问题与 TypeGraphQL 自身的 schema 构建产物紧密相关——所有类型、解析器元数据最终都在 src/schema/schema-generator.ts 中被组装成GraphQLSchema任何跨副本的 schema 实例都会触发 realm 校验失败。Types类型定义的高频疑难InputType()与ArgsType()有什么区别两者完全不同。这是 FAQ 中明确强调的第一点InputType会生成真正的GraphQLInputType适用于参数里需要嵌套对象结构的场景生成的 SDL 形如updateItem(data: UpdateItemInput!): Item!ArgsType是虚拟的不会产生独立的输入类型其字段会被扁平化进解析器方法的参数列表生成的 SDL 形如updateItem(id: Int!, userId: Int!): Item!从实现上看两者在装饰器层面就走的不同元数据通道src/decorators/InputType.ts 调用collectInputMetadata注册输入类型且支持传入名称与描述而 src/decorators/ArgsType.ts 只调用collectArgsMetadata直接以类名注册不生成任何独立 GraphQL 类型节点。需要嵌套对象作为单个参数时用InputType希望多个参数扁平展开、便于单独校验时用ArgsType。什么时候必须用() [ItemType]数组语法只要字段类型是数组或 query/mutation 返回数组就应该显式使用[ItemType]数组语法。例如Field(() [Recipe]) recipes: Recipe[];虽然技术上在基础类型不是Promise时可以省略数组记号、只写Field(() ItemType) field: ItemType[]由 TypeScript 的design:type元数据推断数组但官方明确建议为了与其他注解保持一致始终显式声明数组类型。这一建议与 TypeGraphQL 的反射逻辑有关。在 src/helpers/findType.ts 中装饰器会读取design:type/design:returntype元数据同时检查 src/helpers/returnTypes.ts 列出的禁用类型[Promise, Array, Object, Function]——一旦设计类型落在禁用集合里例如直接声明为Promise却未提供返回类型函数就会抛出NoExplicitTypeError。此外当返回类型函数返回数组时如() [ItemType]findType会递归计算数组嵌套深度并设置array、arrayDepth选项这正是 schema 生成器能正确输出[ItemType]、[[ItemType]]等多层列表的依据。如何定义二维数组嵌套数组GraphQL 规范本身不支持二维数组该限制的讨论可追溯至 graphql-spec 的 issue #423所以不能直接把data: [[Float]]当作 GraphQL 类型。官方给出的替代方案是创建一个贴合数据的临时对象或输入类型再使用一维列表。例如先定义type DataPoint { x: Int y: Float }然后以列表形式引用data: [DataPoint]在 TypeScript 侧只需为DataPoint建立一个ObjectType()类若作为参数则用InputType()字段分别标注Field(() Int)与Field(() Float)data字段则声明为Field(() [DataPoint]) data: DataPoint[]。注意findType的数组深度检测虽然支持多层嵌套的返回类型函数findTypeValueArrayDepth会递归展开但这只是 TypeGraphQL 层的能力最终仍受限于 GraphQL 规范对列表类型表达能力的约束因此实践中务必使用“临时类型 一维列表”的模式。InputType 和 ObjectType 形状相同如何共享定义GraphQL 体系中输入对象与输出对象是独立类型系统对象类型可能包含循环引用、接口或联合类型字段这些都不适合作为输入参数。因此只有当类里只有简单字段标量、普通列表等不含复杂引用关系时才可以安全复用代码。复用方法非常直接在ObjectType类上再叠加一个InputType装饰器并显式指定新的类型名ObjectType() // 名称从类名推断为 Person InputType(PersonInput) export class Person {}之所以要换名字是因为 GraphQL 中输出类型与输入类型处于不同的命名空间之下也需要可区分的标识。两条装饰器的元数据会分别进入对象类型与输入类型集合前者由 src/decorators/ObjectType.ts 的collectObjectMetadata收集后者由 src/decorators/InputType.ts 的collectInputMetadata收集二者互不干扰schema 生成时会同时产出Person输出与PersonInput输入两个节点。小结围绕 TypeGraphQL 0.17 的官方 FAQ可以把实践中最重要的几条结论浓缩为问题结论字段解析器怎么写仅需根值用 getter带参数且有副作用用解析器类方法配合 DI纯计算用对象类型方法想解耦业务逻辑就用解析器类全局错误处理用中间件把await next()包进 try-catch并注册为第一个全局中间件[object Object]报错interface/union 场景必须返回对象类型类实例不能返回普通对象schema realm 报错npm ls graphql排查多版本统一 semver 后npm dedupe扁平化InputTypevsArgsType前者生成真实输入类型嵌套对象后者虚拟并被扁平化为独立参数数组类型字段/返回值是数组时始终显式使用() [ItemType]二维数组GraphQL 不支持改用临时对象类型 一维列表形状相同的输入/输出ObjectType类上叠加InputType(新名字)复用定义这些结论都能在仓库的装饰器实现src/decorators/、类型解析src/helpers/findType.ts、容器src/utils/container.ts与 schema 生成src/schema/schema-generator.ts等源码中找到对应依据可作为你排查问题时的第一手参考。赞分享后端GraphQLAPI设计【免费下载链接】type-graphqlCreate GraphQL schema and resolvers with TypeScript, using classes and decorators!项目地址https://gitcode.com/gh_mirrors/ty/type-graphql点击查看免费下载相关推荐TypeGraphQL FAQ 实战指南Resolver、启动引导与类型定义疑难全解TypeGraphQL FAQ 实战指南Resolver、启动引导与类型定义疑难全解 本篇指南以 TypeGraphQL 官方 FAQ 文档 website后端GraphQLAPI设计TypeGraphQL 实战 FAQ 深度解析Resolver 设计、Schema 引导与类型定义疑难全解TypeGraphQL 实战 FAQ 深度解析Resolver 设计、Schema 引导与类型定义疑难全解 本文围绕 TypeGraphQL 官方 FAQ 展后端GraphQLAPI设计如何快速集成Material Menu到你的Android应用5分钟快速开始教程如何快速集成Material Menu到你的Android应用5分钟快速开始教程 想要为你的Android应用添加流畅的Material Design动画图标后端GraphQLAPI设计创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表