I use nestjs with class-validator, and I have the following case:
class A {
@IsDefined()
field: number;
}
class B {
@IsDefined()
field: string;
}
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!
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.com/typestack/class-transformer#providing-more-than-one-type-option