In this article you will learn how to validate your payload coming from a POST request for an Express API using express-validator. Learn how to validate any data coming in as input to your Express endpoints.
Express Validator is an npm package that helps developers to validate the incoming requests to an API build in Express in the routes layer. To start with, install the express-validator package.
npm install --save express-validator
I have an Express API route that saves a user profile.
router.post("/profile", function(req, res) { profileService.saveProfile(req,res); });
Usually we apply all the validation login in the service after extracting all the values from the request. This can be done easily in the route using express-validator. It provides various built in validators to assert all kinds of input types.
You need to import check and validationResult from express-validator.
const { check, validationResult } = require('express-validator');
Mobile Number, Email and Name can be validated using the following piece of code. If there’s an error, it will be added to the errors array. On checking the array, you would know if there are any errors, depending on which you would have to send error response.
Here I use the in-built validators like isMobilePhone(), isEmail() and isLength() to validate mobileNumber, email and name.
router.post('/profile', [ check('mobileNumber').isMobilePhone(), check('email').isEmail(), check('name').isLength({ max: 30, min: 6 }), ], (req, res) => { const errors = validationResult(req) if (!errors.isEmpty()) { return res.status(422).json({ errors: errors.array() }) } profileService.saveProfile(req,res); })
Let’s look at other validators which are readily available.
Some values like About an user are optional. You can add .optional() in the validation chain.
check('about').optional().isLength({ max: 300, min: 6 }),
To check if a value is URL.
check('fb').optional().isURL(),
To check if a value is in base64 format.
check('profilePic').optional().isBase64()
There are many validators available like this.
The error response would be in the format below.
{ "errors": [{ "location": "body", "msg": "Invalid value", "param": "email" }] }
Custom Validators
You can create your own validators with custom messages. Let’s say I want to check if the password field contains 8 characters with one number, one uppercase and one lowercase letter, I can match the password with a regex and return a custom message if it doesn’t match.
check('password').custom(password => { if(password && password.match(/^(?=.{8,}$)(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\W).*$/)) { return true; } }).withMessage("Password must contain 8 characters and atleast 1 number, 1 uppercase and lowercase letter."),
My full source code for validating input for Save Profile would like this.
router.post('/profile', [ check('password').custom(password => { if(password && password.match(/^(?=.{8,}$)(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\W).*$/)) { return true; } }).withMessage("Password must contain 8 characters and atleast 1 number, 1 uppercase and lowercase letter."), check('mobileNumber').isMobilePhone(), check('email').isEmail(), check('name').isLength({ max: 30, min: 6 }), check('likes').optional().isLength({ max: 300, min: 6 }), check('role').optional().isLength({ max: 50, min: 6 }), check('profession').optional().isLength({ max: 50, min: 6 }), check('country').optional().isLength({ max: 50, min: 3 }), check('fb').optional().isURL(), check('twitter').optional().isURL(), check('ig').optional().isURL(), check('about').optional().isLength({ max: 300, min: 6 }), check('profilePic').optional().isBase64() ], (req, res) => { const errors = validationResult(req) if (!errors.isEmpty()) { return res.status(422).json({ errors: errors.array() }) } profileService.saveProfile(req,res); })