NestJS class validator can i validate the entire class?

138 Views Asked by At

I am running into an issue where I am using the class validator library and as per my use case, instead of just the properties of a class I want to validate the entire class. For example, my class is a QueryDto which has 4 optional fields.

However, I am expecting the user of the endpoint to provide a combination of either start_date/end_date or start_disposed_date/end_disposed_date. I want to validate if they by any chance provide a start_date/end_disposed_date so I can error that out.

Is it possible to achieve this with the class-validator library and creating a decorator?

export class AggregateQueryDto {
  @Type(() => Date)
  @IsDate()
  @IsOptional()
  @IsEndDateBefore('end_date', { message: 'end date must be after start date' })
  start_date?: Date;

  @Type(() => Date)
  @IsDate()
  @IsOptional()
  end_date?: Date;

  @Type(() => Date)
  @IsDate()
  @IsOptional()
  @IsEndDateBefore('end_disposed_date', {
    message: 'end disposed date must be after start disposed date',
  })
  start_disposed_date?: Date;

  @Type(() => Date)
  @IsDate()
  @IsOptional()
  end_disposed_date?: Date;
}
1

There are 1 best solutions below

0
On

Since it is always a combination of start_date, end_date I would recommend shortening this dto to

export class AggregateQueryDto {
  @Type(() => Date)
  @IsDate()
  @IsOptional()
  @IsEndDateBefore('end_date', { message: 'end date must be after start date' })
  start_date?: Date;

  @Type(() => Date)
  @IsDate()
  @IsOptional()
  end_date?: Date;

  /* 
   * if the combination of properties determines the logic in your code
   * I would recommend maybe some kind of operationType property here  
  */
}

But okay, that is not what the question is about :)

Validation groups

Here I would recommend use validation groups. Validation groups are described in the docs as something you can use in situations when you want to have different validation schemas of the same object.

The documentation also provides an example that makes the approach easier to understand:

import { validate, Min, Length } from 'class-validator';

export class User {
  @Min(12, {
    groups: ['registration'],
  })
  age: number;

  @Length(2, 20, {
    groups: ['registration', 'admin'],
  })
  name: string;
}

let user = new User();
user.age = 10;
user.name = 'Alex';

validate(user, {
  groups: ['registration'],
}); // this will not pass validation

validate(user, {
  groups: ['admin'],
}); // this will pass validation

validate(user, {
  groups: ['registration', 'admin'],
}); // this will not pass validation

validate(user, {
  groups: undefined, // the default
}); // this will not pass validation since all properties get validated regardless of their groups

validate(user, {
  groups: [],
}); // this will not pass validation, (equivalent to 'groups: undefined', see above)

However, you can have a problem with this approach if you use nestjs. In that case please check this thread