typestack / class-validator

Decorator-based property validation for classes.
MIT License
10.87k stars 785 forks source link

Easy way to compose ORed validators #2466

Open JensRantil opened 4 months ago

JensRantil commented 4 months ago

Background

I am validating that a string is either a MongoId or a UUID. I had to implement my own validator for this:

import {
  ValidatorConstraint,
  ValidatorConstraintInterface,
  ValidationOptions,
  registerDecorator,
  isUUID,
  isMongoId,
} from 'class-validator';

@ValidatorConstraint()
export class IsUUIDOrMongoIdConstraint implements ValidatorConstraintInterface {
  validate(text: string): boolean {
    return isUUID(text) || isMongoId(text);
  }

  defaultMessage(): string {
    return 'Text ($value) must be a UUID or a MongoId';
  }
}

export function IsUUIDOrMongoId(validationOptions?: ValidationOptions) {
  return function (object: Object, propertyName: string) {
    registerDecorator({
      target: object.constructor,
      propertyName: propertyName,
      options: validationOptions,
      constraints: [],
      validator: IsUUIDOrMongoIdConstraint,
    });
  };
}

A workaround is also a somewhat complex RegExp, but that doesn't work in all cases where you want to compose different validators.

Proposed solution

Dream scenario would be to to be able to compose different validators, similar to how applyDecorators(...) works. I am thinking of something like this:

import ...

export class MyOwnDto {
  @ValidateOr(
    IsUUID(),
    IsMongoId(),
  )
  readonly myProperty: string;
}

Or something like this:

import { applyValidators } from '@nestjs/common';

export function IsUUIDOrMongoId() {
  return applyValidators(
    IsUUID(),
    IsMongoId(),
  );
}
JensRantil commented 4 months ago

This came out of https://github.com/nestjs/class-validator/issues/390.