Lightweight Joi-like validation library with NO dependencies targeting web browsers and Node.js. A nice Joi alternative with a similar API.
NOTE: vlid.js
targets language features supported in 90%+ browsers. This means that it does use some more
widely-supported ES6 features, and thus requires a modern-ish browser and/or Node 8+. Most notably, IE11 is
not supported. All versions of Firefox, Safari, Chrome, and Edge released within the past several years are
fully supported.
- Size
- Installation
- Principles
- Usage / vlid API
Bundle size is very important, and a lot of attention is paid to keeping the code lean and small. We try to strike a balance of providing all the core validations and logic that you most commonly need, while making it easy to provide your own custom validation rules for anything else.
Install from NPM or Yarn:
npm install vlid --save
yarn add vlid
Use in your JavaScript:
const v = require('vlid');`
Or with import
:
import v from 'vlid';
vlid.js has a few guiding principles:
- Low bundle size - Since vlid.js targets browsers as well as Node.js, we should aim to ship as few bytes as possible. We transpile as little as possible and only use JavaScript features with 90%+ global browser support. This also means vlid.js does not support IE11 since it would require a significant amount of additional transpilation.
- No dependencies - Your validation library shouldn't have to pull in half of lodash and a bunch of other 3rd-party libraries just to do its job.
- Simple API - Keep the public API clean and simple (easy to learn), without too many ways to do the same thing
- Async validation - Validation is done async so that async rules can be easily added at any time. You can
use
validateSync
if there are no async validation rules (i.e. rules that return aPromise
object). If there are any, thenvalidateSync
with throw an error. All built-in rules can be run either async or sync. - 80 / 20 rule - vlid.js provides all the staple built-ins that you need in 80%+ of most typical apps, and provides easy ways to add your own rules for the 20% or less of cases where you need something custom. This is an explicit trade-off to keep the core size smaller.
Here is a more full-featured example of a possible object schema to validate new blog posts:
const schema = v.object({
tags: v.array().items(v.string()).min(1, 'Must have at least one tag').required(),
title: v.string().required(),
isPublished: v.boolean().required().cast(),
authorId: v.number().cast().default(null),
dtCreated: v.date().iso().required(),
});
const data = req.body; // JSON request data from Express.js
const result = await v.validate(schema, data); // result.isValid = true
The base validation object, can be used to represent any value or as a base for completely custom new validation rules. All other validation rules extend from this.
let result = await v.validate(v.any(), 'whatever you want'); // result.isValid = true
Use allow
to allow specific values, even though they may not pass validation.
A common use is to allow null
for string types:
v.string().allow(null);
You can also pass in an array of values to allow:
v.string().allow([null, undefined, '']);
Values are NOT CAST BY DEFAULT. Casting must be explicitly turned on to allow type coercion.
Use no arguments, or use a boolean true
or false
to turn casting on or off:
v.string().cast(); // Turns casting ON
v.string().cast(true); // Turns casting ON
v.string().cast(false); // Turns casting OFF
Or pass in a function add your own casting method and turn casting ON:
v.string().cast(v => v.trim());
If you use object validation, casting the parent object will automatically also cast all child values:
const schema = v.object({
username: v.string().required(),
email: v.string().email().required(),
password: v.string().required(),
isAdmin: v.boolean().required().default(false),
}).cast(); // Turns casting ON for ALL fields and nested fields in this object
Set and allow a default value if no value is provided.
v.string().required().default('');
NOTE: default()
also calls allow()
under the hood to make sure your provided default value will not
trigger a validation error.
Mark a field as required, meaning it cannot be undefined
, null
, or an empty string ''
. Accepts an
optional custom error message.
v.string().required('Is required');
Use .allow(value)
to re-allow any of those values if needed.
Add a custom validation rule with optional custom error message and options. All of the internal validations
use rule()
to add their validation rules.
Rules must either return boolean true/false is they can be run sync, or a Promise
object if async.
// Built-in
v.number().min(100);
// Custom
v.number().rule(value => value <= 100, 'Must be at least 100');
Can only be used from within a v.object()
based schema. References provided data from the provided path. All
references are evaluated at validation time, AFTER all values have been cast and formatted.
const schema = v.object({
content: v.string().required(),
startDate: v.date().required(),
endDate: v.date().min(v.ref('startDate')).required(), // References 'startDate' data as min.
});
const data = {
content: 'My stuff here!',
startDate: '2019-05-20',
endDate: '2019-05-19',
};
const result = await v.validate(schema, data); // result.isValid = false (endDate not before startDate)
String validator.
Accepts only alphanumeric characters.
Email validator.
Minimum string length.
Maximum string length.
Tests input against supplied Regex pattern.
Ensures input value is a valid URL.
v.number().min(100);
Minimum number that can be input.
Maximum number that can be input.
v.date().min(new Date());
Minimum date that can be input.
Maximum date that can be input.
Ensure provided date is a valid ISO-8601 format (default format that JSON.stringify()
will format dates in).
Boolean validator.
v.boolean().required();
Remember that you must explicitly cast()
if you want vlid to cast string values to boolean.
v.boolean().required().cast(); // NOW casting is ON
Casting accepts all these values:
let trueValues = [1, 'true', 't', 'on', 'yes'];
let falseValues = [0, 'false', 'f', 'off', 'no', ''];
Array validator.
Apply a validation rule to all items in an array.
const schema = v.object({
todos: v.array().items(
v.object({
title: v.string().required(),
isDone: v.boolean().required(),
});
),
});
const data = {
todos: [
{
title: 'Task 1',
isDone: false,
},
{
title: 'Task 2',
isDone: true,
},
]
};
const result = await v.validate(schema, data); // result.isValid = true
Minimum number of items that must be present in the array
const result = await v.validate(v.array().min(1), []); // result.isValid = false (min. 1 items required)
Maximum number of items that can be present in the array
const result = await v.validate(v.array().max(2), [1, 2, 3]); // result.isValid = false (max. 2 items in array)
Object schema validation. Specify keys with other validation rules as the values.
const schema = v.object({
title: v.string().required(),
isDone: v.boolean().required(),
});
const data = {
title: 'My todo task',
isDone: false,
};
const result = await v.validate(schema, data); // result.isValid = true
Each call to either validate
or validateSync
will resolve or return a validation result object.
{
isValid: Boolean,
errors: [], // Array of ValidationError objects
value: Mixed, // whatever data was passed in, with casting applied
results: [], // Array of failed validation results
}
Each validation error will return a ValidationError
object (extended from the built-in Error
object) with
the following keys:
{
message: String,
path: String | null, // Path to nested key if in object validaiton, or null
value: Mixed, // whatever data was passed in, with casting applied
}