isvalid-jollof v1.1.10
isvalid
isvalid is an asynchronous node.js library for validating and error correcting JSON. In contrary to JSON Schema it uses a very simple schema model - inspired by the Mongoose schemas.
Table of Content
- How to Use
- Example
- As Connect or Express Middleware * Example
- How it Works
- Errors SchemaError ValidationError
- A Note on the Examples in this Document
- Supported Types
Validators Available to All Types
defaultStatic Values Functions Asynchronous Functions Synchronous FunctionsrequiredImplicitly RequiredallowNullerrorsType Specific Validators Validators Common toObjectandArrayschemaObjectValidatorsunknownKeysallowUnknownKeysdeprecatedArrayValidatorslenuniqueautowrapStringValidatorstrimmatchenumNumberValidatorsrange customAsynchronous Example The Callback Function Synchronous Example Options with Custom Validators * Multiple Custom Validators- Type Shortcuts Object Shortcuts Array Shortcuts * Other Shortcuts
- Automatic Type Conversion Numbers Booleans * Dates
- Changelog
- License
How to Use
isvalid uses a simple schema modal to specify how the data should be formatted. It supports generic validators for all types and type specific validators.
Usage: isvalid(dataToValidate, validationSchema, callback)
Example
Here's a simple example on how to use the validator.
var isvalid = require('isvalid');
isvalid(inputData, {
'user': { type: String, required: true },
'pass': { type: String, required: true }
}, function(err, validData) {
/*
err: Error describing invalid data.
validData: The validated data.
*/
});As Connect or Express Middleware
Connect and Express middleware is build in.
Usage: isvalid.validate.body(schema) validates req.body.
Usage: isvalid.validate.query(schema) validates req.query.
Usage: isvalid.validate.param(schema) validates req.param.
Example
var validate = require('isvalid').validate;
app.param('myparam', validate.param(Number));
app.post('/mypath/:myparam',
validate.query({
'filter': String
}),
validate.body({
'mykey': { type: String, required: true }
}),
function(req, res) {
// req.param.myparam, req.body and req.query are now validated.
// - any default values - or type conversion - has been applied.
}
);Remark: If validation fails
isvalidwill unset the validated content (eg.req.bodywill becomenullif body validation fails). This is to ensure that routes does not get called with invalid data, in case a validation error isn't correctly handled.
How it Works
isvalid is a comprehensive validation library - build for ease of use. Both as Connect or Express middleware - where it comes in really handy - or as stand alone.
A Note on the Examples in this Document
In order to be a complete schema, schemas must have at least the type and/or custom validator. But, as you will notice throughout this document, many of the examples lots of validators with neither. Instead they just use the type shortcuts.
This is because isvalid supports type shortcuts for all its supported types, and you are - if you want to help yourself - going to use them a lot. You can read more about type shortcuts in the designated section at the near-bottom of this document.
Errors
Errors in function parameters or schemas are thrown - as they are developer errors - and validation errors are passed to the callback.
- Wrong parameters throw
Errorinstances. - Schema errors throw
SchemaErrorinstances. - Validation errors are passed to the callback as
ValidationErrorinstances.
SchemaError
The SchemaError contains the schema property which contains the actual schema in which there is an error. It also has the message property with the description of the schema error.
ValidationError
The ValidationError contains three properties besides the message.
- `keyPath` is an array indicating the key path in the data where the error occured.
- `schema` is the schema that failed to validate.
- `validator` is the name of the validator that failed.Supported Types
These types are supported by the validator:
ObjectArrayStringNumberBooleanDate- and
customvalidators.
There are some validators that are common to all types, and some types have specific validators.
You specify the type like this:
{ type: String }or if type is your only validator, you can also do this:
StringIn the above example the input must be of type String.
All schemas must have the type specified and/or have a custom validator through a custom function - more about custom validators in it's designated section below.
Validators Available to All Types
These validators are supported by all types.
default
Defaults data to specific value if data is not present in input. It takes a specific value or it can call a custom function to retrieve the value.
Type: Any value or a function.
Static Values
Example:
{
"email": { type: String, default: "email@not.set" }
}This tells the validator, that an email key is expected, and if it is not found, it should just assign it with whatever is specified as default.
This works with all supported types - below with a boolean type:
{
"receive-newsletter": { type: Boolean, default: false }
}Now if the receive-newsletter field is absent in the data the validator will default it to false.
Functions
default also supports functions.
Asynchronous Functions
An asynchronous default function works using a callback.
{
"created": {
type: String,
default: function(fn) {
fn('This is my default value');
}
}
}Synchronous Functions
A synchronous default function works the same way, except you leave out the callback - and return the value instead.
{
"created": {
type: String,
default: function() {
return 'This is my default value';
}
}
}required
Values: true, false or 'implicit'.
required works a little like default. Except if the value is absent a validation error is send to the callback.
{ type: String, required: true }The above specifies that the data must be present and be of type String.
Implicitly Required
Example:
{
type: Object,
required: 'implicit',
schema: {
'user': { type: String, required: true }
'email': String
}
}The above example is to illustrate what 'implicit' does. Because the key user in the subschema is required, the parent object inherently also becomes required. If none of the subschemas are required, the parent object is also not required.
This enables you to specify that some portion of the data is optional, but if it is present - it's content should have some required fields.
See the example below.
{
type: Object,
required: false,
schema: {
'user': { type: String, required: true }
'email': String
}
}In the above example the data will validate if the object is not present the input, even though user is required - because the parent object is explicitly not required. If the object - on the other hand - is present it must have the user key and it must be of type String.
Remark: If
requiredis not specified, thenObjectandArraytypes are by default'implicit'. All other types are by default non-required. Alsorequiredis ignored ifdefaultis specified.
allowNull
Type: Boolean
This validator allows for null-values to pass through - even if the input is required.
{ type: String, required: true, allowNull: true }In the above example input must be of type String, it is required, but null is allowed.
Remark: By default
nullis not allowed.
errors
Type: Object
Errors are really not a validator - it allows you to customize the errors emitted by the validators. All validators have default error messages, but these can be customized in order to make user and context friendly error messages.
An example below.
{
'username': {
type: String,
required: true,
match: /^[^ @]+$/,
errors: {
type: 'Username must be a string.',
required: 'Username is required.',
match: 'Username cannot contain any white spaces.'
}
}
}Now in case any of the validators fail, they will emit the error message specified - instead of the default built-in error message. The message property of ValidationError will contain the message on validation failure.
Type Specific Validators
Validators Common to Object and Array
schema
The schema validator of Object and Array types specifies the schema of their children. Objects have keys and values - arrays only have a single schema.
An example below of an object schema with a user key.
{
type: Object,
schema: {
'username': String
}
}And an example below of an array of strings.
{
type: Array,
schema: String
}Object Validators
The Object type has only one specific validator - besides the common validators (it has two, though, but the one is deprecated in favour of the other.)
unknownKeys
Type String of values: 'allow', 'deny' or 'remove'
This validator is used to control how unknown keys in objects are handled.
The validator has three options:
allowPass any unknown key onto the validated object.denyCome back with error if object has unknown key.removeRemove the unknown key from the validated object.
An example below.
{
type: Object,
unknownKeys: 'remove',
schema: {
awesome: Boolean
}
}In the above example, if you validated the following object, the why key would be absent from the validated data.
{
awesome: true,
why: 'It is!'
}Default is
deny.
allowUnknownKeys deprecated
Type: Boolean
This validator has been deprecated in favour of unknownKeys, and will be removed in the next major version. Please update your schemas.
Array Validators
The Array type has two specific validator - besides the common validators.
len
Type: Number or String
This ensures that an array has a specific number of items. This can be either a number or a range. The validator sends an error to the callback if the array length is outside the bounds of the specified range(s).
An array that should have exactly 2 items:
{
type: Array,
len: 2,
schema: { … }
}An array that should have at least 2 items:
{
type: Array,
len: '2-',
schema: { … }
}An array that should have a maximum of 2 items:
{
type: Array,
len: '-2',
schema: { … }
}An array that should have at least 2 items and a maximum of 5 items:
{
type: Array,
len: '2-5',
schema: { … }
}An array that should have at two or less items, exactly 5 items or 8 or more items:
{
type: Array,
len: '-2,5,8-',
schema: { … }
}unique
Type: Boolean
This ensures that all elements in the array are unique - basically ensuring the array is a set. If two or more elements are the same, the validator sends an error to the callback.
Example:
{
type: Array,
unique: true,
schema: { … }
}The
uniquevalidator does a deep comparison on objects and arrays.
autowrap
Type: Boolean or String of value transparent.
If the provided data is not an array - but it matches the subschema - this will wrap the data in an array before actual validation.
Example:
{
type: Array,
autowrap: true,
schema: { … }
}If autowrap is set to true and autowrap fails (the subschema cannot validate the data), then the type validator will emit a 'Must be of type Array.' error. If, though, autowrap is set to transparent it will emit eventual errors as the failing subschema validation. This can be useful if you want to hide the fact, that the data can be wrapped in an array.
Default is
false.
String Validators
The String type has three specific validator - besides the common validators.
trim
Type: Boolean
This does not do any actual validation. Instead it trims the input in both ends - before any other validators are checked. Use this if you want to remove any unforeseen white spaces added by the user.
match
Type: RegExp
This ensures that a string can be matched against a regular expression. The validator sends an error to the callback if the string does not match the pattern.
This example shows a string that must contain a string of at least one character of latin letters or decimal numbers:
{ type: String, match: /^[a-zA-Z0-9]+$/ }enum
Type: Array
This is complimentary to match - as this could easily be achieved with match - but it is simpler and easier to read. The validator ensures that the string can be matched against a set of values. If it does not, it sends an error to the callback.
{ type: String, enum: ['none','some','all'] }In the above example the string can only have the values of none, some or all.
Remark that
enumis case sensitive.
Number Validators
The Number type has only one specific validator - besides the common validators.
range
Type: Numberor String
This ensures that the number is within a certain range. If not the validator sends an error to the callback.
The
rangevalidator uses the same formatting as the array'slenvalidator described above.
custom
Custom validators are for usage when the possibilities of the validation schema falls short. Custom validators basically outsources validation to a custom function.
Custom validators are specified by the custom field of a schema.
typebecomes optional when usingcustom. You can completely leave out any validation and just use acustomvalidator.
Asynchronous Example
{
type: Object,
schema: {
'low': Number,
'high': Number
}
'custom': function(data, schema, fn) {
if (data.low > data.high) {
return fn(new Error('low must be lower than high'));
}
fn(null, data);
}
}In the above example we have specified an object with two keys - low and high. The validator will first make sure, that the object validates to the schema. If it does it will then call the custom validator - which in this example calls the callback with an error if low is bigger than high.
The Callback Function
The asynchronous nature of the library, allows for asynchronous operations in custom functions.
The custom function must take three parameters
- data The data that needs validation
- schema The schema to validate against - This enables you to use the schema to pass in options.
- fn The callback function to call when validation either succeeds or fails.
- The callback function takes two parameters
- err An
Errordescribing the validation error that occurred. - data The finished and validated object.
Remark: Errors are automatically converted into a
ValidationErrorinternally.
Synchronous Example
The custom validator also supports synchronous functions, which is done by simple leaving out the callback parameter - and instead errors are thrown.
{
type: Object,
schema: {
'low': Number
'high': Number
}
'custom': function(data, schema) {
if (data.low > data.high) {
throw new Error('low must be lower than high');
}
return data;
}
}Thrown errors are caught and converted to a
ValidationErrorinternally.
Options with Custom Validators
If you need to pass any options to your custom validator, you can do so by using the options property of the schema.
An example below.
{
'myKey': {
options: {
myCustomOptions: 'here'
},
custom: function(data, schema, fn) {
// schema.options will now contain whatever options you supplied in the schema.
// In this example schema.options == { myCustomOptions: 'here'}.
}
}
}Multiple Custom Validators
The custom validator also support an array of validators. Instead of providing a function, provide an array of functions. Synchronous and asynchronous can be mixed and matched as necessary.
An example.
{
custom: [
function(data, schema, fn) {
data(null, myValidatedData);
},
function(data, schema) {
return mySecondValidatedData
}
]
}If, though, any of the custom validator functions returns an error (either using the callback in an asynchronous function, or by throwing an error in a synchronous one), none of the rest of the custom validators in the custom validator chain will get called, and isvalid will return an error.
The custom validator functions are called in order.
Type Shortcuts
Some types can be specified using shortcuts. Instead of specifying the type, you simply just use the type. This works with Object and Array types.
In this document we've been using them extensively on Object examples, and the first example of this document should have looked like this, if it hadn't been used.
isvalid(inputData, {
type: Object,
schema: {
'user': { type: String, required: true },
'pass': { type: String, required: true }
}
}, function(err, validData) {
/*
err: Error describing invalid data.
validData: The validated data.
*/
});Object Shortcuts
Object shortcuts are used like this:
{
"user": String
}and is in fact the same as this:
{
type: Object,
schema: {
"user": { type: String }
}
}Which means that data should be an object with a user key of the type String.
Remark: Internally the library tests for object shortcuts by examining the absent of the
typeandcustomvalidators. So if you need objects schemas with validators for keys with those names, you must explicitly format the object usingtypeandschema- hence the shortcut cannot be used.
Array Shortcuts
The same goes for arrays:
[String]is essentially the same as:
{
type: Array,
schema: { type: String }
}Which means the data must be an array of strings.
Other Shortcuts
The others are a bit different. They are - in essence - a shortcut for the validator type. Instead of writing type you just specify the type directly. Available types are all the supported types of isvalid, namely Object, Array, String, Number, Boolean and Date.
An example below.
{
"favorite_number": Number
}The above example is really an example of two shortcuts in one - the Object and the Number type shortcut. The above example would look like the one below, if shortcuts had not been used.
{
type: Object,
schema: {
"favorite_number": { type: Number }
}
}Automatic Type Conversion
Numbers
If the schema has type Number and the input holds a String containing numbers (or/and a point), the validator will automatically convert the string into a number.
Booleans
Likewise will schemas of type Boolean be automatically converted into a Boolean if a String with the value of true or false is in the data.
Dates
If the schema is of type Date and a String containing an ISO-8601 formatted date is supplied, it will automatically be parsed and converted into a Date.
ISO-8601 is the date format that JSON.stringify(...) convert Date instances into, so this allows you to just serialize an object to JSON on - as an example - the client side, and then isvalid will automatically convert that into a Date instance when validating on the server side.
License
MIT