class-validator: Deep nested validation broken
Description
When trying to validate nested objects using @ValidateNested(), whitelist: true and forbidNonWhitelisted: true, error "property XY should not exist" gets thrown for no apparent reason.
Reproduction
Here a vastly simplified version of my use case:
class ProductPricing {
@Type(() => ProductPricingOptionsDTO)
options: ProductPricingOptionsDTO;
}
class ProductPricingOptionsDTO{
@ValidateNested()
@Type(() => OnlineUserPricingOptionsDTO)
onlineUserPrices: OnlineUserPricingOptionsDTO;
}
class OnlineUserPricingOptionsDTO{
@IsNumber()
@Min(2)
price: number;
}
and validating the following payload:
{
"options": {
"onlineUserPrices": {
"price": 2
}
}
}
with whitelist: true, forbidNonWhitelisted: true throws an error containing the following message:
"constraints": {
"whitelistValidation": "property price should not exist" }
}
Environment
- nodejs:
- browser:
- typeorm:
class-validator version: ^0.12.1
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 7
- Comments: 26 (1 by maintainers)
Cheers! We have found out that adding
@Type(() => NestedType)was the thing. It works without adding that parameter which you suggested. Adding comment for “future generations”.Hi! I had the same issue but I managed to resolve it by using:
Please let me know if it helped also in your cases.
Setting only
forbidNonWhitelisted: trueis necessary to reproduce this problem, that will throw theproperty X should not existmessageFor setting only
forbidUnknownValues: true, the class-validator will throw withan unknown value was passed to the validateIf both options are enabled, it will give an error in the first check rule
For example: If my PipeValidation is
It will throw the
forbidUnknownValuesmessage because it’s the first rule checked at ValidationPipe, the same occurs ifforbidNonWhitelistedis aboveforbidUnknownbut it will throwproperty X should not existmessage insteadI also encountered this issue when using the
plainToClass()class transformer. I tried to reproduce this issue in this CodeSandbox. While doing so I noticed thatplainToClass()doesn’t convert nested “class” objects to the desired class, what actually shouldn’t be an issue if you’re not strictly validating the type of the nested object (like in my example).As you might have seen my example includes some tests what, I think, cover all cases regarding this issue and if you run them you will see that they all pass. Which is strange because when running the server, defined in
index.ts, you can see that it does give an error. The server runs a validation for data with and without class transformer and while doing so thewhitelistandforbidNonWhitelistedflag are set totrue, resulting in errors for the validation with class transformer. This is the only way I could manage to make the validator return validation errors.To summarize I think that this issue can be solved by making the
whitelistfunction declared here recursive, for objects and arrays of objects.Ok. Update on my case.
@Typedecorator didn’t work as should when usedyarn linkalong withclass-transformerin peerDependency. So optionenableImplicitConversion: truehelped me because of not working@Typebut when not linked everything works as it should 👍 .I had
property xxx should not existwith whitelist rule set to true error but my problem was that I wasn’t specifying any decorators for nested properties, whereas in the docs they write:(validate)… will strip all properties that don’t have any decorators. If no other decorator is suitable for your property, you can use @Allow decorator
Now everything works fine with @ValidateNested
@MickL are you sure it is not still broken? Have you tried to validate objects that are nested more than 2 levels deep? That is the issue i was running into. It works on second level objects but fails for 3rd level or deeper. Even when adding @Type(() => MyClass)
I don’t think this issue should be closed until it is confirmed the validation works on 3rd level objects.
I am pretty sure this issue can be closed because nested validation is NOT broken:
When using
@ValidateNested()from class-validator then the property needs to be an instance of the desired class not a plain object. If you use class-transformer then it will not automatically transform your nested objects into classes. Instead you need to add the decorator@Type(() => MyClass)so class-transformer will transform your nested objects into instances of the class and THEN@ValidateNested()from class-validator will work as expected.If you activate
enableImplicitConversionthen class-validator will do this transformation for you, but as the documentation states you should not enableenableImplicitConversionwhen using class-transformer.@hood May you verify and close this issue?
@murbanowicz adding
@Type(() => NestedType)seems to only be working on second level objects. If you go down one more level like in the OP validation doesn’t work on the third level object. I will try @gabrieloczkowski suggestion forenableImplicitConversion: truetoday and see if it works.