deno_class_validator
Forked from class-validator, now for Deno.
We can use like this:
import {
Contains,
IsDate,
IsEmail,
IsFQDN,
IsInt,
Length,
Max,
Min,
validate,
validateOrReject,
} from "https://deno.land/x/deno_class_validator/mod.ts";
Below is the origin docs.
Allows use of decorator and non-decorator based validation. Internally uses validator.js to perform validation. Class-validator works on both browser and node.js platforms.
Table of Contents
- deno_class_validator
- Table of Contents
- Installation
- Usage
- Validation errors
- Validation messages
- Validating arrays
- Validating sets
- Validating maps
- Validating nested objects
- Validating promises
- Inheriting Validation decorators
- Conditional validation
- Whitelisting
- Passing context to decorators
- Skipping missing properties
- Validation groups
- Custom validation classes
- Custom validation decorators
- Using service container
- Synchronous validation
- Manual validation
- Validation decorators
- Defining validation schema without decorators
- Validating plain objects
- Samples
- Extensions
- Release notes decorators](#defining-validation-schema-without-decorators)
- Validating plain objects
- Samples
- Extensions
- Release notes
Installation
npm install class-validator --save
Note: Please use at least npm@6 when using class-validator. From npm@6 the dependency tree is flattened, which is required by
class-validator
to function properly.
Usage
Create your class and put some validation decorators on the properties you want to validate:
import {
Contains,
IsDate,
IsEmail,
IsFQDN,
IsInt,
Length,
Max,
Min,
validate,
validateOrReject,
} from "class-validator";
export class Post {
@Length(10, 20)
title: string;
@Contains("hello")
text: string;
@IsInt()
@Min(0)
@Max(10)
rating: number;
@IsEmail()
email: string;
@IsFQDN()
site: string;
@IsDate()
createDate: Date;
}
let post = new Post();
post.title = "Hello"; // should not pass
post.text = "this is a great post about hell world"; // should not pass
post.rating = 11; // should not pass
post.email = "google.com"; // should not pass
post.site = "googlecom"; // should not pass
validate(post).then((errors) => {
// errors is an array of validation errors
if (errors.length > 0) {
console.log("validation failed. errors: ", errors);
} else {
console.log("validation succeed");
}
});
validateOrReject(post).catch((errors) => {
console.log("Promise rejected (validation failed). Errors: ", errors);
});
// or
async function validateOrRejectExample(input) {
try {
await validateOrReject(input);
} catch (errors) {
console.log(
"Caught promise rejection (validation failed). Errors: ",
errors,
);
}
}
Passing options
The validate
function optionally expects a ValidatorOptions
object as a
second parameter:
export interface ValidatorOptions {
skipMissingProperties?: boolean;
whitelist?: boolean;
forbidNonWhitelisted?: boolean;
groups?: string[];
dismissDefaultMessages?: boolean;
validationError?: {
target?: boolean;
value?: boolean;
};
forbidUnknownValues?: boolean;
stopAtFirstError?: boolean;
}
It’s highly advised to set
forbidUnknownValues: true
as it will prevent unknown objects from passing validation.
Validation errors
The validate
method returns an array of ValidationError
objects. Each
ValidationError
is:
{
target: Object; // Object that was validated.
property: string; // Object's property that haven't pass validation.
value: any; // Value that haven't pass a validation.
constraints?: { // Constraints that failed validation with error messages.
[type: string]: string;
};
children?: ValidationError[]; // Contains all nested validation errors of the property
}
In our case, when we validated a Post object, we have such an array of
ValidationError
objects:
[{
target: /* post object */,
property: "title",
value: "Hello",
constraints: {
length: "$property must be longer than or equal to 10 characters"
}
}, {
target: /* post object */,
property: "text",
value: "this is a great post about hell world",
constraints: {
contains: "text must contain a hello string"
}
},
// and other errors
]
If you don’t want a target
to be exposed in validation errors, there is a
special option when you use validator:
validator.validate(post, { validationError: { target: false } });
This is especially useful when you send errors back over http, and you most probably don’t want to expose the whole target object.
Validation messages
You can specify validation message in the decorator options and that message
will be returned in the ValidationError
returned by the validate
method (in
the case that validation for this field fails).
import { MaxLength, MinLength } from "class-validator";
export class Post {
@MinLength(10, {
message: "Title is too short",
})
@MaxLength(50, {
message: "Title is too long",
})
title: string;
}
There are few special tokens you can use in your messages:
$value
- the value that is being validated$property
- name of the object’s property being validated$target
- name of the object’s class being validated$constraint1
,$constraint2
, …$constraintN
- constraints defined by specific validation type
Example of usage:
import { MaxLength, MinLength } from "class-validator";
export class Post {
@MinLength(10, {
// here, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>c</mi><mi>o</mi><mi>n</mi><mi>s</mi><mi>t</mi><mi>r</mi><mi>a</mi><mi>i</mi><mi>n</mi><mi>t</mi><mn>1</mn><mi>w</mi><mi>i</mi><mi>l</mi><mi>l</mi><mi>b</mi><mi>e</mi><mi>r</mi><mi>e</mi><mi>p</mi><mi>l</mi><mi>a</mi><mi>c</mi><mi>e</mi><mi>d</mi><mi>w</mi><mi>i</mi><mi>t</mi><mi>h</mi><mi mathvariant="normal">"</mi><mn>10</mn><mi mathvariant="normal">"</mi><mo separator="true">,</mo><mi>a</mi><mi>n</mi><mi>d</mi></mrow><annotation encoding="application/x-tex">constraint1 will be replaced with "10", and </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">co</span><span class="mord mathnormal">n</span><span class="mord mathnormal">s</span><span class="mord mathnormal">t</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">ain</span><span class="mord mathnormal">t</span><span class="mord">1</span><span class="mord mathnormal" style="margin-right:0.02691em;">w</span><span class="mord mathnormal">i</span><span class="mord mathnormal" style="margin-right:0.01968em;">ll</span><span class="mord mathnormal">b</span><span class="mord mathnormal">ere</span><span class="mord mathnormal" style="margin-right:0.01968em;">pl</span><span class="mord mathnormal">a</span><span class="mord mathnormal">ce</span><span class="mord mathnormal">d</span><span class="mord mathnormal" style="margin-right:0.02691em;">w</span><span class="mord mathnormal">i</span><span class="mord mathnormal">t</span><span class="mord mathnormal">h</span><span class="mord">"10"</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">an</span><span class="mord mathnormal">d</span></span></span></span>value with actual supplied value
message:
"Title is too short. Minimal length is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>c</mi><mi>o</mi><mi>n</mi><mi>s</mi><mi>t</mi><mi>r</mi><mi>a</mi><mi>i</mi><mi>n</mi><mi>t</mi><mn>1</mn><mi>c</mi><mi>h</mi><mi>a</mi><mi>r</mi><mi>a</mi><mi>c</mi><mi>t</mi><mi>e</mi><mi>r</mi><mi>s</mi><mo separator="true">,</mo><mi>b</mi><mi>u</mi><mi>t</mi><mi>a</mi><mi>c</mi><mi>t</mi><mi>u</mi><mi>a</mi><mi>l</mi><mi>i</mi><mi>s</mi></mrow><annotation encoding="application/x-tex">constraint1 characters, but actual is </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">co</span><span class="mord mathnormal">n</span><span class="mord mathnormal">s</span><span class="mord mathnormal">t</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">ain</span><span class="mord mathnormal">t</span><span class="mord">1</span><span class="mord mathnormal">c</span><span class="mord mathnormal">ha</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">a</span><span class="mord mathnormal">c</span><span class="mord mathnormal">t</span><span class="mord mathnormal">ers</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">b</span><span class="mord mathnormal">u</span><span class="mord mathnormal">t</span><span class="mord mathnormal">a</span><span class="mord mathnormal">c</span><span class="mord mathnormal">t</span><span class="mord mathnormal">u</span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">i</span><span class="mord mathnormal">s</span></span></span></span>value",
})
@MaxLength(50, {
// here, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>c</mi><mi>o</mi><mi>n</mi><mi>s</mi><mi>t</mi><mi>r</mi><mi>a</mi><mi>i</mi><mi>n</mi><mi>t</mi><mn>1</mn><mi>w</mi><mi>i</mi><mi>l</mi><mi>l</mi><mi>b</mi><mi>e</mi><mi>r</mi><mi>e</mi><mi>p</mi><mi>l</mi><mi>a</mi><mi>c</mi><mi>e</mi><mi>d</mi><mi>w</mi><mi>i</mi><mi>t</mi><mi>h</mi><mi mathvariant="normal">"</mi><mn>50</mn><mi mathvariant="normal">"</mi><mo separator="true">,</mo><mi>a</mi><mi>n</mi><mi>d</mi></mrow><annotation encoding="application/x-tex">constraint1 will be replaced with "50", and </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">co</span><span class="mord mathnormal">n</span><span class="mord mathnormal">s</span><span class="mord mathnormal">t</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">ain</span><span class="mord mathnormal">t</span><span class="mord">1</span><span class="mord mathnormal" style="margin-right:0.02691em;">w</span><span class="mord mathnormal">i</span><span class="mord mathnormal" style="margin-right:0.01968em;">ll</span><span class="mord mathnormal">b</span><span class="mord mathnormal">ere</span><span class="mord mathnormal" style="margin-right:0.01968em;">pl</span><span class="mord mathnormal">a</span><span class="mord mathnormal">ce</span><span class="mord mathnormal">d</span><span class="mord mathnormal" style="margin-right:0.02691em;">w</span><span class="mord mathnormal">i</span><span class="mord mathnormal">t</span><span class="mord mathnormal">h</span><span class="mord">"50"</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">an</span><span class="mord mathnormal">d</span></span></span></span>value with actual supplied value
message:
"Title is too long. Maximal length is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>c</mi><mi>o</mi><mi>n</mi><mi>s</mi><mi>t</mi><mi>r</mi><mi>a</mi><mi>i</mi><mi>n</mi><mi>t</mi><mn>1</mn><mi>c</mi><mi>h</mi><mi>a</mi><mi>r</mi><mi>a</mi><mi>c</mi><mi>t</mi><mi>e</mi><mi>r</mi><mi>s</mi><mo separator="true">,</mo><mi>b</mi><mi>u</mi><mi>t</mi><mi>a</mi><mi>c</mi><mi>t</mi><mi>u</mi><mi>a</mi><mi>l</mi><mi>i</mi><mi>s</mi></mrow><annotation encoding="application/x-tex">constraint1 characters, but actual is </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">co</span><span class="mord mathnormal">n</span><span class="mord mathnormal">s</span><span class="mord mathnormal">t</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">ain</span><span class="mord mathnormal">t</span><span class="mord">1</span><span class="mord mathnormal">c</span><span class="mord mathnormal">ha</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">a</span><span class="mord mathnormal">c</span><span class="mord mathnormal">t</span><span class="mord mathnormal">ers</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">b</span><span class="mord mathnormal">u</span><span class="mord mathnormal">t</span><span class="mord mathnormal">a</span><span class="mord mathnormal">c</span><span class="mord mathnormal">t</span><span class="mord mathnormal">u</span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">i</span><span class="mord mathnormal">s</span></span></span></span>value",
})
title: string;
}
Also you can provide a function, that returns a message. This allows you to create more granular messages:
import { MaxLength, MinLength, ValidationArguments } from "class-validator";
export class Post {
@MinLength(10, {
message: (args: ValidationArguments) => {
if (args.value.length === 1) {
return "Too short, minimum length is 1 character";
} else {
return "Too short, minimum length is " + args.constraints[0] +
" characters";
}
},
})
title: string;
}
Message function accepts ValidationArguments
which contains the following
information:
value
- the value that is being validatedconstraints
- array of constraints defined by specific validation typetargetName
- name of the object’s class being validatedobject
- object that is being validatedproperty
- name of the object’s property being validated
Validating arrays
If your field is an array and you want to perform validation of each item in the
array you must specify a special each: true
decorator option:
import { MaxLength, MinLength } from "class-validator";
export class Post {
@MaxLength(20, {
each: true,
})
tags: string[];
}
This will validate each item in post.tags
array.
Validating sets
If your field is a set and you want to perform validation of each item in the
set you must specify a special each: true
decorator option:
import { MaxLength, MinLength } from "class-validator";
export class Post {
@MaxLength(20, {
each: true,
})
tags: Set<string>;
}
This will validate each item in post.tags
set.
Validating maps
If your field is a map and you want to perform validation of each item in the
map you must specify a special each: true
decorator option:
import { MaxLength, MinLength } from "class-validator";
export class Post {
@MaxLength(20, {
each: true,
})
tags: Map<string, string>;
}
This will validate each item in post.tags
map.
Validating nested objects
If your object contains nested objects and you want the validator to perform
their validation too, then you need to use the @ValidateNested()
decorator:
import { ValidateNested } from "class-validator";
export class Post {
@ValidateNested()
user: User;
}
Please note that nested object must be an instance of a class, otherwise
@ValidateNested
won’t know what class is target of validation. Check also
Validating plain objects.
It also works with multi-dimensional array, like :
import { ValidateNested } from "class-validator";
export class Plan2D {
@ValidateNested()
matrix: Point[][];
}
Validating promises
If your object contains property with Promise
-returned value that should be
validated, then you need to use the @ValidatePromise()
decorator:
import { Min, ValidatePromise } from "class-validator";
export class Post {
@Min(0)
@ValidatePromise()
userId: Promise<number>;
}
It also works great with @ValidateNested
decorator:
import { ValidateNested, ValidatePromise } from "class-validator";
export class Post {
@ValidateNested()
@ValidatePromise()
user: Promise<User>;
}
Inheriting Validation decorators
When you define a subclass which extends from another one, the subclass will automatically inherit the parent’s decorators. If a property is redefined in the descendant class decorators will be applied on it both from that and the base class.
import { validate } from "class-validator";
class BaseContent {
@IsEmail()
email: string;
@IsString()
password: string;
}
class User extends BaseContent {
@MinLength(10)
@MaxLength(20)
name: string;
@Contains("hello")
welcome: string;
@MinLength(20)
password: string;
}
let user = new User();
user.email = "invalid email"; // inherited property
user.password = "too short"; // password wil be validated not only against IsString, but against MinLength as well
user.name = "not valid";
user.welcome = "helo";
validate(user).then((errors) => {
// ...
}); // it will return errors for email, title and text properties
Conditional validation
The conditional validation decorator (@ValidateIf
) can be used to ignore the
validators on a property when the provided condition function returns false. The
condition function takes the object being validated and must return a boolean
.
import { IsNotEmpty, ValidateIf } from "class-validator";
export class Post {
otherProperty: string;
@ValidateIf((o) => o.otherProperty === "value")
@IsNotEmpty()
example: string;
}
In the example above, the validation rules applied to example
won’t be run
unless the object’s otherProperty
is "value"
.
Note that when the condition is false all validation decorators are ignored,
including isDefined
.
Whitelisting
Even if your object is an instance of a validation class it can contain
additional properties that are not defined. If you do not want to have such
properties on your object, pass special flag to validate
method:
import { validate } from "class-validator";
// ...
validate(post, { whitelist: true });
This will strip all properties that don’t have any decorators. If no other decorator is suitable for your property, you can use @Allow decorator:
import {validate, Allow, Min} from "class-validator";
export class Post {
@Allow()
title: string;
@Min(0)
views: number;
nonWhitelistedProperty: number;
}
let post = new Post();
post.title = 'Hello world!';
post.views = 420;
post.nonWhitelistedProperty = 69;
(post as any).anotherNonWhitelistedProperty = "something";
validate(post).then(errors => {
// post.nonWhitelistedProperty is not defined
// (post as any).anotherNonWhitelistedProperty is not defined
...
});
If you would rather to have an error thrown when any non-whitelisted properties
are present, pass another flag to validate
method:
import { validate } from "class-validator";
// ...
validate(post, { whitelist: true, forbidNonWhitelisted: true });
Passing context to decorators
It’s possible to pass a custom object to decorators which will be accessible on
the ValidationError
instance of the property if validation failed.
import { validate } from "class-validator";
class MyClass {
@MinLength(32, {
message: "EIC code must be at least 32 characters",
context: {
errorCode: 1003,
developerNote: "The validated string must contain 32 or more characters.",
},
})
eicCode: string;
}
const model = new MyClass();
validate(model).then((errors) => {
//errors[0].contexts['minLength'].errorCode === 1003
});
Skipping missing properties
Sometimes you may want to skip validation of the properties that do not exist in
the validating object. This is usually desirable when you want to update some
parts of the object, and want to validate only updated parts, but skip
everything else, e.g. skip missing properties. In such situations you will need
to pass a special flag to validate
method:
import { validate } from "class-validator";
// ...
validate(post, { skipMissingProperties: true });
When skipping missing properties, sometimes you want not to skip all missing
properties, some of them maybe required for you, even if skipMissingProperties
is set to true. For such cases you should use @IsDefined()
decorator.
@IsDefined()
is the only decorator that ignores skipMissingProperties
option.
Validation groups
In different situations you may want to use different validation schemas of the same object. In such cases you can use validation groups.
import { Length, Min, validate } from "class-validator";
export class User {
@Min(12, {
groups: ["registration"],
})
age: number;
@Length(2, 20, {
groups: ["registration", "admin"],
})
name: string;
}
let user = new User();
user.age = 10;
user.name = "Alex";
validate(user, {
groups: ["registration"],
}); // this will not pass validation
validate(user, {
groups: ["admin"],
}); // this will pass validation
validate(user, {
groups: ["registration", "admin"],
}); // this will not pass validation
validate(user, {
groups: undefined, // the default
}); // this will not pass validation since all properties get validated regardless of their groups
validate(user, {
groups: [],
}); // this will not pass validation, (equivalent to 'groups: undefined', see above)
There is also a special flag always: true
in validation options that you can
use. This flag says that this validation must be applied always no matter which
group is used.
Custom validation classes
If you have custom validation logic you can create a Constraint class:
First create a file, lets say
CustomTextLength.ts
, and define a new class:import { ValidationArguments, ValidatorConstraint, ValidatorConstraintInterface, } from "class-validator"; @ValidatorConstraint({ name: "customText", async: false }) export class CustomTextLength implements ValidatorConstraintInterface { validate(text: string, args: ValidationArguments) { return text.length > 1 && text.length < 10; // for async validations you must return a Promise<boolean> here } defaultMessage(args: ValidationArguments) { // here you can provide default error message if validation failed return "Text ($value) is too short or too long!"; } }
We marked our class with
@ValidatorConstraint
decorator. You can also supply a validation constraint name - this name will be used as “error type” in ValidationError. If you will not supply a constraint name - it will be auto-generated.Our class must implement
ValidatorConstraintInterface
interface and itsvalidate
method, which defines validation logic. If validation succeeds, method returns true, otherwise false. Custom validator can be asynchronous, if you want to perform validation after some asynchronous operations, simply return a promise with boolean inside invalidate
method.Also we defined optional method
defaultMessage
which defines a default error message, in the case that the decorator’s implementation doesn’t set an error message.
Then you can use your new validation constraint in your class:
import { Validate } from "class-validator"; import { CustomTextLength } from "./CustomTextLength"; export class Post { @Validate(CustomTextLength, { message: "Title is too short or long!", }) title: string; }
Here we set our newly created
CustomTextLength
validation constraint forPost.title
.And use validator as usual:
import { validate } from "class-validator"; validate(post).then((errors) => { // ... });
You can also pass constraints to your validator, like this:
import { Validate } from "class-validator";
import { CustomTextLength } from "./CustomTextLength";
export class Post {
@Validate(CustomTextLength, [3, 20], {
message: "Wrong post title",
})
title: string;
}
And use them from validationArguments
object:
import {
ValidationArguments,
ValidatorConstraint,
ValidatorConstraintInterface,
} from "class-validator";
@ValidatorConstraint()
export class CustomTextLength implements ValidatorConstraintInterface {
validate(text: string, validationArguments: ValidationArguments) {
return text.length > validationArguments.constraints[0] &&
text.length < validationArguments.constraints[1];
}
}
Custom validation decorators
You can also create a custom decorators. Its the most elegant way of using a
custom validations. Lets create a decorator called @IsLongerThan
:
Create a decorator itself:
import { registerDecorator, ValidationArguments, ValidationOptions, } from "class-validator"; export function IsLongerThan( property: string, validationOptions?: ValidationOptions, ) { return function (object: Object, propertyName: string) { registerDecorator({ name: "isLongerThan", target: object.constructor, propertyName: propertyName, constraints: [property], options: validationOptions, validator: { validate(value: any, args: ValidationArguments) { const [relatedPropertyName] = args.constraints; const relatedValue = (args.object as any)[relatedPropertyName]; return typeof value === "string" && typeof relatedValue === "string" && value.length > relatedValue.length; // you can return a Promise<boolean> here as well, if you want to make async validation }, }, }); }; }
Put it to use:
import { IsLongerThan } from "./IsLongerThan"; export class Post { title: string; @IsLongerThan("title", { /* you can also use additional validation options, like "groups" in your custom validation decorators. "each" is not supported */ message: "Text must be longer than the title", }) text: string; }
In your custom decorators you can also use ValidationConstraint
. Lets create
another custom validation decorator called IsUserAlreadyExist
:
Create a ValidationConstraint and decorator:
import { registerDecorator, ValidationArguments, ValidationOptions, ValidatorConstraint, ValidatorConstraintInterface, } from "class-validator"; @ValidatorConstraint({ async: true }) export class IsUserAlreadyExistConstraint implements ValidatorConstraintInterface { validate(userName: any, args: ValidationArguments) { return UserRepository.findOneByName(userName).then((user) => { if (user) return false; return true; }); } } export function IsUserAlreadyExist(validationOptions?: ValidationOptions) { return function (object: Object, propertyName: string) { registerDecorator({ target: object.constructor, propertyName: propertyName, options: validationOptions, constraints: [], validator: IsUserAlreadyExistConstraint, }); }; }
note that we marked our constraint that it will by async by adding
{ async: true }
in validation options.And put it to use:
import { IsUserAlreadyExist } from "./IsUserAlreadyExist"; export class User { @IsUserAlreadyExist({ message: "User $value already exists. Choose another name.", }) name: string; }
Using service container
Validator supports service container in the case if want to inject dependencies into your custom validator constraint classes. Here is example how to integrate it with typedi:
import { Container } from "typedi";
import { useContainer, Validator } from "class-validator";
// do this somewhere in the global application level:
useContainer(Container);
let validator = Container.get(Validator);
// now everywhere you can inject Validator class which will go from the container
// also you can inject classes using constructor injection into your custom ValidatorConstraint-s
Synchronous validation
If you want to perform a simple non async validation you can use validateSync
method instead of regular validate
method. It has the same arguments as
validate
method. But note, this method ignores all async validations you
have.
Manual validation
There are several method exist in the Validator that allows to perform non-decorator based validation:
import { isBoolean, isEmpty } from "class-validator";
isEmpty(value);
isBoolean(value);
Validation decorators
Decorator | Description |
---|---|
Common validation decorators | |
@IsDefined(value: any) |
Checks if value is defined (!== undefined, !== null). This is the only decorator that ignores skipMissingProperties option. |
@IsOptional() |
Checks if given value is empty (=== null, === undefined) and if so, ignores all the validators on the property. |
@Equals(comparison: any) |
Checks if value equals (“===”) comparison. |
@NotEquals(comparison: any) |
Checks if value not equal (“!==”) comparison. |
@IsEmpty() |
Checks if given value is empty (=== ”, === null, === undefined). |
@IsNotEmpty() |
Checks if given value is not empty (!== ”, !== null, !== undefined). |
@IsIn(values: any[]) |
Checks if value is in a array of allowed values. |
@IsNotIn(values: any[]) |
Checks if value is not in a array of disallowed values. |
Type validation decorators | |
@IsBoolean() |
Checks if a value is a boolean. |
@IsDate() |
Checks if the value is a date. |
@IsString() |
Checks if the string is a string. |
@IsNumber(options: IsNumberOptions) |
Checks if the value is a number. |
@IsInt() |
Checks if the value is an integer number. |
@IsArray() |
Checks if the value is an array |
@IsEnum(entity: object) |
Checks if the value is an valid enum |
Number validation decorators | |
@IsDivisibleBy(num: number) |
Checks if the value is a number that’s divisible by another. |
@IsPositive() |
Checks if the value is a positive number greater than zero. |
@IsNegative() |
Checks if the value is a negative number smaller than zero. |
@Min(min: number) |
Checks if the given number is greater than or equal to given number. |
@Max(max: number) |
Checks if the given number is less than or equal to given number. |
Date validation decorators | |
@MinDate(date: Date) |
Checks if the value is a date that’s after the specified date. |
@MaxDate(date: Date) |
Checks if the value is a date that’s before the specified date. |
String-type validation decorators | |
@IsBooleanString() |
Checks if a string is a boolean (e.g. is “true” or “false”). |
@IsDateString() |
Alias for @IsISO8601() . |
@IsNumberString(options?: IsNumericOptions) |
Checks if a string is a number. |
String validation decorators | |
@Contains(seed: string) |
Checks if the string contains the seed. |
@NotContains(seed: string) |
Checks if the string not contains the seed. |
@IsAlpha() |
Checks if the string contains only letters (a-zA-Z). |
@IsAlphanumeric() |
Checks if the string contains only letters and numbers. |
@IsDecimal(options?: IsDecimalOptions) |
Checks if the string is a valid decimal value. Default IsDecimalOptions are force_decimal=False , decimal_digits: '1,' , locale: 'en-US' |
@IsAscii() |
Checks if the string contains ASCII chars only. |
@IsBase32() |
Checks if a string is base32 encoded. |
@IsBase64() |
Checks if a string is base64 encoded. |
@IsIBAN() |
Checks if a string is a IBAN (International Bank Account Number). |
@IsBIC() |
Checks if a string is a BIC (Bank Identification Code) or SWIFT code. |
@IsByteLength(min: number, max?: number) |
Checks if the string’s length (in bytes) falls in a range. |
@IsCreditCard() |
Checks if the string is a credit card. |
@IsCurrency(options?: IsCurrencyOptions) |
Checks if the string is a valid currency amount. |
@IsEthereumAddress() |
Checks if the string is an Ethereum address using basic regex. Does not validate address checksums. |
@IsBtcAddress() |
Checks if the string is a valid BTC address. |
@IsDataURI() |
Checks if the string is a data uri format. |
@IsEmail(options?: IsEmailOptions) |
Checks if the string is an email. |
@IsFQDN(options?: IsFQDNOptions) |
Checks if the string is a fully qualified domain name (e.g. domain.com). |
@IsFullWidth() |
Checks if the string contains any full-width chars. |
@IsHalfWidth() |
Checks if the string contains any half-width chars. |
@IsVariableWidth() |
Checks if the string contains a mixture of full and half-width chars. |
@IsHexColor() |
Checks if the string is a hexadecimal color. |
@IsHSLColor() |
Checks if the string is an HSL color based on CSS Colors Level 4 specification. |
@IsRgbColor(options?: IsRgbOptions) |
Checks if the string is a rgb or rgba color. |
@IsIdentityCard(locale?: string) |
Checks if the string is a valid identity card code. |
@IsPassportNumber(countryCode?: string) |
Checks if the string is a valid passport number relative to a specific country code. |
@IsPostalCode(locale?: string) |
Checks if the string is a postal code. |
@IsHexadecimal() |
Checks if the string is a hexadecimal number. |
@IsOctal() |
Checks if the string is a octal number. |
@IsMACAddress(options?: IsMACAddressOptions) |
Checks if the string is a MAC Address. |
@IsIP(version?: "4"|"6") |
Checks if the string is an IP (version 4 or 6). |
@IsPort() |
Checks if the string is a valid port number. |
@IsISBN(version?: "10"|"13") |
Checks if the string is an ISBN (version 10 or 13). |
@IsEAN() |
Checks if the string is an if the string is an EAN (European Article Number). |
@IsISIN() |
Checks if the string is an ISIN (stock/security identifier). |
@IsISO8601(options?: IsISO8601Options) |
Checks if the string is a valid ISO 8601 date format. Use the option strict = true for additional checks for a valid date. |
@IsJSON() |
Checks if the string is valid JSON. |
@IsJWT() |
Checks if the string is valid JWT. |
@IsObject() |
Checks if the object is valid Object (null, functions, arrays will return false). |
@IsNotEmptyObject() |
Checks if the object is not empty. |
@IsLowercase() |
Checks if the string is lowercase. |
@IsLatLong() |
Checks if the string is a valid latitude-longitude coordinate in the format lat, long. |
@IsLatitude() |
Checks if the string or number is a valid latitude coordinate. |
@IsLongitude() |
Checks if the string or number is a valid longitude coordinate. |
@IsMobilePhone(locale: string) |
Checks if the string is a mobile phone number. |
@IsISO31661Alpha2() |
Checks if the string is a valid ISO 3166-1 alpha-2 officially assigned country code. |
@IsISO31661Alpha3() |
Checks if the string is a valid ISO 3166-1 alpha-3 officially assigned country code. |
@IsLocale() |
Checks if the string is a locale. |
@IsPhoneNumber(region: string) |
Checks if the string is a valid phone numberusing libphonenumber-js. |
@IsMongoId() |
Checks if the string is a valid hex-encoded representation of a MongoDB ObjectId. |
@IsMultibyte() |
Checks if the string contains one or more multibyte chars. |
@IsNumberString(options?: IsNumericOptions) |
Checks if the string is numeric. |
@IsSurrogatePair() |
Checks if the string contains any surrogate pairs chars. |
@IsUrl(options?: IsURLOptions) |
Checks if the string is an url. |
@IsMagnetURI() |
Checks if the string is a magnet uri format. |
@IsUUID(version?: "3"|"4"|"5"|"all") |
Checks if the string is a UUID (version 3, 4, 5 or all ). |
@IsFirebasePushId() |
Checks if the string is a Firebase Push ID |
@IsUppercase() |
Checks if the string is uppercase. |
@Length(min: number, max?: number) |
Checks if the string’s length falls in a range. |
@MinLength(min: number) |
Checks if the string’s length is not less than given number. |
@MaxLength(max: number) |
Checks if the string’s length is not more than given number. |
@Matches(pattern: RegExp, modifiers?: string) |
Checks if string matches the pattern. Either matches(‘foo’, /foo/i) or matches(‘foo’, ‘foo’, ‘i’). |
@IsMilitaryTime() |
Checks if the string is a valid representation of military time in the format HH:MM. |
@IsHash(algorithm: string) |
Checks if the string is a hash The following types are supported:md4 , md5 , sha1 , sha256 , sha384 , sha512 , ripemd128 , ripemd160 , tiger128 , tiger160 , tiger192 , crc32 , crc32b . |
@IsMimeType() |
Checks if the string matches to a valid MIME type format |
@IsSemVer() |
Checks if the string is a Semantic Versioning Specification (SemVer). |
@IsISSN(options?: IsISSNOptions) |
Checks if the string is a ISSN. |
@IsISRC() |
Checks if the string is a ISRC. |
@IsRFC3339() |
Checks if the string is a valid RFC 3339 date. |
Array validation decorators | |
@ArrayContains(values: any[]) |
Checks if array contains all values from the given array of values. |
@ArrayNotContains(values: any[]) |
Checks if array does not contain any of the given values. |
@ArrayNotEmpty() |
Checks if given array is not empty. |
@ArrayMinSize(min: number) |
Checks if the array’s length is greater than or equal to the specified number. |
@ArrayMaxSize(max: number) |
Checks if the array’s length is less or equal to the specified number. |
@ArrayUnique(identifier?: (o) => any) |
Checks if all array’s values are unique. Comparison for objects is reference-based. Optional function can be speciefied which return value will be used for the comparsion. |
Object validation decorators | |
@IsInstance(value: any) |
Checks if the property is an instance of the passed value. |
Other decorators | |
@Allow() |
Prevent stripping off the property when no other constraint is specified for it. |
Defining validation schema without decorators
You can define your validation schemas without decorators:
- you can define it in the separate object
- you can define it in the
.json
file
This feature maybe useful in the cases if:
- are using es5/es6 and don’t have decorators available
- you don’t have a classes, and instead using interfaces
- you don’t want to use model at all
- you want to have a validation schema separate of your model
- you want beautiful json-schema based validation models
- you simply hate decorators
Here is an example of using it:
Create a schema object:
import { ValidationSchema } from "class-validator"; export let UserValidationSchema: ValidationSchema = { // using interface here is not required, its just for type-safety name: "myUserSchema", // this is required, and must be unique properties: { firstName: [ { type: "minLength", // validation type. All validation types are listed in ValidationTypes class. constraints: [2], }, { type: "maxLength", constraints: [20], }, ], lastName: [ { type: "minLength", constraints: [2], }, { type: "maxLength", constraints: [20], }, ], email: [ { type: "isEmail", }, ], }, };
Same schema can be provided in
.json
file, depend on your wish.Register your schema:
import { registerSchema } from "class-validator"; import { UserValidationSchema } from "./UserValidationSchema"; registerSchema(UserValidationSchema); // if schema is in .json file, then you can simply do registerSchema(require("path-to-schema.json"));
Better to put this code in a global place, maybe when you bootstrap your application, for example in
app.ts
.Validate your object using validation schema:
import { validate } from "class-validator"; const user = { firstName: "Johny", secondName: "Cage", email: "johny@cage.com", }; validate("myUserSchema", user).then((errors) => { if (errors.length > 0) { console.log("Validation failed: ", errors); } else { console.log("Validation succeed."); } });
That’s it. Here
"myUserSchema"
is the name of our validation schema.validate
method will perform validation based on this schema
Validating plain objects
Due to nature of the decorators, the validated object has to be instantiated
using new Class()
syntax. If you have your class defined using class-validator
decorators and you want to validate plain JS object (literal object or returned
by JSON.parse), you need to transform it to the class instance via using
class-transformer).
Samples
Take a look on samples in ./sample for more examples of usages.
Extensions
There are several extensions that simplify class-validator integration with other modules:
- class-validator integration with class-transformer
- class-validator-rule
- ngx-dynamic-form-builder
- abarghoud/ngx-reactive-form-class-validator
Release notes
See information about breaking changes and release notes here.