Search code examples
javascriptexpressexpress-validator

How to extract express-validator checks in separate mw-functions?


This works ok, though it is extremely messy:

//./user/router.js

const express = require('express')
const router = express.Router()
const controller = require('./controller')

// mw
const { check } = require('express-validator')

router.get('/register', controller.register)
router.post(
   '/register',
   [
      check('username')
         .not()
         .isEmpty()
         .withMessage('Username is required'),
      check('email')
         .isEmail()
         .withMessage('Incorrect email.'),
      check('password')
         .not()
         .isEmpty()
         .withMessage('Password is required.')
         .isLength({ min: 3 })
         .withMessage('Should be more then 3 characters.'),
   ],
   controller.register__post,
)
module.exports = router

The aim is to extract validation in separate middleware function. So the router-file will be clean and straitforward

//./user/router.js

const express = require('express')
const router = express.Router()
const controller = require('./controller')

// mw
const { validateRegister } = require('./mw/validation')


router.get('/register', controller.register)
router.post('/register', validateRegister, controller.register__post)

module.exports = router


This doesn't throws any errors, but validation errors are not in validationResult(req):

//./user/mw/validation.js

const { check } = require('express-validator')

exports.validateRegister = function(req, res, next) {

   check('username')
      .not()
      .isEmpty()
      .withMessage('Username is required')
   check('email')
      .isEmail()
      .withMessage('Incorrect email.')
   check('password')
      .not()
      .isEmpty()
      .withMessage('Password is required.')
      .isLength({ min: 3 })
      .withMessage('Should be more then 3 characters.')

   return next()

}

__

Also: how does check() function work in terms of middleware function? I mean, it's ok to pass check-functions as a list

//./user/router.js

...
router.post('/register', [
      check('username').not().isEmpty(),
      check('email').isEmail(),
      check('password').isLength({ min: 3 }),
   ],
   controller.register__post)
...

But check-function doesn't call next(), so this won't work:

//./user/router.js

const { validateRegister } = require('./mw/validation')

...

router.post('/register', validateRegister, controller.register__post)

//./user/mw/validation

const { check } = require('express-validator')

exports.validateRegister = function(req, res, next) {
   return check('email').isEmail()
}


Solution

  • In this case it would be convenient to use validator (on which express-validator is built). Validation methods are the same.

    middleware function

    //./user/mw.js
    
    const { isEmail, isLength, isEmpty } = require('validator')
    
    exports.validateRegister = function(req, res, next) {
       const { username, email, password } = req.body
       const errors = []
    
       if (isEmpty(username))
          errors.push({
             param: 'username',
             msg: 'Имя пользователя обязательно.',
          })
    
       if (!isEmail(email))
          errors.push({ param: 'email', msg: 'Некорректный email.' })
    
       if (!isLength(password, { min: 3 }))
          errors.push({
             param: 'password',
             msg: 'Пароль должен быть не менее 3 символов.',
          })
    
       req.errors = errors
       return next()
    }
    
    

    router

    //./user/router.js
    
    const express = require('express')
    const router = express.Router()
    const controller = require('./controller')
    const { validateRegister } = require('./mw')
    
    router.get('/register', controller.register)
    router.post('/register', validateRegister, controller.register__post)
    
    
    module.exports = router