DEV Community

Cover image for A Clean Approach to Using Express Validator
Chinedu Orie
Chinedu Orie

Posted on

A Clean Approach to Using 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.

Note: This article assumes that the reader already has an express project and only wants to implement validation using express validator. Hence, some details may be skipped.

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:

// ...rest of the initial code omitted for simplicity.
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))
  }
)
Enter fullscreen mode Exit fullscreen mode

Looking at the snippet above, you'd notice that the validation is tightly coupled to the route definition. That pattern may be okay for a very simple use case but when usage scales, it'd be difficult for the codebase to be maintained and also it makes the route definition not readable.

In this article, I'll be showing how the validation above can be made more readable and easier to maintain.

Step 1

Create a file named validator.js
Inside the validator.js, we are going to add two functions, one of the functions will hold the validation rules, while the second will contain the function the does the actual validation.

Copy the snippet below into the validator.js

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,
}
Enter fullscreen mode Exit fullscreen mode

Step 2

Now re-writing the initial snippet above, we'd 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))
})
Enter fullscreen mode Exit fullscreen mode

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"
        },
    ]
}
Enter fullscreen mode Exit fullscreen mode

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.

This article has a lot of assumptions and hence some details were skipped. However, if you do have any question, feel free to reach out to me.

You can read more about express validator on the official documentation website

This article was originally published on my blog

Latest comments (45)

Collapse
 
yassne profile image
yasu uo

Hell,Thanks For Shairng !
I want to just to know if someone use the validator.js library

Collapse
 
rick47curious profile image
Anuplab chatterjee

Awesome article. I have recently used this implementation in my clone application with slight tweeks.
Thanks for the share! Cheers 🥂

Collapse
 
imkivan profile image
imk-ivan

Great solution, thanks!

Collapse
 
drey profile image
.

Hi Chinedu,

Was looking for a way to make a custom middleware for this validator and this solved my problem brilliantly!

Awesome work

Collapse
 
shanbiswas profile image
Santanu Biswas

I found a more simplistic approach of doing this on Stackoverflow.

// validator.js
const { check, validationResult } = require('express-validator')

exports.validateUser = [
check('name')
    .trim()
    .escape()
    .not()
    .isEmpty()
    .withMessage('Name can not be empty!')
    .bail()
    .isLength({min: 3})
    .withMessage('Minimum 3 characters required!')
    .bail(),

(req, res, next) => {
    const errors = validationResult(req);
    if (!errors.isEmpty())
    return res.status(200).json({errors: errors.array()});
    next();
},
];


// router.js
const validateUser = require('../validator)
router.post('/users/create', validateUser, UserController.create)

// UserController.js
async create(req, res) {
     // do stuff
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
mirzasetiyono profile image
Mirza Setiyono

thank you!

Collapse
 
farzinkhaleghian profile image
Farzin Khaleghian

In this function if we want to support multiple validation rules and make a condition based on one key in the request body, do you have any ideas? In the other hand how we can pass req in this function?

Collapse
 
pprachit09 profile image
Prachit Suhas Patil

Thanks for sharing! Very useful.

Collapse
 
nishig20 profile image
nishiG-20

Thanks Chinedu

Collapse
 
veera_zaro profile image
Veera

userValidationRules() why do we need to use parentheses to call this function in the route. since this is a callback right ?