35

I want to apply validation on request payload like, there is field name with string type. But name is not compulsory field but if it exist it must execute @IsNotEmpty()

I tried something like this @IsNotEmpty() name?: string // it not considering ? optional constraint

Kim Kern
  • 54,283
  • 17
  • 197
  • 195
Revansiddh
  • 2,932
  • 3
  • 19
  • 33

5 Answers5

67

You can use the @IsOptional() validator:

Checks if given value is empty (=== null, === undefined) and if so, ignores all the validators on the property.

Kim Kern
  • 54,283
  • 17
  • 197
  • 195
  • 1
    Then why null values were not filtered by class-validator while I configure class-validator to do whitelist for me. I mean I expect to have no null/undefined value for any defined property, however I do have. And it was an error prone behavior in my case. – Kasir Barati May 16 '22 at 07:47
30

class-validator has an @IsOptional() validator that you can add on along with any other validators you defined like so:

@IsOptional() @IsNotEmpty() name: string;

The decorators are commutative so validation doesn't depend on the order of the validators. If the need to validate depends on something other than presence, you can use @ValidateIf() which takes a function argument.

pol
  • 457
  • 4
  • 5
6

You can use @ValidateIf conditional validation, this will run other validation if the function return true

examle : in this case if o.otherProperty === 'value' euqal true then the @IsNotEmpty will run otherwise it will not run

export class Post {
  otherProperty: string;

  @ValidateIf(o => o.otherProperty === 'value')
  @IsNotEmpty()
  example: string;
}
ron
  • 726
  • 11
  • 16
2

Kim's answer is great. If you want to apply this behavior to all of your optional fields, you can also use skipMissingProperties: true with your validation pipe(s).

Alec Branaa
  • 120
  • 2
  • 8
  • 2
    Could you give an example on where to put this property in the pipes? Thanks – Raphael Pinel Dec 03 '21 at 08:32
  • You can apply a validation pipe globally and pass this config as a option to the pipe's constructor. See the [docs](https://docs.nestjs.com/techniques/validation#using-the-built-in-validationpipe). – Tim Mar 16 '22 at 15:05
0

I dislike the functionality of IsOptional() as it will allow null values on fields where you havent specified null in the DTO. This means you can inadvertently allow non nullable fields to be nulled.

I created a custom decorator based off another stackoverflow answer that allows a field to be undefined, but wont let it pass validation as null.

import { IsOptional, ValidateIf, ValidationOptions } from 'class-validator'

export function IsOptionalNonNullable(data?: {
  nullable: boolean
  validationOptions?: ValidationOptions
}) {
  const { nullable = false, validationOptions = undefined } = data || {}

  if (nullable) {
    // IsOptional allows null
    return IsOptional(validationOptions)
  }

  return ValidateIf((ob: any, v: any) => {
    return v !== undefined
  }, validationOptions)
}

// Example usage 
export class SomeUpdateDTO {
  @IsInt()
  // Param can be undefined, but not null 
  @IsOptionalNonNullable()
  nbOfViews?: number
}

// Example of why IsOptional is a problem
export class SomeOtherUpdateDTO {
  @IsInt()
  @IsOptional()
  // Null is not specified, but IsOptional will allow it! 
  // Could end up nulling a required field in the db
  nbOfViews?: number
}
omeanwell
  • 1,847
  • 1
  • 10
  • 16