typestack / class-validator

Decorator-based property validation for classes.
MIT License
10.99k stars 794 forks source link

question: get constrains in decorators and not the message #2433

Open ako-v opened 7 months ago

ako-v commented 7 months ago

I am trying to customize messages in nestjs response, I am using decorators in DTOs, and want to get min constraint I pass to @Min (this is just an example). My DTO is something like this:

class GetUsersDto {
  @ApiProperty({ required: false })
  @IsOptional()
  @Min(1, { message: 'validation.min' })
  @IsInt()
  @Transform((param) => parseInt(param.value, 10))
  page?: number;
}

in nestjs I am getting the validation error that comes from class-validator, but I get only "validation.min" as the constraint:

app.useGlobalPipes(
    new ValidationPipe({
      stopAtFirstError: true,
      whitelist: true,
      forbidNonWhitelisted: true,
      transform: true,
      exceptionFactory: (errors) => {
        console.log(errors);
        const result = errors
          .map((error) => {
            const key = Object.values(error.constraints)[0];
            const message = getMessage(key, error); // I get the customized message from the message I provided to `@Min`
            return message ? message : getMessage('validation.400'); 
          })
          .join('');
        return new BadRequestException(result);
      },
    }),
  );

in the console.log(errors), I get something like this:

[
  ValidationError {
    target: GetUsersDto { page: -1 },
    value: -1,
    property: 'page',
    children: [],
    constraints: { min: 'validation.min' }
  }
]

As you see I get validation.min (the message) I passed as the constraint, the question is how can I get the value (here is 1) I passed to @Min?

emir-gradient commented 7 months ago

Hello.

In your custom validator, you can utilize snippet similar to this one:

import { getMetadataStorage, MetadataStorage } from 'class-validator';

// ... Some other code
const dataType = CreateAdminDTO; // you put your data type here (one you are validating). I think you can use ValidationError.target for this.
const metadataStorage: MetadataStorage = getMetadataStorage();
const metas = metadataStorage.getTargetValidationMetadatas(dataType, null, false, false);

console.log(metas);

// Result is like:
//   [
// ValidationMetadata {
//   groups: [],
//   each: false,
//   context: undefined,
//   type: 'customValidation',
//   name: 'minLength',
//   target: [class CreateAdminDTO],
//   propertyName: 'username',
//   constraints: [ 4 ], => validator was @minLength(4)
//   constraintCls: [class CustomConstraint],
//   validationTypeOptions: undefined
// },
// ... other metadatas
// ]