简体   繁体   中英

NestJS DTO class set class-validator and class-transformer execution order

Is there a way to set the execution order of decorators when describing a DTO class in NestJS using class-validator and class-transformer packages?

Following code fails when the value of foo is set to null with the error:

Expected a string but received a null

@IsOptional()
@IsString()
@IsByteLength(1, 2048)
@Transform(({ value }) => validator.trim(value))
@Transform(({ value }) => validator.stripLow(value))
foo: string;

Even tho I have a isString decorator that should check that indeed a string was passed and must already fail to not pass the execution to the @Transform decorators, but it didn't failed.

Class-Validator works based on classes. Request payloads that come into the server are just plain JSON objects to start off with. To change this behaviour, Nest has to first call plainToClass from class-validator if you're using its ValidationPipe . Because of this, the @Transform() decorators take precedence over the other class-validator decorators, and are acted upon first. You could get around this by using multiple pipes, or possibly providing default values for the @Transform() decorator, but what is happening is the intended effect.

Control @Transfrom and Validator Decorator execution order by 2 ValidationPipe

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({
      whitelist: true,
      transform: false,
    }),

    new ValidationPipe({
      transform: true,
      transformOptions: { groups: ['transform'] },
    }),
  );

  await app.listen(4000);
}
bootstrap();

create-user.dto.ts

export class CreateUserDto {
  @ApiProperty({
    description: 'username',
    minLength: 4,
    maxLength: 64,
  })
  @Length(4, 64)
  name: string;

  @ApiProperty({
    description: 'password',
    minLength: 4,
    maxLength: 64,
  })
  @Length(6, 64)
  @Transform(({ value }: { value: string }) => hashSync(value), {
    groups: ['transform'],
  })
  password: string;
}

This will run @Length first, and then @Transform

Note: The transform property in the first ValidationPipe must be false.

Translation with Deepl

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM