Table of Contents
Async Validate
Asynchronous validation for node and the browser.
Install
npm i async-validate
Usage
Usage involves defining a descriptor, assigning it to a schema and passing the object to be validated and a callback function to validate()
:
var Schema = require('..')
, descriptor = {name: {type: "string", required: true}}
, validator = new Schema(descriptor)
, source = {};
schema.plugin(
[require('../plugin/string')]);
validator.validate(source, function(errors, fields) {
if(errors) {
return console.dir(errors)
}
});
Guide
Plugins
To use schema types you should load plugins for the types you wish to validate:
var schema = require('async-validate');
schema.plugin([
require('async-validate/plugin/array'),
require('async-validate/plugin/boolean'),
require('async-validate/plugin/number'),
require('async-validate/plugin/string')
])
As a shortcut you may use all available types with:
require('async-validate/plugin/all');
See plugins for the type plugins that ship with this module and zephyr for documentation on the plugin system.
The plugin fixture and the plugin test provide an example of creating a type plugin.
Descriptor
A descriptor defines the validation rules as a map of fields to rules.
This section describes the rule fields recognised by the module plugins, typically you would create a type plugin so that the type is reusable but you may also inline rule functions:
var descriptor = {
name: function(cb) {
cb(this.errors);
}
}
Type
Indicates the type
of validator to use. A type corresponds to a plugin function and the plugin should have been loaded.
Recognised type values are:
string
: Must be of type string
.number
: Must be of type number
.boolean
: Must be of type boolean
.method
: Must be of type function
.regexp
: Must be an instance of RegExp
or a string that does not generate an exception when creating a new RegExp
.integer
: Must be of type number
and an integer.float
: Must be of type number
and a floating point number.array
: Must be an array as determined by Array.isArray
.object
: Must be of type object
and not Array.isArray
.enum
: Value must exist in the enum
.date
: Value must be valid as determined by moment().isValid()
.
When the object
plugin has been loaded the type
field may be a function in which case the value must be an instanceof
the function assigned to type
.
Required
The required
rule property indicates that the field must exist on the source object being validated.
Pattern
The pattern
rule property indicates a regular expression that the value must match to pass validation.
Range
A range is defined using the min
and max
properties. For string
and array
types comparison is performed against the length
, for number
types the number must not be less than min
nor greater than max
.
Length
To validate an exact length of a field specify the len
property. For string
and array
types comparison is performed on the length
property, for the number
type this property indicates an exact match for the number
, ie, it may only be strictly equal to len
.
If the len
property is combined with the min
and max
range properties, len
takes precedence.
Values
Used with the array
type as a shorthand for validating array values, may be an object
or array
containing validation rules.
When values
is an object it is applied to all array elements in the source array otherwise each values
entry is compared against each source array entry which allows mixed types to be used in arrays.
Note that values
is expanded to fields
, see deep rules.
Enumerable
To validate a value from a list of possible values use the enum
type with a enum
property listing the valid values for the field, for example:
var descriptor = {
role: {type: "enum", enum: ['admin', 'user', 'guest']}
}
Date Format
Validating dates can be complex but using moment date validation is substantially easier.
If no format
is specified for a rule that is a date
type then it is assumed the date is ISO 8601. If a format is specified then the date is validated according to the specified format.
It is recommended you read the moment documentation on the isValid
method to understand what validation is performed.
The important part is:
Note: It is not intended to be used to validate that the input string matches the format string. Because the strictness of format matching can vary depending on the application and business requirements, this sort of validation is not included in Moment.js.
This limitation may be overcome by combining a pattern
in a date rule, for example:
var descriptor = {
active: {
type: "date",
format: "YYYY-MM-DD",
pattern: /^([\d]{4})-([\d]{2})-([\d]{2})$/
}
}
Whitespace
It is typical to treat required fields that only contain whitespace as errors. To add an additional test for a string that consists solely of whitespace add a whitespace
property to a rule with a value of true
. The rule must be a string
type.
You may wish to sanitize user input instead of testing for whitespace, see transform for an example that would allow you to strip whitespace.
Multiple Rules
It is often useful to test against multiple validation rules for a single field, to do so make the rule an array of objects, for example:
var descriptor = {
email: [
{type: "string", required: true},
function(cb) {
cb(this.errors);
}
]
}
Deep Rules
If you need to validate deep object properties you may do so for validation rules that are of the object
or array
type by assigning nested rules to a fields
property of the rule.
var descriptor = {
address: {
type: "object", required: true,
fields: {
street: {type: "string", required: true},
city: {type: "string", required: true},
zip: {type: "string", required: true, len: 8, message: "invalid zip"}
}
},
name: {type: "string", required: true}
}
var validator = new schema(descriptor);
validator.validate({ address: {} }, function(errors, fields) {
});
Note that if you do not specify the required
property on the parent rule it is perfectly valid for the field not to be declared on the source object and the deep validation rules will not be executed as there is nothing to validate against.
Deep rule validation creates a schema for the nested rules so you can also specify the options
passed to the schema.validate()
method.
var descriptor = {
address: {
type: "object", required: true, options: {single: true, first: true},
fields: {
street: {type: "string", required: true},
city: {type: "string", required: true},
zip: {type: "string", required: true, len: 8, message: "invalid zip"}
}
},
name: {type: "string", required: true}
}
var validator = new schema(descriptor);
validator.validate({ address: {} }, function(errors, fields) {
});
The parent rule is also validated so if you have a set of rules such as:
var descriptor = {
roles: {
type: "array", required: true, len: 3,
fields: {
0: {type: "string", required: true},
1: {type: "string", required: true},
2: {type: "string", required: true}
}
}
}
And supply a source object of {roles: ["admin", "user"]}
then two errors will be created. One for the array length mismatch and one for the missing required array entry at index 2.
Messages
Depending upon your application requirements, you may need i18n support or you may prefer different validation error messages.
The easiest way to achieve this is to assign a message
to a rule:
{name:{type: "string", required: true, message: "Name is required"}}
You may also use a function for the rule message, it is invoked in the scope of the rule validator and passed the original message and replacement parameters:
var descriptor = {
name: {
type: "string",
required: true,
message: function(message, parameters) {
return this.field + ' is required';
}
}
}
If you just want to change the default messages:
var schema = require('async-validate')
, messages = require('async-validate/messages');
messages.required = "%s is a required field";
Potentially you may require the same schema validation rules for different languages, in which case duplicating the schema rules for each language does not make sense.
In this scenario you could just require your own messages file for the language and assign it to the schema:
var schema = require('async-validate');
var es = require('messages-es');
var descriptor = {name:{type: "string", required: true}};
var validator = new schema(descriptor);
validator.messages(es);
Or you could clone a default messages instance and then assign language specific messages to the schema using the messages
method.
var schema = require('async-validate')
, messages = require('async-validate/messages')
var es = schema.clone(messages);
es.required = "%s es un campo obligatorio";
var descriptor = {name:{type: "string", required: true}};
var validator = new schema(descriptor);
validator.messages(es);
If you are defining your own validation functions it is better practice to assign the message strings to a messages object and then access the messages via the this.messages
property within the validation function.
Transform
Sometimes it is necessary to transform a value before validation, possibly to coerce the value or to sanitize it in some way. To do this add a transform
function to the validation rule. The property is transformed prior to validation and re-assigned to the source object to mutate the value of the property in place.
Without the transform
function validation would fail due to the pattern not matching as the input contains leading and trailing whitespace, but by adding the transform function validation passes and the field value is sanitized at the same time.
var schema = require('..')
, descriptor = {
name: {
type: "string",
required: true, pattern: /^[a-z]+$/,
transform: function(value) {
return value.trim();
}
}
}
, validator = new schema(descriptor)
, source = {name: " user "};
schema.plugin([require('../plugin/string')]);
validator.validate(source, function(errors, fields) {
console.dir(source.name);
});
Standard Rules
Some standard rules for common validation requirements are accessible, you may wish to reference these rules or copy and modify them.
These rules must be required to be used: require('async-validate/std-rules')
, see std rules.
field
: Typical required field.email
: Basic email validation rule using a pattern, note validating email addresses with a regular expression is fraught with pitfalls, use this with caution.url
: Simple http(s) URL rule.hex
: Rule for hexadecimal color values with optional leading hash.
API
Validate
function(source, [options], callback)
source
: The object to validate (required).options
: An object describing processing options for the validation (optional).callback
: Callback function to invoke when validation completes (required).
Options
first
: Invoke callback
when the first validation rule generates an error, no more validation rules are processed. If your validation involves multiple asynchronous calls (for example, database queries) and you only need the first error use this option.single
: Only ever return a single error. Typically used in conjunction with first
when a validation rule could generate multiple errors.keys
: Specifies the keys on the source object to be validated. Use this option to validate fields in a determinate order or to validate a subset of the rules assigned to a schema.parallel
: A boolean indicating that the validation should be executed in parallel.field
: Field name for the root object, default is source
when not specified.rules
: Rules to apply to the root source object, may be an array or a single rule object.
Consider the rule:
{name: {type: "string", required: true, min: 10, pattern: /^[^-].*$/}}
When supplied with a source object such as {name: "-name"}
the validation rule would generate two errors, as the pattern does not match and the string length is less then the required minimum length for the field.
In this instance when you only want the first error encountered use the single
option.
Rules
Rules are functions that perform validation. They are invoked in the scope of a validator so you should not call bind()
on validation rule functions.
function(cb)
cb
: Callback function to invoke when validation completes, expects an array of error instances to be passed.
Scope
The scope of the rule function exposes the fields:
rule
: The validation rule in the source descriptor that corresponds to the field name being validated.value
: The value of the source object property being validated.field
: The name of the field being validated.source
: The source object that was passed to the validate
method.options
: The options passed to validate()
.messages
: Reference to the messages assigned to options
.errors
: Array of errors for the field validation.
Developer
Test
Run the test specifications:
npm test
Cover
Generate code coverage:
npm run cover
Browserify
Create a standalone browserify build:
npm run browserify
Clean
Remove generated files:
npm run clean
Docs
To generate all documentation:
npm run docs
Readme
Generate the project readme file mdp:
npm run readme
Browser Support
| | | |
---|
Latest ✔ (tested on 39) | Latest ✔ (tested on 33) | Latest ✔ (tested on 25) | Latest ✔ (tested on 8) |
## License
Everything is MIT. Read the license if you feel inclined.
Generated by mdp(1).