NestJS+GraphQL自定义校验错误响应格式方案咨询
NestJS GraphQL 自定义校验错误格式(class-validator风格)
问题背景
使用NestJS + GraphQL + PostgreSQL时,校验失败返回的错误格式不符合需求,需要统一改为class-validator风格的响应,要求包含数组形式的message、BAD_USER_INPUT错误码、400状态码等。
解决方案
1. 完善DTO校验规则
修正DTO中的校验配置,确保class-validator规则正确生效,同时匹配GraphQL字段定义:
import { Field, InputType } from "@nestjs/graphql"; import { IsEnum, MinLength, IsOptional, IsNumber } from "class-validator"; import { PoolType, Status } from "src/pool/entities/pool.enum"; @InputType() export class CreatePoolInput { @Field() @IsNumber() orgId: number; @Field({ nullable: true }) // 可选字段需显式声明nullable @IsOptional() @MinLength(3) // 添加长度校验规则 clientId?: string; // 根据校验需求调整类型,这里假设为字符串 @IsEnum(PoolType) @Field() type: PoolType; @Field({ nullable: true }) name: string; @Field({ nullable: true }) description: string; @Field({ nullable: true }) list: string; @IsEnum(Status) @Field() status: Status; }
2. 全局配置ValidationPipe
在AppModule中开启全局校验管道,确保class-validator的错误被正确抛出:
import { Module } from '@nestjs/common'; import { APP_PIPE } from '@nestjs/core'; import { ValidationPipe } from '@nestjs/common'; @Module({ providers: [ { provide: APP_PIPE, useValue: new ValidationPipe({ transform: true, // 自动转换请求数据类型 whitelist: true, // 过滤DTO未定义字段 forbidNonWhitelisted: true, // 非白名单字段直接报错 errorHttpStatusCode: 400, // 校验失败返回400状态码 }), }, ], }) export class AppModule {}
3. 修改formatError函数统一错误格式
更新GraphQL的formatError函数,分别处理GraphQL内置校验错误和class-validator校验错误,统一转换为期望格式:
formatError: (error) => { // 处理GraphQL内置校验错误(如必填字段缺失、类型不匹配) if (error.extensions?.code === 'GRAPHQL_VALIDATION_FAILED') { const fieldMatch = error.message.match(/Field \"(\w+\.\w+)\"/); const fieldName = fieldMatch ? fieldMatch[1].split('.')[1] : 'unknown field'; let errorMessage: string; if (error.message.includes('was not provided')) { errorMessage = `${fieldName} is required`; } else if (error.message.includes('type mismatch')) { errorMessage = `${fieldName} has invalid type`; } else { errorMessage = error.message; } return { message: [errorMessage], code: 'BAD_USER_INPUT', name: 'UserInputError', statusCode: 400, }; } // 处理class-validator抛出的校验错误 if (error.extensions?.response?.statusCode === 400) { return { message: Array.isArray(error.extensions.response.message) ? error.extensions.response.message : [error.extensions.response.message], code: 'BAD_USER_INPUT', name: 'UserInputError', statusCode: 400, }; } // 其他服务器错误保持原有格式 return { message: [error.message], code: error.extensions?.code || 'SERVER_ERROR', name: error.extensions?.name || error.name, statusCode: error?.extensions?.response?.statusCode || error?.statusCode || 500, }; },
效果验证
修改后,校验失败时会返回符合要求的响应格式:
{ "errors": [ { "message": [ "clientId must be longer than or equal to 3 characters" ], "code": "BAD_USER_INPUT", "name": "UserInputError", "statusCode": 400 } ] }
内容的提问来源于stack exchange,提问作者nabeel
相关产品推荐
相关产品推荐

