Hello,
i have something like this:
class Day
{
@IsMilitaryTime()
from: string;
@IsMilitaryTime()
to: string;
}
export class DailyCalendar
{
@IsDefined() // do i need it?
@ValidateNested()
monday: Day;
...
}
When calling the route with this body: { "monday": { "from": "foo" } } or { "monday": { } } it doesn't throw an error.
Also when not using @IsDefined() i can call the route without monday property and it doesn't throw an error.
The class will be created, but not validated.
@IsDefined() // do i need it?
You dont, it should throw by default when using @ValidateNested().
Do you use this with pleerock/routing-controllers? In previous versions, validation was turned off by default. Can you try with the latest version? (0.7.0-alpha.11)
Hello,
yes, I use it with routing-controllers. I updated from version 0.7.0-alpha.10 to 0.7.0-alpha.11, but didn't fix it.
Anyways I set the validation property to true in the createServer-function.
Well, the validation works in the main class.
E.g.: when I change my class to this:
...
@IsDefined()
monday: any;
...
and I don't provide the monday attribute in my http call, it will throw an BadRequestError.
It's just the nested validation, which doesn't work.
I am experiencing this issue right now as well - ValidateNested() doesn't seem to catch the errors on the nested objects. I have tried with both @IsDefined() and without it.
Version 0.7.1
Edit:
I suspect that this was an issue because I was just creating an object with the right fields, not an instance of a class, which is probably needed in order for the decorators to do their thing. I now use ES6 classes properly, and @ValidateNested() appears to be working correctly.
Post full code of how you substantiate the object to be validated. I use this annotation without issues. I believe you are not initializing the Monday obj properly.
Sent from my iPhone
On Jun 19, 2017, at 3:43 PM, Albert notifications@github.com wrote:
I am experiencing this issue right now as well - ValidateNested() doesn't seem to catch the errors on the nested objects. I have tried with both @IsDefined() and without it.
Version 0.7.1
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or mute the thread.
I suspect that this was an issue because I was just creating an object with the right fields, not an instance of a class, which is probably needed in order for the decorators to do their thing. I now use ES6 classes properly, and @ValidateNested() appears to be working correctly.
Yes, validation works only with instances of class decorated with constraints - for validating plain JS object I recommend you to use class-transformer-validator 😉
I have the same problem. This work for me:
export class ICreateOrUpdateActivity implements IActivity {
@IsString() title: string
@ValidateNested() @Type(() => ICreateOrUpdateActivityPrize) prizes: ICreateOrUpdateActivityPrize[]
@ValidateNested() @Type(() => ICreateOrUpdateActivityReply) replies: ICreateOrUpdateActivityReply[]
}
@Type is from module class-transformer.
Let mod = newModelC(rawjson);
Export class newModelC {
Constructor(rawjson){
Object.assign(this, rawjson)
Also works well and is standard javascript not supported in IE but the polyfills seem to handle this.
Sent from my iPhone
On Jun 28, 2017, at 9:41 AM, ruiming notifications@github.com wrote:
I have the same problem. This work for me:
export class ICreateOrUpdateActivity implements IActivity {
@IsString() title: string
@ValidateNested() @Type(() => ICreateOrUpdateActivityPrize) prizes: ICreateOrUpdateActivityPrize[]
@ValidateNested() @Type(() => ICreateOrUpdateActivityReply) replys: ICreateOrUpdateActivityReply[]
}
@Type is from module class-transformer.—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.
Hey @pleerock
any updates on this issue? We are using NestJS and are implementing a validation pipe (combination of class-transformer and class-validator). Unfortunately @ ValidateNested() still doesn't work as it doesn't return any errors in obviously wrong objects.
Best Regards
What issue? Your nested property has to be an instance of the class, not the plain object. Do it and it will be working fine 😉
Seems like I am a bit overworked, false alert:
My object I wanted to transform and validate was placed within a field and not the root object. So yeah, it's working like a charm now, sorry for any inconvenience caused.
I have another issue (using TypeScript 2.5.3, NodeJS 6.10.3 and class-validator 0.7.3):
class Nested {
foo: string;
}
class Klass {
@ValidateNested()
@IsDefined()
nested: Nested;
}
const obj = new Klass();
obj.nested = null as any; // I need `as any` because I'm using strictNullChecks
const res = validateSync(obj);
Last line throws an error Only objects and arrays are supported to nested validation (https://github.com/pleerock/class-validator/blob/master/src/validation/ValidationExecutor.ts#L208).
If I remove the line obj.nested = null as any, then obj.nested is undefined and everything works as expected - in this case I receive a validation error that obj.nested must be defined.
If I remove IsDefined then the error is still thrown.
@19majkel94 @jerradpatch I just wanted to point out that the original reported issue does still appear to be a problem. I'm also using routing-controllers, which uses class-transformer to transform the object I pass in into an actual instance of the class. Validation works for the main object, but does not work for nested objects.
I know the issue is not closed, but I wanted to make sure it was clear that there is still an issue that is not a user error.
Hi @Masterrg I'm also using Nestjs, could you share a simple example of how you do nested validation? I try with plainToClass on ValidatorPipe but only validates parent class.
Well, I've just solved my problem, I share the solution:
DummyDto (main class)
import { Type } from 'class-transformer';
import { Contains, ValidateNested } from 'class-validator';
import { SubDto } from './sub.dto';
export class DummyDto {
@Contains("hello")
public stringAttr: string;
@ValidateNested()
@Type(() => SubDto)
public subAttr: SubDto;
}
SubDto file:
import { Contains } from 'class-validator';
export class SubDto {
@Contains("eric")
public sub1: string;
public sub2: string;
}
This dto works:
{
"stringAttr": "hello",
"subAttr": {
"sub1": "eric",
"sub2": "subhello2"
}
}
This dto fails:
{
"stringAttr": "hello",
"subAttr": {
"sub1": "aaa",
"sub2": "subhello2"
}
}
Note for NestJs users:
The ValidatorPipe is very similar to the existing on docs.
I hope this helps somebody.
Thanks @ericzon It worked for me, but I needed to convert the body to class before hand using plainToClass function provided by class-transformer.
import { Type } from 'class-transformer';
import { IsDefined, ValidateNested } from 'class-validator';
export class SubDto {
@IsDefined()
public sub1: string;
}
export class MainDto {
@ValidateNested()
@Type(() => SubDto)
public subAttr: SubDto;
}
Body for both cases
const body = {
subAttr: {
sub1: 'str'
}
}
Does not fail
import { validate } from 'class-validator';
const validatorObject = Object.assign(new MainDto(), body);
const validationErrors = await validate(validatorObject);
// validationErrors = []
Does fail
import { validate } from 'class-validator';
import { plainToClass } from 'class-transformer';
const validatorObject = plainToClass(MainDto, body);
const validationErrors = await validate(validatorObject);
// validationErrors = [ValidationError]
https://github.com/typestack/class-validator#validating-plain-objects
Hi guys!
As discussed above, this is not an issue with class-validator itself. An instance of the class must be assigned to the properties to make class-validator works.
import { validate, IsMilitaryTime, IsDefined, ValidateNested } from 'class-validator';
class Day
{
@IsMilitaryTime()
from: string;
@IsMilitaryTime()
to: string;
constructor(from: string, to: string) {
this.from = from;
this.to = to;
}
}
export class DailyCalendar
{
@IsDefined()
@ValidateNested()
monday: Day;
constructor(day: any) {
this.monday = day;
}
}
const day = new Day('05:30', '05:');
const fails = new DailyCalendar(day);
const passes = new DailyCalendar({ from: '05:30', to: '05'});
const validationErrorsFails = await validate(fails);
const validationErrorsPasses = await validate(passes);
console.log(validationErrorsFails);
console.log(validationErrorsPasses);
Hi.
I had to validate a field representing an array of defined objects. I did this way, creating my decorator as a function.
export function IsArrayOfInstancesOf(className, validationOptions?: ValidationOptions) {
if (!validationOptions) {
validationOptions = {}
}
if (!validationOptions.message) {
validationOptions.message = "Value must be an array of valid(s) " + className.name;
}
return function (object: Object, propertyName: string) {
registerDecorator({
name: "IsArrayOfInstancesOf",
target: object.constructor,
propertyName: propertyName,
constraints: [],
options: validationOptions,
async: true,
validator: {
// https://github.com/typestack/class-validator/issues/83
async validate(value: any, args: ValidationArguments): Promise<boolean> {
const validator = new Validator();
if (! validator.isArray(value)) {
return false;
}
const items = value;
async function validateItem(item): Promise<boolean> {
const object = plainToClass(className, item);
const errors = await validate(object);
return !errors.length;
}
const validations = await Promise.all(items.map(validateItem));
// Si y'a au moins un false, on return false
return validations.filter(isValidated => !isValidated).length === 0;
}
}
});
}
}
And you use it this way
@IsArrayOfInstancesOf(ContractPaymentCreation)
public readonly payments: ContractPaymentCreation[];
Still have not found how to return sub-errors, I'd like to present them to client instead of just the generic one ("Value must be an array of[...]")
@NicolasCharpentier Please open a new question.
I just ran into this unexpected bug. It works fine if I have an actual instance of the type, but non-instances are ignored. E.g., in one of my unit tests, I'm casting a string to any, when it should be a class instance, and assigning the any to an array property on the parent. The any value passes as valid. I would expect this to throw an error because a string is not an instance of my expected type.
Example:
export class ChildPropertyType {
@IsDefined()
@IsNotEmpty()
@IsString()
public prop: string;
}
export class Parent {
@IsOptional()
@IsArray()
@ValidateNested()
@Type(type => ChildPropertyType)
public children: ChildPropertyType[];
}
// in the unit test
const p = new Parent();
p.children = [<any>'string'];
// call validate... no errors thrown.
The reason I even tried this is because we want to have more control over error responses, so we turned off validation in routing-controllers and call the validation method manually. This allows for clients to pass in any info they want and it by-passes the validation routine.
Please open a new issue if you encounter a similar problem.
@ps2goat there is no validation error because there is no validation metadata for a string so it's "passes" the validation. You can set forbidUnknownValues to true to throw an error on unknown values.
validate(p, { forbidUnknownValues: true })
Most helpful comment
Well, I've just solved my problem, I share the solution:
DummyDto (main class)
SubDto file:
This dto works:
This dto fails:
Note for NestJs users:
The ValidatorPipe is very similar to the existing on docs.
I hope this helps somebody.