
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
Declarative validation with async validators support. If you also want to work with filters and default values, take a look at transformer-chain
Note: This module works in browsers and Node.js >= 4.0. Use Object.assign and Promise polyfills for Internet Explorer
Try demo on RunKit.
npm install validy
const validy = require('validy');
<script src="node_modules/validy/dist/validy.js">
or minified version
<script src="node_modules/validy/dist/validy.min.js">
You can use the module with AMD/CommonJS or just use window.validy.
validy allows you to validate flat and nested objects using collection of default validators and your own validators.
Validators can be asynchronous, you can do DB calls for example and so on.
To validate object you should define schema. It's simple object with your constraints:
const book = { // object to validate
name: 'The Adventures of Tom Sawyer',
author: {
name: 'Mark Twain'
},
reviews: [
{
author: 'Leo Tolstoy',
text: 'Great novel'
},
{
author: 'Fyodor Dostoyevsky',
text: 'Very interesting'
}
]
};
const schema = {
name: {
$validate: {
required: true,
string: true
}
},
author: {
$validate: { // you can omit check that "author" value is object, it will be done internally
required: true
},
name: {
$validate: {
required: true,
string: true
}
}
},
reviews: [{ // define schema for array items
author: {
$validate: {
required: true,
string: true
}
},
text: {
$validate: {
required: true,
string: true
}
}
}]
};
validy(book, schema)
.then(errors => {
if (errors) {
// you have validation errors ("errors" is plain object)
} else {
// no errors ("errors" is undefined)
}
})
.catch(err => {
// application error (something went wrong)
});
// async/await example
async function example() {
try {
const errors = await validy(book, schema);
if (errors) {
// you have validation errors ("errors" is plain object)
} else {
// no errors ("errors" is undefined)
}
} catch(err) {
// application error (something went wrong)
}
}
object (Object) - Object to validateschema (Object) - Schema which defines how to validate object[options] (Object) - Validation options
[format=flat] (string) - Format of object with validation errors (flat, nested)[reject=false] (boolean) - Should return fulfilled promise with errors (by default) or rejected with ValidationError?(Promise) - Result of validation. Promise is returned even for synchronous only validation
By default validy uses collection of simple and useful validators (common-validators module).
Note:
The basic principle of built-in validators is that most of them (except required, notEmpty and type validators object, array, ...) consider empty values as valid values.
Empty values are:
undefinednullNaN''' ' (whitespace only string)[]{}Also they convert passed value to expected type. For example, max validator which checks that value is not greater than some limit will try to convert passed value to number (Number(value)).
All non-convertible values will be treated as NaN and validator will return validation error.
Some of built-in validators:
undefined, null, NaN, empty or whitespace only string, empty array or objectrequired but undefined is valid value. It is useful for PATCH requestsundefined is valid valueYou can add your own validator:
validy.validators.add('greaterThan', function(value, options) {
// validator implementation
});
// or
validy.validators.add({ // this way you can add several validators at once
greaterThan: function(value, options) {
// validator implementation
},
anotherValidator: function(value, options) {
// validator implementation
}
});
Although in most cases you will have only two parameters in your own validators (value and options), some situations will require a bit knowledgeable validator.
So, full signature of validator is:
validator(value, options, object, fullObject, path)
value (any) - Validated valueoptions (Object) - Validator optionsobject (Object) - Object whose property is validated at the momentfullObject (Object) - The whole validated object (object which was initially passed to validy)path (string[]) - Path to propertySo imagine you wrote validateSomething validator:
const book = {
name: 'The Adventures of Tom Sawyer',
author: {
name: 'Mark Twain'
}
};
const schema = {
name: {
$validate: {
required: true,
string: true
}
},
author: {
$validate: {
required: true
},
name: {
$validate: {
required: true,
string: true,
validateSomething: 'someArgument' // <--- and you want to use it here
}
}
}
};
validateSomething validator will be called with the following arguments:
Value of author.name property.
'Mark Twain'
When you use non-object value as validator options it will be wrapped in object with arg property.
{
arg: 'someArgument'
}
Object with name property (author object).
{
name: 'Mark Twain'
}
The whole validated object (book object).
{
name: 'The Adventures of Tom Sawyer',
author: {
name: 'Mark Twain'
}
}
['author', 'name']
Example:
validy.validators.add('russianLettersOnly', function(value) {
// it's ok to consider empty value as valid value
// use "required" validator when this value must not be empty
if (value === '') {
// if value is valid just return nothing or falsy value
return;
}
if (typeof value !== 'string' || !/^[а-яё]+$/i.test(value)) {
// when value is invalid, return string with error
return 'must contain only Russian letters';
}
});
// or
validy.validators.add({ // this way you can add several validators at once
russianLettersOnly: function(value) { /**/ },
anotherValidator: function(value) { /**/ }
});
And then just use it as any other validator:
{
name: {
$validate: {
// validator will be called only if its config is not equal to false/null/undefined
russianLettersOnly: true
}
}
}
Almost the same as synchronous validator, just return fulfilled promise:
validy.validators.add({
/**
* Check using mongoose model that value exists in mongodb
*
* @param {string} value
* @param {Object} options
* @param {Object} options.model - Mongoose model
* @param {string} [options.field] - Which field to use for search
*
* @returns {Promise}
*/
exists: function(value, options) {
const errorMessage = 'does not exist';
if (value === '') {
return Promise.resolve();
}
if (typeof value !== 'string') {
return Promise.resolve(errorMessage);
}
const model = options.model;
const field = options.field || '_id';
return model.count({ [field]: value })
.then(count => {
if (!count) {
// if value is invalid, return fulfilled promise with validation error
return Promise.resolve(errorMessage);
}
});
}
});
If there are no validation errors validy returns undefined as fulfillment value:
validy(book, schema)
.then(errors => {
console.log(errors); // undefined
})
If you have validation errors:
const book = {
name: '', // empty
author: {
name: 123456789 // not string
}
};
const schema = {
name: {
$validate: {
required: true,
string: true
}
},
author: {
$validate: {
required: true
},
name: {
$validate: {
required: true,
string: true
}
}
}
};
validy(book, schema)
.then(errors => {
console.log(errors);
})
errors has flat structure by default:
{
name: [{ // errors are always placed in array
error: 'required', // validator name
message: 'Is required' // error message
}],
'author.name': [{
error: 'string',
message: 'Must be a string'
}]
}
But you can use nested structure:
validy(book, schema, { format: 'nested' })
.then(errors => {
console.log(errors);
})
errors with nested structure:
{
name: [{
error: 'required',
message: 'Is required'
}],
author: {
name: [{
error: 'string',
message: 'Must be a string'
}]
}
}
By default validy returns fulfilled promise when validated object is not valid.
If for some reasons you want to use rejected promise with validation error instead of fulfilled promise, specify reject option:
validy(object, schema, { reject: true })
.then(() => {
// no errors, everything is valid
})
.catch(err => {
if (err instanceof validy.ValidationError) {
// err.errors contains validation errors
} else {
// application error (something went wrong)
}
});
Sometimes you may need a way to validate some property differently depending on specific conditions. Example with order of various products:
const order = {
products: [
{
type: 'book',
name: 'The Adventures of Tom Sawyer',
count: 1
},
{
type: 'sugar',
weight: 3000
}
]
};
const productsSchemas = {
book: {
name: {
$validate: {
required: true,
string: true
}
},
count: {
$validate: {
required: true,
integer: true,
min: 1
}
}
},
sugar: {
weight: {
$validate: {
required: true,
integer: true,
min: 1000
}
}
}
};
const schema = {
products: [(product/*, products, order, pathToItem*/) => {
const productSchema = productsSchemas[product.type];
return Object.assign({}, productSchema, {
type: {
$validate: {
required: true,
string: true,
inclusion: Object.keys(productsSchemas)
}
}
});
}]
};
// or you can do like this (products is marked as required)
const alternativeSchema = {
products: {
$validate: { // validate also "products" before items validation
required: true,
array: true
},
$items: function(product/*, products, order, pathToItem*/) {
const productSchema = productsSchemas[product.type] || {};
return Object.assign({}, productSchema, {
type: {
$validate: {
required: true,
string: true,
inclusion: Object.keys(productsSchemas)
}
}
});
}
}
};
You can do similar things with $validate and specific validator:
const bookSchema = {
author: {
name: {
$validate: function(name, author, book, pathToName) {
// implement your custom logic
// validation will only run if you return object
// so you can return null for example to skip validation
return {
required: function(name, author, book, pathToName) {
// implement your custom logic
// return undefined, null or false if you want skip validation
},
string: true
};
}
}
}
};
npm install
npm run build
npm install
npm test
FAQs
Declarative validation with async validators support
The npm package validy receives a total of 16 weekly downloads. As such, validy popularity was classified as not popular.
We found that validy demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.