monkeyUser
monkeyUser

Reputation: 4671

Class validator with numbers and enum

I want to create a DTO in nestjs using class-validator.

The value can accept a value between 1-24,trial or lifetime

I created an enum like this

export enum PeriodEnum {
    "trial" = "trial",
    "lifetime" = "lifetime"
}

And I tried to used this validation

@IsNotEmpty()            
@ApiProperty(CustomersConfigSwagger.API_PROP_REF_PERIOD)
@Min(0)
@Max(24)
@IsEnum(Object.keys(PeriodEnum))
period: string;

I get an error if I pass 1:

   "period must be a valid enum value",
    "period must not be greater than 10",
    "period must not be less than 0"

I tried to add

"1" = "1"

But the "An enum member cannot have a numeric"

I tried even with RegExp

@IsNotEmpty()            
@ApiProperty(CustomersConfigSwagger.API_PROP_REF_PERIOD)
@Matches(`/^(${Object.keys(PeriodEnum)}|[1-9]|1[0-9]|2[0-4])$/`) 
period: string;

Upvotes: 1

Views: 1100

Answers (3)

Luke
Luke

Reputation: 175

@Min() decorator can't check cause by the data type of period is string.
Please cast period to number to valid Min and Max.
In your case, I use @Type() decorator to cast:

@IsNotEmpty()            
@ApiProperty(CustomersConfigSwagger.API_PROP_REF_PERIOD)
@Type(() => Number)
@Min(0)
@Max(24)
@IsEnum(Object.keys(PeriodEnum))
period: string;

Upvotes: 0

monkeyUser
monkeyUser

Reputation: 4671

I edited my DTO like this:

@IsNotEmpty()            
@ApiProperty(CustomersConfigSwagger.API_PROP_REF_PERIOD)
@Matches(`^(${Object.values(PeriodEnum).join("|")}|[1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4])$`)

period: string;

It works as I want now

Upvotes: 0

Ahmed Sbai
Ahmed Sbai

Reputation: 16199

since you are accepting strings, @Min and @Max no longer make sens. so here you need to deal with your numbers as string.

what I suggest is to create your own validation decorator :

export function IsLifetimeOrTrialOrBetween1and24(
  validationOptions?: ValidationOptions
) {
  return function (object: Object, propertyName: string) {
    registerDecorator({
      name: "IsLifetimeOrTrialOrBetween1and24",
      target: object.constructor,
      propertyName: propertyName,
      options: validationOptions,
      validator: {
        validate(value: any) {
          // you manage your logic here then return either TRUE or FALSE
        },
      },
    });
  };
}

then use it like this :

@IsLifetimeOrTrialOrBetween1and24({
   message: 'should be lifetime trial or a number between 1 and 24',
})
readonly period: string;

learn more here

but if you don't want to custom validation decorator this is an ugly solution but it works fine :

@IsIn(['trial', 'lifetime', '1', '2', '3', '4', '5', '6', '7',...,'23','24'])
readonly period: string;

Upvotes: 0

Related Questions