vlucas / vlid

Lightweight validation library with NO dependencies. A nice Joi alternative with a similar API.
BSD 3-Clause "New" or "Revised" License
65 stars 6 forks source link

vlid.js

NPM Build
Status Min Size Minzipped Size

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.

Table of Contents

Size

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.

Installation

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';

Principles

vlid.js has a few guiding principles:

Usage / vlid API

Example Object Schema

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

vlid.any()

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

any.allow(values: Any | [ Any ])

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, '']);

any.cast(Boolean | Function)

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

any.default(value: any)

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.

any.required([err: String])

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.

any.rule(rule: Function [, message: String | Function, opts: Object])

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');

vlid.ref(field: String)

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)

vlid.string()

String validator.

string.alphanum([err: String | Function])

Accepts only alphanumeric characters.

string.email([err: String | Function])

Email validator.

string.min(min: Number [, err: String | Function])

Minimum string length.

string.max(max: Number [, err: String | Function])

Maximum string length.

string.regex(pattern: Regex [, err: String | Function])

Tests input against supplied Regex pattern.

string.url([err: String | Function])

Ensures input value is a valid URL.

vlid.number()

v.number().min(100);

number.min(min: Number [, err: String | Function])

Minimum number that can be input.

number.max(max: Number [, err: String | Function])

Maximum number that can be input.

vlid.date()

v.date().min(new Date());

date.min(min: Date [, err: String | Function])

Minimum date that can be input.

date.max(max: Date [, err: String | Function])

Maximum date that can be input.

date.iso([err: String | Function])

Ensure provided date is a valid ISO-8601 format (default format that JSON.stringify() will format dates in).

vlid.boolean()

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', ''];

vlid.array()

Array validator.

array.items(item: vlid.any)

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

array.min(min: Number [, err: String | Function])

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)

array.max(max: Number [, err: String | Function])

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)

vlid.object(data: Object)

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

Validation Result Object

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
}

vlid.ValidationError

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
}