Class-validator: feat: add option to define class level custom decorators

Created on 22 Mar 2018  路  20Comments  路  Source: typestack/class-validator

Is there support for validation on a class level and not just property level? I want to do DB lookups but issue a single query vs one per field.

feature

Most helpful comment

This makes a lot of sense to me - I was thinking of exactly the same thing (specifically wanting to do Joi's with and or validators.

All 20 comments

Can you elaborate please, give me some theoretical example code?

In the class-validator world:

@IsUnique(WidgetRepository, ["name", "tag"])
export class Widget {
  @IsString()
  name: string;

  @IsString()
  @IsLowercase()
  tag: string;
}

@IsUnique would use something like typedi to get the repository from the container, and the array would be the fields that are to be unique.

I could think of a few more examples that would be nice to compare all fields at once. The main example is to do a single query utilizing the object after all field validations passed.

Have you seen TypeORM? It's exactly what you are looking for.

I'm not using TypeORM. I'm using MongoDB at the moment and they are pretty far behind in driver support. And not a lot of movement in MongoDB within TypeORM (issues grow, nothing getting done).

I'd like to push it to a validation library. The Symfony library I referenced above is a class validation library such as this one with support for validating DoctrineORM objects.

Edit: I'm also using https://github.com/19majkel94/type-graphql which has built-in support for this library.

Then you can create such functionality here via

@NoNameProvided I created a decorator already, but it's bound to the field and not the class, so I lack access to multiple fields.

Edit: I might be able to access multiple fields, but if so, it wouldn't be clear what the validation is trying to do.

I created a decorator already, but it's bound to the field and not the class, so I lack access to multiple fields.

You can create multi-field validations. Here is an example: https://github.com/typestack/class-validator/issues/145#issuecomment-373949845

I might be able to access multiple fields, but if so, it wouldn't be clear what the validation is trying to do.

In your example, it totally makes sense to put it on the unique property instead of the class.

Yes, in my fake example use-case, perhaps it can be solved "cleanishly" (although the two fields are not related at all, so IMO it's not clean and is actually more confusing).

Another example where it makes more sense on a class level:

@IsValidLocation(['address1', 'address2', 'city', 'state', 'zip'])
export class User {
  address1: string;
  address2: string;
  city: string;
  state: string;
  zip: string;
}

or

@IsValidLogin()
export class Auth {
  username: string;
  password: string;
}
// This may do a true lookup on the image, verify image size, etc, etc... I don't see this being clean on a field level.

@IsImageValid(({ baseUrl, name, extension }) => `${baseUrl)${name}${extension}`)
export class Image {
  @IsURL()
  baseURL: string;

  @IsString()
  name: string;

  @IsValidExtension()
  extension: string;
}

Others do it:

I see where if you're comparing a field to another field, then field level validation works and makes sense, but if the fields aren't being compared and are being used as a final validation constraint, then it'd make more sense on the class level. It can also be an area where you may do heavier validations. You can run your simple field level validations first, then do things like DB lookups, external requests, etc, on a class level so that simple validations can fail first.

As of now, I'd never do any of these examples with class-validator and am forced to do these types of validations hardcoded in my app. It'd be awesome to have it all in one place.

This makes a lot of sense to me - I was thinking of exactly the same thing (specifically wanting to do Joi's with and or validators.

Anything on this issue? Class level validators are very useful.

Up, for example I have this case:

// Having at least one of the two set.
@ClassLevelValidator(post => post.articleId != null || post.externalLink != null)
export class PostDto {
  @IsNotEmpty()
  @IsString()
  title: string;

  @IsDefined()
  @IsString()
  shortDescription: string;

  @IsOptional()
  @IsInt()
  articleId: number; // if set I know this post relate to an article entity, that I can retrieve using the id

  @IsOptional()
  @IsUrl()
  externalLink: string; // if set I know this post relate to an external link.
}

// if both are set or none are set then this is a wrong entry.

It do exist in Java https://stackoverflow.com/questions/2781771/how-can-i-validate-two-or-more-fields-in-combination

Generic Unique Constrain For any Column I hope we can Use below code like

File Name:- isUnique.ts
@ValidatorConstraint({ async: true }) export class IsUniqueConstraint implements ValidatorConstraintInterface { validate(columnNameValue: any, args: ValidationArguments) { let columnNameKey = args.property; let tableName = args.targetName; return getManager().query("SELECT * FROM " + tableName + " WHERE " + columnNameKey + " = ?", [columnNameValue]).then(user => { if (user[0]) return false; return true; }); } } export function IsUnique(validationOptions?: ValidationOptions) { return function (object: Object, propertyName: string) { registerDecorator({ target: object.constructor, propertyName: propertyName, options: validationOptions, constraints: [], validator: IsUniqueConstraint }); }; }

Can be use in Typeorm Model Users as

@Column() @IsEmail({}, { message: 'Invalid email Address.' }) @IsUnique({ message: "Email $value already exists. Choose another name." }) email: string;

@Column() @Length(4, 20) @IsUnique({ message: "User Name $value already exists. Choose another name." }) username: string;

So it will be common for any model table.

I was also hoping for a class-level validator, any news about this?

Voting up for class level decorators. Would be a useful feature.

@NoNameProvided this is pretty wanted.

Sure. We are open to proposals how this may works. But for now this is future request.

Hey, I made a tiny package that solves this exact problem, I tried to remain as close as possible to class-validator API
https://github.com/astahmer/entity-validator/

my need for "class level" is to validate across multiple properties at the same time versus just one... i was concerned when i saw this issue still open... yet issue #759 referencing the docs Custom validation decorators - @IsLongerThan() example shows how to reference the any of the current objects properties inside the validator so i'm hopeful i can adapt that to my needs... just wanted to post in case it helps others

Any updates on this issue?

Was this page helpful?
0 / 5 - 0 ratings