All object validation libraries come bundled with their own assertion / sanitization primitives. Which is kind of dumb. There is a lot of great libraries such as chai.js or validator.js which could and should be used instead.
node-validation-pod is just an empty shell for running synchronous / asynchronous validation on objects. It doesn't come with any functionality for validating data. Only the validation logic. This way, you can plug-in any validation library you want.
Implements 3 steps :
- before : prepare your data for validation. If some fields validity depend on each other, you can check it here. If a validation error occurs, go directly to
after
step. - attributes validators : for each attribute in your object, run the corresponding validator. Gathers all errors in one object.
- after : check for unknown attributes. Add errors to the errors found in previous step.
Here is a simple example on how to use validator.js to validate the data submitted in a user sign-up form.
var chai = require('validator')
, vpod = require('validation-pod')
userRegisterValidator = new vpod.Validator({
email: function(val) {
if (!validator.isEmail(val)) return 'Invalid email'
},
password: function(val) {
if (!isLength(password, 8)) return 'Password must be at least 8 characters!'
// ... more validation rules
},
confirmPassword: function(val) {
if (this.password !== val) return 'Passwords do not match'
}
})
First you need to create a subclass of Validator
:
var chai = require('chai')
, vpod = require('validation-pod')
, inherits = require('util').inherits
var ChaiValidator = function() {
vpod.Validator.apply(this, arguments)
}
inherits(ChaiValidator, vpod.Validator)
// This hooks allows to catch errors that occur during any of the 3 steps
// of the validation process.
// Return a message if the error is a validation error and should be handled,
// return nothing or `false` if the error has not been handled and should be thrown.
ChaiValidator.prototype.handleError = function(err) {
if (err instanceof chai.AssertionError) {
return err.message
}
}
ChaiValidator
will allow us to validate data using chai assertions. Let's now create a validator for some boring Animal
object :
var fs = require('fs')
, chai = require('chai')
, expect = chai.expect
var animalValidator = new ChaiValidator({
// Example of synchronous validation
species: function(val) { expect(val).to.be.a('string') },
color: function(val) { expect(val).to.be.a('string') },
age: function(val) { expect(val).to.be.a('number') },
// Example of asynchronous validation (note the second argument is a `done` callback)
// We want to validate that the folder where we put our animal's pictures exists.
pictureFolder: function(val, done) {
fs.open(val, 'r', function(err) {
if (err && err.code === 'ENOENT')
err = new chai.AssertionError('path \'' + val + '\' does not exist')
done(err)
})
}
})
Now let's validate some stuff :
// A valid animal
var aDog = {
species: 'dog',
color: 'blue',
age: 12,
pictureFolder: '/tmp'
}
animalValidator.run(aDog, function(err, validationErrors) {
if (err) throw err // this is real errors coming here.
console.log(validationErrors) // -> {}
})
// An unvalid animal
var anotherDog = {
species: 'dog',
color: 1,
age: 12,
pictureFolder: '/waf waf',
unknownAttribute: '???'
}
animalValidator.run(anotherDog, function(err, validationErrors) {
if (err) throw err // this is real errors coming here.
console.log(validationErrors) // -> {'.color': 'expected ...', '.': 'unknownAttribute': '...', ...}
})
Builds a new validator.
Run the validation on obj
. Options can be :
prefix
: the prefix to add to the validation error keysvalidationErrors
: an object to populate with validation errors