1

It sounds like a quite simple question but I've been searching for a solution for a very long time now. I want to validate an array of UUIDs in an endpoint.

Like this: ["9322c384-fd8e-4a13-80cd-1cbd1ef95ba8", "986dcaf4-c1ea-4218-b6b4-e4fd95a3c28e"]

I have already successfully implemented it as a JSON object { "id": ["9322c384-fd8e-4a13-80cd-1cbd1ef95ba8", "986dcaf4-c1ea-4218-b6b4-e4fd95a3c28e"]} with the following code:

public getIds(
  @Body(ValidationPipe)
  uuids: uuidDto
) {
  console.log(uuids);
}
import { ApiProperty } from '@nestjs/swagger';
import { IsUUID } from 'class-validator';

export class uuidDto {
  @IsUUID('4', { each: true })
  @ApiProperty({
    type: [String],
    example: [
      '9322c384-fd8e-4a13-80cd-1cbd1ef95ba8',
      '986dcaf4-c1ea-4218-b6b4-e4fd95a3c28e',
    ],
  })
  id!: string;
}

But unfortunately I can't customize the function that calls that endpoint. So I need a solution to only validate a array of uuids.

HaaLeo
  • 10,065
  • 3
  • 44
  • 55
MOE
  • 769
  • 6
  • 19

2 Answers2

0

instead of type string , write string[]. like below:

import { ApiProperty } from '@nestjs/swagger';
import { IsUUID } from 'class-validator';

export class uuidDto {
  @IsUUID('4', { each: true })
  @ApiProperty({
    type: string[],
    example: [
      '9322c384-fd8e-4a13-80cd-1cbd1ef95ba8',
      '986dcaf4-c1ea-4218-b6b4-e4fd95a3c28e',
    ],
  })
  id!: string[];
}
HaaLeo
  • 10,065
  • 3
  • 44
  • 55
alireza javanmardi
  • 117
  • 1
  • 2
  • 7
  • But then the problem is still, that I have an object with property id which is an array, I only wanna have an array without the need of the id property – MOE Dec 04 '21 at 14:31
  • So I guess the DTO approach is wrong, since I do not have an object – MOE Dec 04 '21 at 14:47
  • yes , you dont need an object but if you think you do , simply create an interface for it and export it then use it in your dto – alireza javanmardi Dec 05 '21 at 07:03
0

You can build a custom validation pipe for it:

@Injectable()
export class CustomClassValidatorArrayPipe implements PipeTransform {

  constructor(private classValidatorFunction: (any)) {}

  transform(value: any[], metadata: ArgumentMetadata) {
    const errors = value.reduce((result, value, index) => {
      if (!this.classValidatorFunction(value))
        result.push(`${value} at index ${index} failed validation`)
      return result
    }, [])

    if (errors.length > 0) {
      throw new BadRequestException({
        status: HttpStatus.BAD_REQUEST,
        message: 'Validation failed',
        errors
      });
    }

    return value;
  }
}

In your controller:

@Post()
createExample(@Body(new CustomClassValidatorArrayPipe(isUUID)) body: string[]) {
  ...
}
  • Ensure to use the lowercase functions from class-validator. It has to be isUUID instead of IsUUID. (This is used for the manual validation with class-validator.)
  • CustomClassValidatorArrayPipe is build modular. You can validate any other type with it. For example a MongoId: @Body(new CustomClassValidatorArrayPipe(isMongoId)) body: ObjectId[]

Result

If you send this:

POST http://localhost:3000/example
Content-Type: application/json

[
  "986dcaf4-c1ea-4218-b6b4-e4fd95a3c28e",
  "123",
  "test"
]

Server will reply:

{
  "status": 400,
  "message": "Validation failed",
  "errors": [
    "123 at index 1 failed validation",
    "test at index 2 failed validation"
  ]
}
Lars Flieger
  • 2,421
  • 1
  • 12
  • 34