DEV Community

Cover image for A Clean Approach to Using Express Validator

A Clean Approach to Using Express Validator

Chinedu Orie on August 09, 2019

Express validator is one of the many npm packages for validating a request an express application. I recently used express validator in a project ...
Collapse
 
gallib_net profile image
Alain

Very useful thanks!

For my purpose I just split validators.js in 2 parts, your validate const is for me a separate middleware in which I've also added a

req.matchedData = matchedData(req) 
Enter fullscreen mode Exit fullscreen mode

useful to me to access to validated data in next middleware.

My validateRules middleware looks like:

import { matchedData, validationResult } from 'express-validator';

const validateRules = (req, res, next) => {
    const errors = validationResult(req);

    if (errors.isEmpty()) {
        req.matchedData = matchedData(req);
        return next();
    }

    const extractedErrors = [];
    errors.array().map(err => extractedErrors.push({ [err.param]: err.msg }));

    return res.status(422).json({
        errors: extractedErrors,
    });
}

export default validateRules;
Enter fullscreen mode Exit fullscreen mode
Collapse
 
arnabmunshi profile image
ARNAB MUNSHI

hi Alain

import { matchedData, validationResult } from 'express-validator';

This line not working for me. I don't know why.

But the following code is work for me.

import expressValidator from "express-validator";
const { body, validationResult } = expressValidator;
Collapse
 
nedsoft profile image
Chinedu Orie

That was insightful. Thanks for sharing!

Collapse
 
pearsonhill profile image
PearsonHill • Edited

Hey Chinedu,

I echo sentiment of others regarding the endless search for finding a tutorial that made sense and was easy to implement! Thank you! Would I check for duplicates in the database in this file as well?

  • Pearson

PS: I found this:
express-validator.github.io/docs/c...

how would we incorporate it into what we have?

I'm sure your slammed with requests like this - no worries if you don't have the bandwidth to reply

Collapse
 
pearsonhill profile image
PearsonHill

hey Chinedu - kept searching and found my answer! I am fired up - see below if anyone else is interested:

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

