如何在NestJS中验证动态键值结构的DTO?
在NestJS中校验动态键值对结构的DTO字段
要实现data字段(动态键、值为TestDto类型)的校验,核心是利用class-validator和class-transformer的装饰器组合,针对动态键值对的特性做适配。以下是具体实现步骤:
1. 确保依赖与全局校验配置
NestJS的DTO校验依赖class-validator和class-transformer,未安装的话先执行:
npm install class-validator class-transformer
同时在main.ts中开启全局校验管道,自动处理请求体转换与校验:
import { ValidationPipe } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalPipes(new ValidationPipe({ transform: true, // 自动将请求体转换为DTO实例 whitelist: true, // 过滤DTO中未定义的字段 forbidNonWhitelisted: true, // 存在未定义字段时直接抛出错误 })); await app.listen(3000); } bootstrap();
2. 定义子DTO TestDto
先写好子DTO的基础校验规则,示例如下:
// test.dto.ts import { IsString, IsNumber, Min } from 'class-validator'; export class TestDto { @IsString({ message: 'name必须为字符串类型' }) name: string; @IsNumber({}, { message: 'age必须为数字类型' }) @Min(18, { message: 'age不能小于18' }) age: number; }
3. 改造主DTO UserReqDto
针对data的动态键值对结构,用Record<string, TestDto>声明类型,配合三个核心装饰器实现校验:
@IsObject():确保data是合法对象@ValidateNested({ each: true }):告诉校验器递归校验对象内的每一个值@Type(() => TestDto):让class-transformer识别每个值的类型为TestDto,从而应用子DTO的校验规则
代码示例:
// user-req.dto.ts import { IsObject, ValidateNested, Type } from 'class-validator'; import { TestDto } from './test.dto'; export class UserReqDto { // 可添加其他字段的校验规则 // @IsString() // requestId: string; @IsObject({ message: 'data必须为对象类型' }) @ValidateNested({ each: true }) @Type(() => TestDto) data: Record<string, TestDto>; }
4. (可选)校验动态键的格式
如果需要对data的键做格式限制(比如要求是10位数字字符串),可以自定义验证器:
第一步:创建自定义校验约束
// valid-data-keys.constraint.ts import { ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments } from 'class-validator'; @ValidatorConstraint({ name: 'validDataKeys', async: false }) export class ValidDataKeysConstraint implements ValidatorConstraintInterface { validate(data: Record<string, TestDto>, args: ValidationArguments) { // 自定义键的校验规则,这里示例为必须是10位数字字符串 return Object.keys(data).every(key => /^\d{10}$/.test(key)); } defaultMessage(args: ValidationArguments) { return 'data字段的键必须是10位数字字符串'; } }
第二步:在主DTO中应用自定义校验
// user-req.dto.ts import { IsObject, ValidateNested, Type, Validate } from 'class-validator'; import { TestDto } from './test.dto'; import { ValidDataKeysConstraint } from './valid-data-keys.constraint'; export class UserReqDto { @IsObject({ message: 'data必须为对象类型' }) @Validate(ValidDataKeysConstraint) // 新增键格式校验 @ValidateNested({ each: true }) @Type(() => TestDto) data: Record<string, TestDto>; }
测试示例
符合规则的请求数据:
{ "data": { "1234567890": { "name": "张三", "age": 20 }, "0987654321": { "name": "李四", "age": 25 } } }
如果age传入字符串、键不符合格式,或者name缺失,都会返回对应的校验错误信息。
内容的提问来源于stack exchange,提问作者Butani Hardik
相关产品推荐
相关产品推荐

