NestJS ValidationPipe配置@ValidateNested和@Type后不校验嵌套对象问题
问题原因
ParentObject的Child属性缺少基础校验装饰器:class-validator默认会跳过没有任何基础校验装饰器的属性,仅配置@ValidateNested不足以触发嵌套校验逻辑。- Nest默认的ValidationPipe返回的校验错误为嵌套结构,不会自动拼接父属性前缀生成
Child.Data这类格式的扁平化错误消息,需要自定义异常工厂处理错误结构。
解决步骤
1. 修改父类定义,给嵌套属性新增基础校验装饰器
在parent-object.ts中给Child属性加上@IsObject()、@IsDefined()装饰器,确保嵌套属性会被识别为需要校验的字段:
import { Type } from 'class-transformer'; import { IsString, MinLength, ValidateNested, IsObject, IsDefined } from 'class-validator'; import { NestedObject } from './nested-object'; export class ParentObject { @IsString() @MinLength(1) public readonly FileName: string; @IsDefined() // 校验Child属性必须存在 @IsObject() // 校验Child必须为对象类型 @ValidateNested() @Type(() => NestedObject) public Child: NestedObject; }
2. 调整ValidationPipe配置,新增自定义异常工厂
修改测试用例中ValidationPipe的初始化参数,新增exceptionFactory配置,把嵌套的错误消息打平为带父属性前缀的格式:
const target: ValidationPipe = new ValidationPipe({ transform: true, whitelist: true, enableDebugMessages: true, errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY, // 自定义异常工厂,打平嵌套错误路径 exceptionFactory: (errors) => { const buildMessages = (errors: any[], parentPath = '') => { let messages: string[] = []; errors.forEach(err => { const currentPath = parentPath ? `${parentPath}.${err.property}` : err.property; if (err.constraints) { Object.values(err.constraints).forEach(msg => { // 调整消息格式,匹配预期输出 const formatMsg = msg.replace(/^[A-Z]/, c => c.toLowerCase()); messages.push(`${currentPath} ${formatMsg}`); }); } if (err.children?.length) { messages = messages.concat(buildMessages(err.children, currentPath)); } }); return messages; }; return { statusCode: HttpStatus.UNPROCESSABLE_ENTITY, message: buildMessages(errors), error: 'Unprocessable Entity' }; } });
修改完成后重新运行测试,即可返回预期的5条校验错误信息。
内容的提问来源于stack exchange,提问作者Steven Scott
相关产品推荐
相关产品推荐

