Allows use of decorator and non-decorator based validation. Internally uses [validator.js][1] to perform validation. Class-validator works on both browser and node.js platforms.
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-validatorto function properly.
Create your class and put some validation decorators on the properties you want to validate:
import {
validate,
validateOrReject,
Contains,
IsInt,
Length,
IsEmail,
IsFQDN,
IsDate,
Min,
Max,
} 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);
}
}
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;
}
IMPORTANT The
forbidUnknownValuesvalue is set totrueby default and it is highly advised to keep the default. Setting it tofalsewill result unknown objects passing the validation!
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.
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 { MinLength, MaxLength } 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 typeExample of usage:
import { MinLength, MaxLength } from 'class-validator';
export class Post {
@MinLength(10, {
// here, $constraint1 will be replaced with "10", and $value with actual supplied value
message: 'Title is too short. Minimal length is $constraint1 characters, but actual is $value',
})
@MaxLength(50, {
// here, $constraint1 will be replaced with "50", and $value with actual supplied value
message: 'Title is too long. Maximal length is $constraint1 characters, but actual is $value',
})
title: string;
}
Also you can provide a function, that returns a message. This allows you to create more granular messages:
import { MinLength, MaxLength, 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 validatedIf 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 { MinLength, MaxLength } from 'class-validator';
export class Post {
@MaxLength(20, {
each: true,
})
tags: string[];
}
This will validate each item in post.tags array.
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 { MinLength, MaxLength } from 'class-validator';
export class Post {
@MaxLength(20, {
each: true,
})
tags: Set<string>;
}
This will validate each item in post.tags set.
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 { MinLength, MaxLength } from 'class-validator';
export class Post {
@MaxLength(20, {
each: true,
})
tags: Map<string, string>;
}
This will validate each item in post.tags map.
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[][];
}
If your object contains property with Promise-returned value that should be validated, then you need to use the @ValidatePromise() decorator:
import { ValidatePromise, Min } 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>;
}
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 from both its own class 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, password, name and welcome properties
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 { ValidateIf, IsNotEmpty } 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.
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 });
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
});
Sometimes you may want to skip validation of the properties tha
$ claude mcp add class-validator \
-- python -m otcore.mcp_server <graph>