javascript - How to validate nested array of multiple types using class-validator? - Stack Overflow

admin2025-04-20  0

I use nestjs with class-validator, and I have the following case:

  • Two classes with same field name that has different types:
class A {
  @IsDefined()
  field: number;
}

class B {
  @IsDefined()
  field: string;
}
  • Third class that has array of elements from types A or B, my problem is how to validate each array member against its own class:
class C {
  @ValidateNested({ each: true })
  @Type(I_DON'T_KNOW_WHAT_TO_DO_HERE)
  array: (A | B)[];
}

How can I validate the array?

Thanks ahead!

I use nestjs with class-validator, and I have the following case:

  • Two classes with same field name that has different types:
class A {
  @IsDefined()
  field: number;
}

class B {
  @IsDefined()
  field: string;
}
  • Third class that has array of elements from types A or B, my problem is how to validate each array member against its own class:
class C {
  @ValidateNested({ each: true })
  @Type(I_DON'T_KNOW_WHAT_TO_DO_HERE)
  array: (A | B)[];
}

How can I validate the array?

Thanks ahead!

Share Improve this question asked Mar 19, 2023 at 13:19 user2993539user2993539 5151 gold badge8 silver badges22 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 6

You should have a descriminative field, to allow the class-transformer to identify the type to cast and use in the validation. The same can be done with nested objects.

In the example below, if the property "version" is equal to "v1", then the field should be a number, in the other hand, if the property version is equal to "v2" the property field should be a string.
In the discriminator property you should set a field to be used to identify the different polymorphic forms of the nested objects. The subTypes.[].value is the class to be used in validation and subTypes.[].name is the value that the discriminator field should have to assume the class added in the subTypes.[].name field.

import { Type } from 'class-transformer';
import { IsDefined, IsEnum, IsNumber, IsString, ValidateNested } from 'class-validator';

enum VersionEnum {
  VERSION_1 = 'v1',
  VERSION_2 = 'v2',
}

class Discriminator {
  @IsEnum(VersionEnum)
  version: VersionEnum;
}

class A extends Discriminator {
  @IsDefined()
  @IsNumber()
  field: number;
}

class B extends Discriminator {
  @IsDefined()
  @IsString()
  field: string;
}

export class C {
  @ValidateNested({ each: true })
  @Type(() => Discriminator, {
    discriminator: {
      property: 'version',
      subTypes: [
        { value: A, name: VersionEnum.VERSION_1 },
        { value: B, name: VersionEnum.VERSION_2 },
      ],
    },
    keepDiscriminatorProperty: true,
  })
  array: (A | B)[];
}

Now your controller should look like this:

@Controller()
export class AppController {
  @Post()
  public example(
    @Body(new ValidationPipe({ transform: true }))
    body: C,
  ) {
    return body;
  }
}

And you can do your requests:

curl --location 'localhost:3000/' \
--header 'Content-Type: application/json' \
--data '{
  "array": [
    {
      "version": "v1",
      "field": 1
    },
    {
      "version": "v2",
      "field": "2"
    }
  ]
}'

If you change the second element of the nested array to be a number with the version property as "v2", then you will see an error:

{
  "version": "v2",
- "field": "2"
+ "field": 2
}
{
  "statusCode": 400,
  "message": [
    "array.1.field must be a string"
  ],
  "error": "Bad Request"
}

References: https://github./typestack/class-transformer#providing-more-than-one-type-option

转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1745081467a283884.html

最新回复(0)