Usage
Basic validation
import LIVR from 'livr';
const validator = new LIVR.Validator({
name: 'required',
email: ['required', 'email'],
gender: { one_of: ['male', 'female'] },
phone: { max_length: 10 },
password: ['required', { min_length: 10 }],
password2: { equal_to_field: 'password' },
});
const validData = validator.validate(userData);
if (validData) {
saveUser(validData);
} else {
console.log(validator.getErrors());
}Construct a validator once and use it for many inputs: rules are compiled on the first validation, and every later validate() call only runs them. Call prepare() to compile them in advance.
Errors
Errors are codes, not messages, and they mirror the structure of the input:
{
email: 'WRONG_EMAIL',
password: 'TOO_SHORT',
address: { zip: 'NOT_POSITIVE_INTEGER' },
tags: [null, 'TOO_LONG'],
}All errors are returned at once. Translate the codes in your UI and attach them to form fields by path. The error codes are the same in every LIVR implementation.
Modifiers
Modifiers change the output while it is validated:
const validator = new LIVR.Validator({
email: ['required', 'trim', 'email', 'to_lc'], // trim, validate, lowercase
age: ['positive_integer', { default: 18 }], // a default for an empty value
});Available modifiers: trim, to_lc, to_uc, default, remove, leave_only. Numeric rules also convert valid strings to numbers, so '42' from a form becomes 42 in the output.
Auto-trim
Trim every string before validation, for one validator or for all of them:
const validator = new LIVR.Validator(schema, { autoTrim: true });
LIVR.Validator.defaultAutoTrim(true); // all validators created after this callAsync validation
For rules that query a database or call an API:
import LIVR from 'livr/async';
const validator = new LIVR.AsyncValidator({
username: ['required', 'unique_username'], // a custom async rule
email: ['required', 'email'],
});
try {
const validData = await validator.validate(userData);
saveUser(validData);
} catch (errors) {
console.log(errors);
}Differences from the sync validator:
- Import from
'livr/async'and useAsyncValidator validate()returns a promise, and rejects with the errors object (there is nogetErrors())- Fields are validated in parallel, the rules of one field run one after another
- Sync rules stay sync: a field waits for a promise only when one of its rules returns one
Smaller bundles
livr registers all built-in rules. To ship only the rules you use, start from the bare validator:
import Validator from 'livr/lib/Validator';
import required from 'livr/lib/rules/common/required';
import email from 'livr/lib/rules/special/email';
import min_length from 'livr/lib/rules/string/min_length';
import equal_to_field from 'livr/lib/rules/special/equal_to_field';
Validator.registerDefaultRules({ required, email, min_length, equal_to_field });
const validator = new Validator({
email: ['required', 'email'],
password: ['required', { min_length: 8 }],
password2: { equal_to_field: 'password' },
});The validator core is about 2 KB min+gzip. See Zero dependencies for the sizes.
Performance tips
// Good: create once, validate many times
const validator = new LIVR.Validator(schema);
for (const item of items) {
const result = validator.validate(item);
}
// Slower: a new validator for every item
for (const item of items) {
const validator = new LIVR.Validator(schema);
const result = validator.validate(item);
}Creating validators is cheap too: LIVR is the fastest in the benchmark that creates a validator for every call. Still, a reused validator is 2–3 times faster. See Performance.