NestJS+GraphQL错误格式化:国际化与结构化处理问询
NestJS GraphQL 国际化错误处理与BAD_USER_INPUT格式优化
问题描述
我正在使用NestJS搭建GraphQL服务器,希望API的所有错误信息都能根据浏览器发送的lang请求头实现国际化。目前在处理非显式抛出的异常时遇到问题,尤其是GraphQL验证导致的BAD_USER_INPUT错误。我想实现类似nestjs-i18n结合class-validator进行全局验证的方案,考虑使用异常过滤器捕获BAD_USER_INPUT错误并通过nestjs-i18n格式化响应。但收到的错误格式如下:
{ "message": "Variable \"$input\" got invalid value \"hello\" at \"input.id\"; Value is not a valid UUID: hello", "locations": [ { "line": 1, "column": 37 } ], "extensions": { "code": "BAD_USER_INPUT" } }
该消息包含了错误位置、值及违反的约束,但格式不够直观。请问NestJS是否有内置方式将这些信息转换为更便捷的格式(比如包含字段路径的path属性)?还是只能通过解析消息提取信息,这是否是最简洁的实现方式?
解决方案
1. 内置能力说明
NestJS没有直接将此类错误消息转换为结构化path属性的内置方法,但可以通过自定义异常过滤器结合GraphQL的GraphQLError类重构错误结构。
2. 解析错误消息(最简洁实现)
解析原始错误消息提取结构化信息是当前最直接的方案,步骤如下:
- 全局异常过滤器捕获
BAD_USER_INPUT类型的GraphQL错误 - 从消息中提取字段路径、错误值、约束类型
- 结合
nestjs-i18n根据lang请求头返回国际化消息 - 重构错误响应,添加
path等便捷属性到extensions
示例代码:
import { ExceptionFilter, Catch, ArgumentsHost } from '@nestjs/common'; import { GqlArgumentsHost } from '@nestjs/graphql'; import { GraphQLError } from 'graphql'; import { I18nService } from 'nestjs-i18n'; @Catch(GraphQLError) export class GraphqlExceptionFilter implements ExceptionFilter { constructor(private readonly i18n: I18nService) {} async catch(error: GraphQLError, host: ArgumentsHost) { const gqlHost = GqlArgumentsHost.create(host); const lang = gqlHost.getContext().req.headers['lang'] || 'en'; if (error.extensions.code === 'BAD_USER_INPUT') { const msgRegex = /Variable ".+" got invalid value "(.+)" at "(.+)"; (.+)/; const match = error.message.match(msgRegex); if (match) { const [, invalidValue, fieldPath, constraint] = match; // 提取约束关键词(如"Value is not a valid UUID") const constraintKey = constraint.split(':')[0].trim().replace(/\s+/g, '_').toLowerCase(); // 国际化翻译 error.message = await this.i18n.translate(`errors.${constraintKey}`, { lang, args: { field: fieldPath, value: invalidValue } }); // 添加结构化字段 error.extensions.path = fieldPath; error.extensions.invalidValue = invalidValue; } } return error; } }
3. 替换默认验证器(进阶方案)
如果不想解析消息,可以替换GraphQL默认验证逻辑,用class-validator直接验证输入参数,错误会自带结构化字段路径:
- 在GraphQL模块配置中启用
validationPipe - 为输入DTO添加
class-validator装饰器 - 自定义异常工厂,结合
nestjs-i18n生成国际化错误
示例配置:
import { Module } from '@nestjs/common'; import { GraphQLModule } from '@nestjs/graphql'; import { ValidationPipe } from '@nestjs/common'; import { I18nService } from 'nestjs-i18n'; @Module({ imports: [ GraphQLModule.forRootAsync({ useFactory: (i18n: I18nService) => ({ autoSchemaFile: 'schema.gql', context: ({ req }) => ({ req }), validationPipe: new ValidationPipe({ transform: true, exceptionFactory: async (errors) => { const req = errors[0].context?.req; const lang = req?.headers['lang'] || 'en'; // 转换验证错误为国际化格式 const translatedErrors = await Promise.all(errors.map(async (err) => { const constraintKey = Object.keys(err.constraints)[0]; return { field: err.property, message: await i18n.translate(`errors.${constraintKey}`, { lang, args: { value: err.value } }) }; })); return new Error(JSON.stringify(translatedErrors)); } }) }), inject: [I18nService] }) ] }) export class AppModule {}
内容的提问来源于stack exchange,提问作者Juan Chaves
相关产品推荐
相关产品推荐

