express-validation is a middleware that validates the body
, params
, query
, headers
and cookies
of a request and returns a response with errors; if any of the configured validation rules fail.
$ npm install express-validation --save
express-validation
supports validating the following:
- body
- params
- query
- headers
- cookies
In order to setup and use express-validation
consider the following simple express application. It has a single route; configured to use the express-validation
middleware; it accepts as input validation.login
; which are the validation rules we have defined for this route.
file: test/app.js
var express = require('express')
, validate = require('express-validation')
, http = require('http')
, bodyParser = require('body-parser')
, cookieParser = require('cookie-parser')
, app = express();
app.use(bodyParser.json())
app.use(cookieParser())
app.set('port', 3000);
app.post('/login', validate(validation.login), function(req, res){
res.json(200);
});
// error handler, required as of 0.3.0
app.use(function(err, req, res, next){
res.status(400).json(err);
});
http.createServer(app);
The following section defines our validation rules validation.login
. This is simply an object, which uses https://github.com/spumko/joi to define validation rules for a request.
We have defined two rules email
and password
. They are encapsulated inside body
; which is important; as this defines their location, alternatives being, params
, query
, headers
and cookies
.
file: test/validation/login.js
var Joi = require('joi');
module.exports = {
body: {
email: Joi.string().email().required(),
password: Joi.string().regex(/[a-zA-Z0-9]{3,30}/).required()
}
};
The following test, calls the route defined in our express application /login
; it passes in a payload with an email
and empty password
.
file: test/body.js
describe('when the request has a missing item in payload', function () {
it('should return a 400 ok response and a single error', function(done){
var login = {
email: "[email protected]",
password: ""
};
request(app)
.post('/login')
.send(login)
.expect(400)
.end(function (err, res) {
var response = JSON.parse(res.text);
response.errors.length.should.equal(1);
response.errors[0].messages.length.should.equal(2);
done();
});
});
});
Running the above test will produce the following response.
{
"status": 400,
"statusText": "Bad Request",
"errors": [
{
"field": "password",
"location": "body",
"messages": [
"the value of password is not allowed to be empty",
"the value of password must match the regular expression /[a-zA-Z0-9]{3,30}/"
],
"types": [ "any.empty", "string.regex.base" ]
}
]
}
Full code for these examples is to be found in test/
directory.
When Joi
validates the body
, params
, query
, headers
or cookies
it returns it as Javascript Object.
Example without express-validation
:
app.post('/login', function(req, res){
console.log(req.body); // => '{ "email": "user@domain", "password": "pwd" }'
res.json(200);
});
Example with express-validation
:
var validate = require('express-validation');
var validation = require('./test/validation/login.js');
app.post('/login', validate(validation.login), function(req, res){
console.log(req.body); // => { email: "user@domain", password: "pwd" }
res.json(200);
});
The difference might seem very slight, but it's a big deal.
All parts of a request
will be either parsed, or throw errors.
Enabling a configurable flag, contextRequest
, the Joi validation can access parts of the node http.ClientRequest
.
This allows you to reference other parts of the request in your validations, as follows:
Example:
Validate that the ID in the request params is the same ID as in the body for the endpoint /context/:id
.
file: test/validation/context.js
var Joi = require('joi');
module.exports = {
body: {
id: Joi.string().valid(Joi.ref('$params.id')).required()
}
};
The following test calls the /context/1
route in the express application; It passes a payload with the an id
of '2'.
file: test/context.js
describe('when the schema contains an invalid reference to the request object', function() {
it('should return a 400 response', function(done) {
request(app)
.post('/context/1')
.send({id: '2'})
.expect(400)
.end(function(err, res) {
if(err) {
return done(err);
}
done();
});
});
});
});
Running the above test will produce the following response:
{
"status": 400,
"statusText": "Bad Request",
"errors": [
{
"field": "id",
"location": "body",
"messages": [
"\"id\" must be one of [context:params.id]"
],
"types": [
"any.allowOnly"
]
}
]
}
When creating a validation object that checks req.headers
; please remember to use lowercase
names; node.js will convert incoming headers to lowercase:
var Joi = require('joi');
module.exports = {
headers: {
accesstoken: Joi.string().required(),
userid : Joi.string().required()
}
};
Since 0.4.0 express-validation
calls next()
with a ValidationError
, a specific type of Error
.
This can be very handy when writing more complex error handlers for your Express application, a brief example follows:
var ev = require('express-validation');
// error handler
app.use(function (err, req, res, next) {
// specific for validation errors
if (err instanceof ev.ValidationError) return res.status(err.status).json(err);
// other type of errors, it *might* also be a Runtime Error
// example handling
if (process.env.NODE_ENV !== 'production') {
return res.status(500).send(err.stack);
} else {
return res.status(500);
}
});
By default, additional fields outside of the schema definition will be ignored by validation.
To enforce strict checking, set the allowUnknown\*
options as follows:
module.exports.post = {
options : {
allowUnknownBody: true,
allowUnknownHeaders: true,
allowUnknownQuery: true,
allowUnknownParams: true,
allowUnknownCookies: true
},
...
};
With strict checking enabled, if additional fields gets sent through validation, they will be raise a ValidationError
.
By default, the status code is set to 400
, and status text to Bad Request
, you can change this behaviour with the following:
module.exports.post = {
options: {
status: 422,
statusText: 'Unprocessable Entity'
},
...
};
Status code and text can also be customized globally. At the same time specific behaviour still applies.
var ev = require('express-validation');
// assign options
ev.options({
status: 422,
statusText: 'Unprocessable Entity'
});
// clear options back to default
ev.options();
Thanks to node require()
caching, all the other express-validation
instances also have the same set of global options.
Recap of all options usable both as global or per-validation basis.
allowUnknownBody: boolean - default: true
allowUnknownHeaders: boolean - default: true
allowUnknownQuery: boolean - default: true
allowUnknownParams: boolean - default: true
allowUnknownCookies: boolean - default: true
status: integer - default: 400
statusText: string - default: 'Bad Request'
contextRequest: boolean - default: false
Moved to CHANGELOG.md
This work is licensed under the MIT License (see the LICENSE file).
https://github.com/AndrewKeig/express-validation/blob/master/LICENSE
- Christian Holm https://github.com/holm
- Iheanyi Ekechukwu https://github.com/iheanyi
- Aymeric Beaumet https://github.com/aymericbeaumet
- Valerio Coltrè https://github.com/colthreepv
- gdw2 https://github.com/gdw2
- Robert Barbey https://github.com/rbarbey
- Stefan Lapers https://github.com/slapers
- Alex Mazzeo https://github.com/amazzeo