Nexus resolver返回ApolloError的类型安全实现及最佳实践问询
方案1:直接抛出错误(最推荐)
Apollo Server 会自动捕获 resolver 中抛出的错误,放入响应的errors字段,不需要将错误作为返回值返回,因此你根本不需要把错误类型加入Nexus的返回类型定义,完美解决类型冲突问题。
修改后的代码如下:
export const confirmEmail = mutationField('confirmEmail', { // 只定义成功的返回类型即可 type: nonNull(Boolean), args: { email: nonNull(stringArg()), code: nonNull(stringArg()), }, resolve: async (_, args, ctx) => { const user = await ctx.prisma.user.findUnique({ where: { email: args.email, }, }) if (!user) { // 直接抛出错误而不是返回 throw new ApolloError('User does not exists', 'BAD_USER_INPUT') } await sendEmail( 'jonashiltl2003@gmail.com', `<p>Your confirmation code is: </p> <b>${args.code}</b>`, 'Confirmation Code', ) return true }, })
这种方案完全符合GraphQL的规范,错误统一走顶级errors字段,客户端可以统一处理,同时完全满足TS类型安全要求,没有类型报错。
方案2:定义业务错误联合类型(适合需要把错误放到data字段的场景)
如果你希望业务错误和数据一起放到data字段返回,不走全局errors,可以用Nexus的unionType定义成功和错误的联合返回类型:
首先定义联合类型:
// 先定义错误类型 const UserNotFoundError = objectType({ name: 'UserNotFoundError', definition(t) { t.nonNull.string('message') t.nonNull.string('code') } }) // 定义返回结果联合类型 const ConfirmEmailResult = unionType({ name: 'ConfirmEmailResult', definition(t) { t.members('Boolean', 'UserNotFoundError') }, resolveType(value) { if (value instanceof ApolloError) { return 'UserNotFoundError' } return 'Boolean' } })
然后mutation的type直接用这个联合类型即可:
export const confirmEmail = mutationField('confirmEmail', { type: nonNull(ConfirmEmailResult), args: { email: nonNull(stringArg()), code: nonNull(stringArg()), }, resolve: async (_, args, ctx) => { const user = await ctx.prisma.user.findUnique({ where: { email: args.email, }, }) if (!user) { return new ApolloError('User does not exists', 'BAD_USER_INPUT') } await sendEmail( 'jonashiltl2003@gmail.com', `<p>Your confirmation code is: </p> <b>${args.code}</b>`, 'Confirmation Code', ) return true }, })
这种方案适合需要细分业务错误、让客户端在data层级处理错误的场景,同样完全保证类型安全。
内容的提问来源于stack exchange,提问作者JonasLevin
相关产品推荐
相关产品推荐

