valerie v0.8.0
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); // undefinedSimple 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 (RegExpor/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