Express Validator
Express validator is one of the many npm packages for validating a request an express application.
I recently used express validator
in a project and stumbled upon a few challenges which I'm going to share in this article.
When you visit the express validator docs, you’d notice the way the validator was used in the examples as shown in the snippet below:
const { check, validationResult } = require('express-validator')app.post(
'/user',
[
// username must be an email
check('username').isEmail(),
// password must be at least 5 chars long
check('password').isLength({ min: 5 }),
],
(req, res) => {
// Finds the validation errors in this request and wraps them in an object with handy functions
const errors = validationResult(req)
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() })
} User.create({
username: req.body.username,
password: req.body.password,
}).then(user => res.json(user))
}
)
Looking at the snippet above, you will notice that the validation is tightly coupled to the route definition. That pattern may be good for a simple case but when it comes to scaling, it will be difficult for the code to be maintained and it will make reading the routes difficult.
To make the validation be more readable and easier to maintain:
Step 1
Create a file named validator.js
Inside the validator.js
, we are have two functions, one of the functions will hold the validation rules, while the second will contain the function the does the actual validation.
const { body, validationResult } = require('express-validator')
const userValidationRules = () => {
return [
// username must be an email
body('username').isEmail(),
// password must be at least 5 chars long
body('password').isLength({ min: 5 }),
]
}const validate = (req, res, next) => {
const errors = validationResult(req)
if (errors.isEmpty()) {
return next()
}
const extractedErrors = []
errors.array().map(err => extractedErrors.push({ [err.param]: err.msg })) return res.status(422).json({
errors: extractedErrors,
})
}module.exports = {
userValidationRules,
validate,
}
Step 2
Now re-writing the initial snippet above, we have:
const { userValidationRules, validate } = require('./validator.js')
app.post('/user', userValidationRules(), validate, (req, res) => {
User.create({
username: req.body.username,
password: req.body.password,
}).then(user => res.json(user))
})
Now if you try to register a user without meeting the specification for the user data, the validation error response would look like shown below:
{
"errors": [
{
"username": "username must be an email"
},
{
"password": "password must be at least 5 chars long"
},
]
}
Conclusion
With this method in place, you can define the validation rules for each route or module in a separate file as you may deem fit and then chain it with the validate middleware
. That way the code looks much cleaner, easier to read and easier to maintain.
Hope you enjoyed reading!