const teamValidationRules = () => {

return [
// is name present
check('name'," a string 'name' is required.")
.notEmpty().isString()
.custom(
async (value, {req}) => {
const check = await Team.findOne({name: value})

           if(check){
            return Promise.reject('Name is already in use');
           }


        }),
Collapse
 
nedsoft profile image
Chinedu Orie

Great job, I just saw your comment, good to know you've been able to tackle it

Collapse
 
geepalik profile image
Gil Palikaras • Edited

Hi Chinedu,

Thank you for the solution, looks great and works great.
I am using PHPStorm/WebStorm and when I implemented this solution, the editor shows warning (yellow underline):
Argument types do not match parameters

const {studentValidationRules, validate} = require('../util/dataValidator');
router.post('/student', studentValidationRules(), validate ,studentController.createStudent);

error

I thought I was using correctly the pattern of adding middleware to my routes, did I do something wrong?

Collapse
 
imkivan profile image
imk-ivan

Great solution, thanks!

Collapse
 
syed456 profile image
syed

Hi Chinedu,
I was looking exactly this way,
I want to know how the below line works
"app.post('/user', userValidationRules(), validate, (req, res) => {"

How userValidationRules() related to validate,
Thanks
Syed

Collapse
 
nedsoft profile image
Chinedu Orie

Hi Syed, the userValidationRules() is a helper which uses the express-validator methods to intercept the request and enforce the validation, express-validator methods pass the results of the validations to the request, the validate is a middleware which checks if the request contains errors injected by the express-validator methods; as middlewares do, if there's an error in the request object, it returns the error response, if there's no error in the request object, it calls the next function allowing the request to continue to the next stage.

Collapse
 
syed456 profile image
syed

Hi thanks for the reply
I'm sorry, I'm still in learning the middleware. You said userValidationRules() is helper, but not a middleware, since because of the braces ()?, how these two (userValidationRules() and valiadate) differ from each other in that place.
My understanding is, the helper userValidationRules(), executed immediately, and send the errors ,if any, to validate middleware 'validate'?.
If i want to combine those two into one single middleware, how can I achieve that?

Thanks
Syed

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
 
atexzonate profile image
atexzonate

Nice post. Was struggling with this for a while until I saw your post.. Thank Omo Naija

Collapse
 
nedsoft profile image
Chinedu Orie

Haha, the Omo Naija part. Good to know you found it helpful ✌️

Collapse
 
reak45 profile image
Reak45

Great post! However I have a question. Can this be merged in a single middleware? Instead of two functions?

Collapse
 
nedsoft profile image
Chinedu Orie • Edited

Certainly yes, I've recently made an improvement to it in my personal codes. The validator takes schema as a param. I found it cleaner and I'd update the article ASAP. Below is what it looks like:

const { body, validationResult} = require('express-validator');

const validate = (schemas)  => {
    return async (req, res, next) => {
      await Promise.all(schemas.map((schema) => schema.run(req)));

      const result = validationResult(req);
      if (result.isEmpty()) {
        return next();
      }

      const errors = result.array();
      return  res.send(errors)
    };
  }
 const exampleSchema = [
   body('foo', 'The foo field is required').notEmpty(),
   ...
];

router.post('/foos', validate(exampleSchema), fooHandler);

Enter fullscreen mode Exit fullscreen mode
Collapse
 
leblancmeneses profile image
Leblanc Meneses

How would you implement mutually exclusive properties like google maps geocoding?
can be either: address or latlng but not both

github.com/express-validator/expre...

seems oneOf is middleware not a ValidationChain[]. I'm handling it manually using a custom rule because that allows me to continue using similar "validate" middleware, although, what else are we missing by having this convenience "validate" wrapper .

Great writeup!

Collapse
 
reak45 profile image
Reak45

This is just awesome! Thank you so much!

Thread Thread
 
nedsoft profile image
Chinedu Orie

Anytime!

Collapse
 
consciousness_dev profile image
Ario Setiawan

My error value just "Invalid value", not described as example :
{
"errors": [
{
"username": "username must be an email"
},
{
"password": "password must be at least 5 chars long"
},
]
}

that is from validator library or from backend?

Collapse
 
nedsoft profile image
Chinedu Orie

If you didn't specify a custom error message, then it'll assume the default message from the library

Collapse
 
consciousness_dev profile image
Ario Setiawan
Collapse
 
nedsoft profile image
Chinedu Orie

Hi Mohammad, If I got your question clearly it means you're using server side rendering. The example above would serve well for an API where all responses are JSON objects. In your case, you return a view instead of a JSON object. So what you should do is to return a view then passing the error object as a data to the view.

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
 
sanwar1 profile image
sanwar1

Thank you Chinedu. Just what I was looking for. Very elegant. However, this is just for one API handle. What if there are multiple request handles and each of them with multiple parameters?

Should I create a separate layer for validations for a real-world application??

Collapse
 
damien1990 profile image
Damien1990

Love this approach to validation but wondering how I would compare the value of one field to another with it? For example password and confirmpassword. Any help would be appreciated.

Collapse
 
nedsoft profile image
Chinedu Orie

You can use a custom rule

See example from the docs:

const { body } = require('express-validator');

app.post('/user', body('passwordConfirmation').custom((value, { req }) => {
  if (value !== req.body.password) {
    throw new Error('Password confirmation does not match password');
  }

  // Indicates the success of this synchronous custom validator
  return true;
}), (req, res) => {
  // Handle the request
});
Collapse
 
damien1990 profile image
Damien1990

Thank you, it worked beautifully. I'm guessing you can use a similar approach to checking for 'unique' emails/usernames by requiring the model in the validator class, using the value to search for existing emails/usernames in the database and if one is returned, to throw an error?

Thread Thread
 
nedsoft profile image
Chinedu Orie

yes

Collapse
 
chidioguejiofor profile image
Chidiebere Ogujeiofor

Really appreciate this one. Was already trying to do something like this. Thanks for saving me some valuable time

Collapse
 
nedsoft profile image
Chinedu Orie

Glad you found it helpful

Collapse
 
onestica profile image
onestica

Simple and clear explanation. Thanks, this is what I'm looking for :)

Collapse
 
nbsamurai profile image
Subramani Simhachalam

Very useful info. Was trying to upgrade from the previous version of express-validator. Thanks

Collapse
 
thanhtruchuynh profile image
Truc Huynh

Thank you! This article is very useful !

Collapse
 
nishig20 profile image
nishiG-20

Thanks Chinedu

Collapse
 
kidmek profile image
Kidmek

Thank you so much! There are so many articles which are misleading.

Collapse
 
yassne profile image
yasu uo

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

Collapse
 
pprachit09 profile image
Prachit Suhas Patil

Thanks for sharing! Very useful.

 
nedsoft profile image
Chinedu Orie

Yeah. That's pretty much it. Good job!

Collapse
 
rufatn profile image
Rufat Nuriev

VERY USEFUL! THANK YOU!

Collapse
 
hvsharma profile image
Harshvardhan Sharma

Hello,
Just one question, How do you validate FormData non-file and file fields together?

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
 
mirzasetiyono profile image
Mirza Setiyono

thank you!

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 ?

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