
Company News
/Security News
Socket Selected for OpenAI's Cybersecurity Grant Program
Socket is an initial recipient of OpenAI's Cybersecurity Grant Program, which commits $10M in API credits to defenders securing open source software.
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 polyfill 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: { // you can omit check that "author" value is object, it will be done by validy internally
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 many 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 requestsYou 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: {
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: {
name: {
$validate: {
required: true,
string: true
}
}
}
};
validy(book, schema)
.then(errors => {
console.log(errors);
})
errors with flat structure:
{
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
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 21 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.

Company News
/Security News
Socket is an initial recipient of OpenAI's Cybersecurity Grant Program, which commits $10M in API credits to defenders securing open source software.

Security News
Socket CEO Feross Aboukhadijeh joins 10 Minutes or Less, a podcast by Ali Rohde, to discuss the recent surge in open source supply chain attacks.

Research
/Security News
Campaign of 108 extensions harvests identities, steals sessions, and adds backdoors to browsers, all tied to the same C2 infrastructure.