Class-validator: feat: add option to stop validation after first validation error

Created on 13 Apr 2018  路  21Comments  路  Source: typestack/class-validator

If i apply the following annotations:

  @IsNotEmpty()
  @IsInt()
  @Min(0)
  foobar: number;

The validation result will be:

{ 
  "value": null, 
  "property": "foobar", 
  "children": [], 
  "constraints": {
    "min": "foobar must be greater than 0",
   "isInt": "foobar must be an integer number", 
   "isNotEmpty": "foobar should not be empty" 
  } 
}

If no value is given (i.e.: foobar === null), I only want the validation result of @IsNotEmpty.
All the others are quite useless... worse: since the validation errors (the constraints) are stored in an object, the ordering is lost so I cannot "just take the first error constraint" :(

Expected result:

{ 
  "value": null, 
  "property": "foobar", 
  "children": [], 
  "constraints": {
   "isNotEmpty": "foobar should not be empty" 
  } 
}

or:

 { 
  "value": null, 
  "property": "foobar", 
  "children": [], 
  "constraints": [
    {"isNotEmpty": "foobar should not be empty" },
    {"isInt": "foobar must be an integer number"},
    { "min": "foobar must be greater than 0"}
  ]
}
fixed feature

Most helpful comment

I agree.
Would be much efficient when no validators would run after one failed.

My example:

  @IsInt()
  @IsInModel({ model: User, property: 'id' })
  userId: number;

IsInModel will still run even though userId sent as string.

And error will look doubled and not so smart: User id must be an integer number. Invalid user id

All 21 comments

Is this a feature request? What would be your ideal format?

Yes, this is a feature request :)

The result with all validations as list would be nice:

{ "value": null,
  "property": "foobar",
  "children": [], 
  "constraints": [ 
    {"isNotEmpty": "foobar should not be empty" },
    {"isInt": "foobar must be an integer number"},
    { "min": "foobar must be greater than 0"}
}

with the constraints ordering same as annotation ordering

It would be nice if there is a setting that makes the validator stop after the very first fail. For example, I have custom constraint that checks the database for email existence. I used the following decorators:

@IsNotEmpty()
@Length(3, 50)
@EmailNotExists()
email: string;

This makes database query even if email is empty or with less than 3 characters. Of course I could add additional checks in my constraint, but it makes no sense to do that.

@kostanev is making a good point

Regarding: making the validator stop after the very first fail...

I just had a look a Java Bean Validation: https://docs.oracle.com/javaee/6/tutorial/doc/gircz.html
(or better said: I've been jusing Bean Validation for years :)) and its behavior towards null just makes it easy to use:
all validations allow null, except those that explicitly check for null (and/or undefined for our case).

This in combination with validation in declaration-order make for a intuitive use... maybe this would be nice here, too? This would also solve kostanev's and my problem...

Also: @IsOptional could then be removed

This null/undefined behaviour bugged me so much I just implemented this :)
See commit 4ac6797

And validation with only 1 validation result is implemented in 1ee346b

@NoNameProvided I didn't review the PR thoroughly but, this type of behavior is desired.

It would be great if we could stop a rule from executing given the failure of another constraint on the property. Having this configurable as a validation option, such as exceptWhen: ['isNotEmpty'] would be great.

As of now, I implemented a stopgap by using the context property and configured my service that executes the validation and normalizes the results to exclude anything given my configuration.

Would this be something you would be interested in adding to the feature set if it were built in as a new validation option?

The problem with my current approach is, as @kostanev stated, it'll still make db or api calls when undesired. Another issue I have with returning all errors as it is today is, if you were to present all errors to the user, they may see some that don't pertain such as in the case

@IsDefined()
@IsNotEmpty()
@IsString()
@MaxLength(255)
public someText: string;

If nothing was provided, the user would be told, someText cannot exceed 255 characters. However, if the @ValidateIf decorator was used, to not validate in nothing is there, it would remove the behavior that was informing the user it's required.

What would be great here is, if we could introduce some kind of if/then approach to validators. Given something passes, execute the next, else break and return

all validations allow null, except those that explicitly check for null (and/or undefined for our case).
Also: @IsOptional could then be removed

Just use skipMissingProperties: true with @IsDefined

I agree.
Would be much efficient when no validators would run after one failed.

My example:

  @IsInt()
  @IsInModel({ model: User, property: 'id' })
  userId: number;

IsInModel will still run even though userId sent as string.

And error will look doubled and not so smart: User id must be an integer number. Invalid user id

+1
I want an option for this feature

Any update on the topic? Just came around this, and I think it can become a performance issue to be requesting the database everytime a new request comes in with invalid data

Any update on this issue?

I also need a feature

The feature to stop executing the validation rules if the first validation fails would help alot.

+1. I need too

+1. I need this too.....

For those that are interested, I had the exact same problem as @ph55 . You can use validation groups to solve this issue:

  @IsInt({groups: ["validate-types"] })
  @IsInModel({ model: User, property: 'id' })
  userId: number;

and then run the validation twice:

    await validateOrReject(this, {
      groups: ["validate-types"]
    });
    await validateOrReject(this);

The first validateOrReject call only runs the "type check" validators, and the second call runs through all of the validators. By doing this, you can avoid running validators on values that don't match the type you expect (which as others have mentioned, makes no sense to do and is completely useless).

Looks like #620 will actually fix this issue...

This has been fixed in develop via #620 and be included in the next release.

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MistyKuu picture MistyKuu  路  3Comments

btd1337 picture btd1337  路  5Comments

jerradpatch picture jerradpatch  路  5Comments

golozubov picture golozubov  路  5Comments

AndyBarron picture AndyBarron  路  3Comments