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

在NestJS Service中使用class-validator时校验结果始终为空数组

问题原因

核心问题是:传入Service的user是普通JavaScript对象,而非CreateUserDto的类实例。class-validator的校验装饰器(如@IsEmail())依赖类的元数据工作,普通对象没有这些元数据,导致validate方法无法识别校验规则,返回空数组。

而Controller层校验正常,是因为Nest的ValidationPipe会自动将请求体转换为对应DTO类的实例,并基于元数据执行校验。

解决方案

方案1:让Controller正确传递DTO实例到Service

修改Controller代码,给@Body()添加ValidationPipe并指定参数类型为CreateUserDto,Nest会自动将请求体转换为DTO实例:

@Post()
async create(@Body(new ValidationPipe()) user: CreateUserDto) {
  return this.userService.create(user);
}

此时Service接收的user已是CreateUserDto实例,直接调用校验即可:

import { validate } from 'class-validator';

async create(user: CreateUserDto): Promise<UserEntity> {
  const errors = await validate(user);
  if (errors.length > 0) {
    throw new Error('Invalid criteria!');
  }
  // 密码加密、创建逻辑...
}

若项目全局启用了ValidationPipe,可省略new ValidationPipe(),直接写@Body() user: CreateUserDto。

方案2:在Service中手动转换普通对象为DTO实例

如果不想修改Controller,可在Service内部用class-transformer的plainToInstance方法转换对象后再校验:
先安装依赖:

npm install class-transformer

修改Service代码:

import { validate } from 'class-validator';
import { plainToInstance } from 'class-transformer';

export class UserService extends BaseService<UserEntity> {
  constructor(
    @Inject('USER_RESPOSITORY')
    private userRespository: typeof UserEntity
  ) {
    super(userRespository);
  }

  async create(user: CreateUserDto): Promise<UserEntity> {
    // 将普通对象转换为DTO实例
    const userDto = plainToInstance(CreateUserDto, user);
    const errors = await validate(userDto);

    if (errors.length > 0) {
      throw new Error('Invalid criteria!');
    }

    const hashedPassword = await bcrypt.hash(userDto.password, 10);
    userDto.password = hashedPassword;
    
    const rs = await super.create(userDto);

    return rs;
  }
}

无需手动实例化Validator,直接使用class-validator导出的validate函数即可,这是当前推荐用法。

额外说明
  • Controller层校验正常的本质:ValidationPipe内部自动执行plainToInstance转换,再调用validate校验,因此能识别DTO的校验规则。
  • 避免手动实例化Validator:class-validator从v0.13.x开始推荐使用函数式的validate、validateOrReject等方法,而非new Validator()实例。

内容的提问来源于stack exchange,提问作者Han Luu Nhat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 01:18:27