README
valerie
Simple javascript object validator
The goal of this project is to provide a simple, intuitive, extensible, independent, and isomorphic javascript object validation library.
What makes Valerie any different from other validation libs?
- No dependencies
- Very lightweight
- Easy to use both server- and browser-side
- Validation rules are standard functions (keep it simple)
- Supports async/promise-based validation rules
- Custom rules are super easy to make
- Custom error messages for all built-in rules
- Source uses ES6/7 features (transpiled to ES5 for browsers)
- Full tests and linting
Usage
Import the function and built-in rules
import createValidator from 'valerie';
import { number, oneOf } from 'valerie/rules';
import { range, required } from 'valerie/rules/extended';
Compose the validation schema for our object
const schema = {
id: [required('id is required'), number('id must be a number')],
name: {
first: required('first name is required'),
last: required('last name is required')
},
age: range(0, 123, 'must be a normal human age'),
favoriteColor: oneOf(['blue', 'red', 'yellow'], 'must be a primary color')
};
Create the object validator, which is a function taking a single object parameter, and returns a Promise
which resolves to an array containing errors. The array will be empty if there are no errors.
const validate = createValidator(schema);
Validate
const input = {
id: 10,
name: {
first: 'foo'
},
age: 99,
favoriteColor: 'potato'
};
// ES7
const errors = await validate(input);
// ES6
validate(input).then(errors => {
// tell the user about the errors!
})
// ES5
validate(input).then(function(errors) {
// tell the user about the errors!
});
/*
[
{
property: 'name.last',
message: 'last name is required'
},
{
property: 'favoriteColor',
message: 'must be a primary color'
}
]
*/
// or just get the first error
const errors = await validate(input, 1);
/*
[
{
property: 'name.last',
message: 'last name is required'
}
]
*/
Rules
Validation rules are just simple functions that take a single input, the value to validate, and return undefined
if valid, or an error message if not.
The built-in rule objects exported from valerie/rules
are functions that take a set of options and return the rule function itself.
Example:
import { is } from 'valerie/rules';
const isTrue = is(true, 'value must be true');
isTrue(false); // 'value must be true';
isTrue(true); // undefined
Simple rules
The simple rules are largely based on the fundamental javascript operations.
Equality rules
is(target, [message = "is"])
Tests if a value is strictly equal (===
) to a target value.
target
: what the validated value should equalmessage
: optional custom error message
const isBar = equalTo('bar', 'foo must be bar');
const validate = createValidator({ foo: isBar });
const errors = await validate({ foo: 'bar' });
equalTo(target, [message = "equalTo"])
Tests if a value is loosely equal (==
) to a target value.
target
: what the validated value should equalmessage
: optional custom error message
const isBar = equalTo('bar', 'foo must be bar');
const validate = createValidator({ foo: isBar });
const errors = await validate({ foo: new String('bar') });
Numeric rules
number([message = "number"])
Tests if a value is a number (!isNaN
).
message
: optional custom error message
const isNumber = number(foo 'must be a number');
const validate = createValidator({ foo: isNumber });
const errors = await validate({ foo: Math.PI });
greaterThan(target, [message = "greaterThan"])
Tests if a value is greater than (>
) a target value.
target
: what the validated value should be greater thanmessage
: optional custom error message
const isPositive = greaterThan(0, 'foo must be positive');
const validate = createValidator({ foo: isPositive });
const errors = await validate({ foo: 1 });
lessThan(target, [message = "lessThan"])
Tests if a value is less than (<
) a target value.
target
: what the validated value should be less thanmessage
: optional custom error message
const isNegative = lessThan(0, 'foo must be negative');
const validate = createValidator({ foo: isNegative });
const errors = await validate({ foo: -1 });
Array rules
array([message = "array"])
Tests if a value is an array (Array.isArray
).
message
: optional custom error message
const isArray = array('foo must be an array');
const validate = createValidator({ foo: isArray });
const errors = await validate({ foo: ['bar', 'baz'] });
contains(item, [message = "contains"])
Tests if a value contains (indexOf
) an item.
item
: item that value should containmessage
: optional custom error message
const containsBar = contains('bar', 'foo must contain bar');
const validate = createValidator({ foo: containsBar });
const errors = await validate({ foo: ['bar'] });
oneOf(options, [message = "oneOf"])
Tests if a value is equal to (===
) an item in an Array
.
options
: array of items to check againstmessage
: optional custom error message
const isPrimaryColor = oneOf(['red', 'blue', 'yellow'], 'foo must be a primary color');
const validate = createValidator({ foo: isPrimaryColor });
const errors = await validate({ foo: 'blue' });
Type rules
isInstanceOf(type, [message = "isInstanceOf"])
Tests if a value is an instance of a class (instanceof
).
type
: what the validated value should be an instance ofmessage
: optional custom error message
const isBar = isInstanceOf(Bar, 'foo must be bar');
const validate = createValidator({ foo: isBar });
const errors = await validate({ foo: new Bar() });
isTypeOf(type, [message = "isTypeOf"])
Tests if a value is of a given type (typeof
).
type
: what the validated value should be a type ofmessage
: optional custom error message
const isString = isTypeOf(Bar, 'foo must be a string');
const validate = createValidator({ foo: isString });
const errors = await validate({ foo: 'bar' });
hasProperty(property, [message = "hasProperty"])
Tests if an object has a child property (hasOwnProperty
).
property
: name of the propertymessage
: optional custom error message
const hasBar = hasProperty('bar', 'foo must have bar property');
const validate = createValidator({ foo: hasBar });
const errors = await validate({
foo: {
bar: true
}
});
Logical operators
These rules take one or more rules as input and return new, compoud rule.
async and(rules, [message = "and"])
Tests if a value is valid against all rules within an Array
.
rules
: array of rules to validate againstmessage
: optional custom error message
const isArrayContainingBar = and([array(), contains('bar')], 'foo must be an array containing "bar"');
const validate = createValidator({ foo: isArrayContainingBar });
const errors = await validate({ foo: ['bar', 'baz', 'qux'] );
async or(rules, [message = "or"])
Tests if a value is is valid against at least one rule within an Array
of rules.
rules
: array of rules to validate againstmessage
: optional custom error message
const isNumberOrX = or([number(), equals('x')], 'foo must be a number or the letter "x"');
const validate = createValidator({ foo: isNumberOrX });
const errors = await validate({ foo: 'x' );
async not(rule, [message = "not"])
Tests if a value is not valid against rule.
rule
: rule to validate againstmessage
: optional custom error message
const isNotNumber = not(number(), 'foo must not be a number');
const validate = createValidator({ foo: isNotNumber });
const errors = await validate({ foo: 'bar' );
Other rules
regex(pattern, [message = "regex"])
Tests if a value matches a regex (.match
)
pattern
: regexp (RegExp
or/pattern/
)message
: optional custom error message
const isEMail = regex(/^\S+@\S+$/, 'foo must be an email address');
const validate = createValidator({ foo: isEMail });
const errors = await validate({ foo: 'bar@baz.com' });
Extended Rules
Extended rules use the simple rules to form more complex logic
async range(min, max, [message = "range"])
Tests if a value is between two values. Generally want to use with number
. Depends on and
, or
, greaterThan
, lessThan
, and equalTo
.
min
: minimum value, inclusivemax
: maximum value, inclusivemessage
: optional custom error message
const isNumber = number('foo must be a number');
const isHumanAge = range(0, 123, 'foo must be a human age');
const validate = createValidator({ foo: [isNumber, isHumanAge] });
const errors = await validate({ foo: 100 });
async required([message = "required"])
Tests if a value exists (not undefined
, not an empty string, not an empty array). Depends on and
, defined
, and notEmpty
.
message
: optional custom error message
const isRequired = required('foo is required');
const validate = createValidator({ foo: isRequired });
const errors = await validate({ foo: 'bar' );
Custom Rules
Custom rules are easy to implement. They're simply functions that take a single value and return an error message for failure, and undefined
for passing.
const isEven = value => {
if (value % 2 !== 0) return 'value must be even';
};
isEven(4); // undefined
isEven(5); // value must be even
const validate = createValidator({
foo: isEven
});
const errors = await validate({
foo: 5
});
/*
[
{
property: 'foo',
message: 'value must be even'
}
]
*/
Built-in rules use currying to allow options and custom error messages to be set. You can follow this technique like so:
const divisibleBy = (divisor, message = 'divisibleBy') => {
return value => {
if (value % divisor !== 0) return message;
}
};
const isDivisibleBy3 = divisibleBy(3, 'value must divisibly by 3');
Check out the other rules for more examples.
TODO:
- Rules
email
- Examples of client- and server-side usage
- Example of promise rule
- Compare to other libs
- https://github.com/hapijs/joi (large)
- https://github.com/molnarg/js-schema (no custom messages)
- https://github.com/ansman/validate.js