Validate nested objects using class validator and nestjs
for me, I would able to validate nested object with 'class-transformer'
import { Type } from 'class-transformer';
full example:
import {
MinLength,
MaxLength,
IsNotEmpty,
ValidateNested,
IsDefined,
IsNotEmptyObject,
IsObject,
IsString,
} from 'class-validator';
import { Type } from 'class-transformer';
class MultiLanguageDTO {
@IsString()
@IsNotEmpty()
@MinLength(4)
@MaxLength(40)
en: string;
@IsString()
@IsNotEmpty()
@MinLength(4)
@MaxLength(40)
ar: string;
}
export class VideoDTO {
@IsDefined()
@IsNotEmptyObject()
@IsObject()
@ValidateNested()
@Type(() => MultiLanguageDTO)
name!: MultiLanguageDTO;
}
You are expecting positions: [1]
to throw a 400 but instead it is accepted.
According to this Github issue, this seems to be a bug in class-validator. If you pass in a primitive type (boolean
, string
, number
,...) or an array
instead of an object, it will accept the input as valid although it shouldn't.
I don't see any standard workaround besides creating a custom validation decorator:
import { registerDecorator, ValidationOptions, ValidationArguments } from 'class-validator';
export function IsNonPrimitiveArray(validationOptions?: ValidationOptions) {
return (object: any, propertyName: string) => {
registerDecorator({
name: 'IsNonPrimitiveArray',
target: object.constructor,
propertyName,
constraints: [],
options: validationOptions,
validator: {
validate(value: any, args: ValidationArguments) {
return Array.isArray(value) && value.reduce((a, b) => a && typeof b === 'object' && !Array.isArray(b), true);
},
},
});
};
}
and then use it in your dto class:
@ValidateNested({ each: true })
@IsNonPrimitiveArray()
@Type(() => PositionDto)
positions: PositionDto[];