How to validate array of uuid in nest js using class validator?

Viewed 9426

How to validate an array of uuid ? I'm using the pre-built ParseArrayPipe to validate the payload array structure.

@Post(':id/players')
  addPlayers(
    @Body(new ParseArrayPipe({ items: GamePlayerDto, separator: ',' }))
    gamePlayers: GamePlayerDto,
  ) {
    console.log(gamePlayers);
  }
export class GamePlayerDto {
  @IsUUID()
  playerId!: string;
}

I don't want class validator to check if playersId property is here but only raw value

e.g. this is what my server should received

["73aef2dd-c227-4774-b547-b3117b543863", "73aef2dd-c227-4774-b547-b3117b543863"]
4 Answers

You have to set the option - "each: true".

export class GamePlayerDto {
  @IsUUID(UUIDVersion,{each:true})
  playerId!: string;
}

Accepted UUID Version values - '3' | '4' | '5' | 'all' | 3 | 4 | 5;

Quoting official doc - "Specifies if validated value is an array and each of its items must be validated."

Essentially, The value of playerId is considered as an array and is of type UUID (of specified version) and each value has to be validated.

UPDATE

Also update your request handler to:

@Post(':id/players')
  addPlayers(
    @Body(ValidationPipe))
    gamePlayers: GamePlayerDto,
  ) {
    console.log(gamePlayers);
  }

ValidationPipe is a default pipe in NestJS that works hand in hand with class validator. It will validate the incoming request body/params etc.. and rejects if it does not meet the set conditions in the DTO.

You can write a custom class-validator. Which verifies that the array received by the server only contains UUIDs

import {
  registerDecorator,
  ValidationArguments,
  ValidationOptions,
} from 'class-validator';

import validator from 'validator';

export function IsUuidArray(validationOptions?: ValidationOptions) {
  // eslint-disable-next-line @typescript-eslint/ban-types
  return function (object: Object, propertyName: string) {
    let fakeElements = [];
    registerDecorator({
      name: 'IsUuidArray',
      target: object.constructor,
      propertyName: propertyName,
      options: validationOptions,
      validator: {
        defaultMessage(): string {
          return `[${fakeElements}] is not uuid`;
        },
        validate(value: string[], args: ValidationArguments) {
          fakeElements = [];
          let isOnlyUuid = true;
          value.forEach((element) => {
            const result = validator.isUUID(element);
            if (!result) {
              isOnlyUuid = result;
              fakeElements.push(element);
            }
          });
          return isOnlyUuid;
        },
      },
    });
  };
}

And you can use it like this

export class CreateInsuranceCommand {
  @ApiProperty()
  @IsUuidArray()
  @IsOptional()
  @IsArray()
  providers: string[];
}

I used validator to check if string is uuid

ParseArrayPipe does not validate the values and it only transforms the values into an array. Use ValidationPipe to check whether it is uuid.

you can use it

@IsUUID(undefined, {each:true})
providers: string[]
Related