Class-validator: [Feature] @IsOptionaIf()

Created on 9 Jul 2020  路  4Comments  路  Source: typestack/class-validator

It would be nice if we could have conditional decorator for required/non-required properties.

Example use case:

I want to insert or update a record.
When inserting a new row the title is required, but when updating the releaseYear on existing row the title column is not required.

I could get around this by creating two different classes InsertRecordParameters and UpdateRecordParamaeters but it would be nice to have eveything in one class when insert and update do not differ in terms of the parameters used.

class SaveRecordParameters {
@IsOptional() 
@IsPositive()
 id?: number;

@IsOptionaIf( self => !!self.id )
@MaxLength(5)
@MinLength(50)
 title?: string;

@IsOptional()
@IsNumber()
 releaseYear?: number;
}
has PR feature

All 4 comments

@ibox4real you can use Validation groups. They are meant exactly for what you are looking for.

Example class:
A class that I used in a project here

export enum RecordParametersValidationGroup {
  CREATION = 'creation',
  UPDATE = 'update',
};

export defaul class SaveRecordParameters {
@IsOptional() 
@IsPositive()
 id?: number;

@Length(5, 50, { groups: [RecordParametersValidationGroup.UPDATE] }])
 title?: string;

@IsOptional({ groups: [RecordParametersValidationGroup.UPDATE] })
@IsNumber()
 releaseYear?: number;
}

Example usage:
The usage here

import {validate} from "class-validator";
import { RecordParametersValidationGroup } from '@entity/SaveRecordParameters ';

// ...

validate(an_example_instance_of_record_parameters, {
    groups: [RecordParametersValidationGroup.UPDATE]
});

There's a pull request for a conditional @IsOptional decorator here: https://github.com/typestack/class-validator/pull/196
But it hasn't been merged in over two years now.

Looks way simpler when you have an IsOptionalIf

You can achieve this by creating your own decorator that wraps @ValidateIf.

/**
 * Mark the property as optional if the function returns truthy
 * 
 * @param optionalIfPropertyIsSet
 */
function IsOptionalIf(allowOptional: (obj: any, value: any) => boolean, options?: ValidationOptions) {
  // If required, do validate. Otherwise if null|undefined, don't validate
  return ValidateIf((obj, value) => !allowOptional(obj, value) || value != null), options)
}

class SaveRecordParameters {
  @IsOptional() 
  @IsPositive()
  id?: number;

  @IsOptionalIf(self => !!self.id)
  @MaxLength(5)
  @MinLength(50)
  title?: string;

  @IsOptional()
  @IsNumber()
  releaseYear?: number;
}
Was this page helpful?
0 / 5 - 0 ratings