javascriptnode.jsnestjsdtoclass-validator

Nestjs Class Validator for Confirm Password


I am working on a change password endpoint using nestjs , I want to be able to validate if the two password match

The class-validator library doesn't seem to have that on how to validate two properties within the DTO

How do I achieve this

This is my current code

export class CreatePasswordDTO {
  @MaxLength(6)
  @IsString()
  @Matches(/^\d{6}$/, { message: "Password must be a 6-digit number" })
  password: string;

  @MaxLength(6)
  @IsString()
  @Matches(/^\d{6}$/, { message: "Confirm Password must be a 6-digit number" })
  // I check that the password and confirmPassword are the same
  confirmPassword: string;
}

Solution

  • If there is no default solution, what you usually do is come up with a custom implementation. I would create custom validator to check related fields at the same time:

    import { registerDecorator, ValidationArguments, ValidationOptions } from 'class-validator';
    
    export function Match(property: string, validationOptions?: ValidationOptions) {
      return (object: any, propertyName: string) => {
        registerDecorator({
          name: 'Match',
          target: object.constructor,
          propertyName: propertyName,
          options: validationOptions,
          constraints: [property],
          validator: {
            validate(value: any, args: ValidationArguments) {
              const [relatedPropertyName] = args.constraints;
              const relatedValue = (args.object as any)[relatedPropertyName];
              return value === relatedValue;
            },
            defaultMessage(args: ValidationArguments) {
              const [relatedPropertyName] = args.constraints;
              return `${args.property} must match ${relatedPropertyName}`;
            },
          },
        });
      };
    }
    

    And use your custom validator on confirmPassword field:

    import { IsString, MaxLength, Matches } from 'class-validator';
    import { Match } from './match.decorator'; // Adjust the import path as needed
    
    export class CreatePasswordDTO {
      @MaxLength(6)
      @IsString()
      @Matches(/^\d{6}$/, { message: 'Password must be a 6-digit number' })
      password: string;
    
      @MaxLength(6)
      @IsString()
      @Matches(/^\d{6}$/, { message: 'Confirm Password must be a 6-digit number' })
      @Match('password', { message: 'Passwords do not match' })
      confirmPassword: string;
    }