You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 20:30:33