带有 stopAtFirstError: true 的 NestJS ValidationPipe 不尊重类验证器中装饰器的顺序

问题描述 投票:0回答:1

我使用带有类验证器的 NestJS 来验证传入的请求。在我的 SignUpDto 类中,我应用了 IsNotEmpty、IsString 和 IsEmail 等验证装饰器来验证电子邮件和密码字段。我希望验证错误以与应用装饰器相同的顺序抛出,但仅抛出一个错误(如果)。

为了实现这一目标,我使用 exceptionFactory 抛出 app.useGlobalPipes 配置中唯一的一个错误。但是,错误不会按预期顺序抛出(因为我只返回索引 0 处的错误)

我有什么方法可以解决这个问题,这样我就可以按相同的顺序显示错误,但一次只显示一个错误?

// SignUpDto.ts
import { IsEmail, IsNotEmpty, IsString, MinLength } from 'class-validator';

export class SignUpDto {
  @IsNotEmpty({ message: 'Email should not be empty' })
  @IsString({ message: 'Invalid email format' })
  @IsEmail({}, { message: 'Invalid email format' })
  email: string;

  @IsNotEmpty({ message: 'Password should not be empty' })
  @IsString({ message: 'Invalid password format' })
  @MinLength(8, { message: 'Password must be at least 8 characters long' })
  password: string;
}

// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import {
  BadRequestException,
  HttpException,
  HttpStatus,
  ValidationPipe,
} from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.enableCors({
    origin: true,
    methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
    credentials: true,
  });
  app.useGlobalPipes(
    new ValidationPipe({
      stopAtFirstError: true,
      whitelist: true,
      exceptionFactory: (errors) => {
        const messages = errors[0].constraints; 
        const message = Object.values(messages)[0];
        const response = { message, statusCode: HttpStatus.BAD_REQUEST };
        throw new HttpException(response, HttpStatus.BAD_REQUEST);
      },
    }),
  );
  await app.listen(5001);
}
bootstrap();

nestjs class-validator custom-errors
1个回答
0
投票

您正在使用 TypeScript 装饰器(从

class-validator
导入的装饰器)来添加 DTO 的验证。

TypeScript 装饰器是自下而上执行的。您可以参考https://www.typescriptlang.org/docs/handbook/decorators.html#decorator-composition了解更多详情。

这意味着在您给定的 DTO 中:

export class SignUpDto {
  @IsNotEmpty({ message: 'Email should not be empty' })
  @IsString({ message: 'Invalid email format' })
  @IsEmail({}, { message: 'Invalid email format' })
  email: string;
}

你的装饰器的执行顺序将是:

  1. IsEmail
  2. IsString
  3. IsNotEmpty

我假设你想要另一种方式。这意味着,您需要将装饰器顺序调整为:

export class SignUpDto {
  @IsEmail({}, { message: 'Invalid email format' })
  @IsString({ message: 'Invalid email format' })
  @IsNotEmpty({ message: 'Email should not be empty' })
  email: string;
}

这应该可以为您解决订单问题。


对于仅返回 1 个错误的第二个查询,您的方法看起来不错。同时使用

stopAtFirstError
executionFactory
将是最简单的方法。

© www.soinside.com 2019 - 2024. All rights reserved.