I’m trying to validate nested objects using class-validator and NestJS. I’ve already tried following this thread by using the @Type
decorator from class-transform and didn’t have any luck. This what I have:
DTO:
class PositionDto { @IsNumber() cost: number; @IsNumber() quantity: number; } export class FreeAgentsCreateEventDto { @IsNumber() eventId: number; @IsEnum(FinderGamesSkillLevel) skillLevel: FinderGamesSkillLevel; @ValidateNested({ each: true }) @Type(() => PositionDto) positions: PositionDto[]; }
I’m also using built-in nestjs validation pipe, this is my bootstrap:
async function bootstrap() { const app = await NestFactory.create(ServerModule); app.useGlobalPipes(new ValidationPipe()); await app.listen(config.PORT); } bootstrap();
It’s working fine for other properties, the array of objects is the only one not working.
Advertisement
Answer
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[];