Search code examples
node.jserror-handlinglodashexpress-validator

express-validator - Customize errors output


I am using express validator to validate the json body.

router

router.post('/login', [
  body('mobno')
    .exists().withMessage('Required')
    .isLength({ min: 10, max: 12 }).withMessage('10-12 characters')
    .isNumeric().withMessage('Numeric'),
  body('password')
    .not().isEmpty().withMessage('Password is required'),
], async (req, res, next) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return res.json({ errors: errors.array(), success: false, msg: 'Check Parameters' });
  }
 // do stuff and respond
});

response

{
  "errors": [
    {
      "value": "998716***658()",
      "msg": "10-12 characters",
      "param": "mobno",
      "location": "body"
    },
    {
      "value": "998716***658()",
      "msg": "Numeric",
      "param": "mobno",
      "location": "body"
    }
  ],
  "success": false,
  "msg": "Check Parameters"
}

In the frontend, I am using Vuetify, hence I need the resonse to be in a format which can easily be consumed by the frontend.

Expected output

{
  "errors": {
    "mobno": [
      "10-12 characters",
      "Numeric"
    ]
  },
  "success": false,
  "msg": "Check Parameters"
}

Question

  1. Is there any option/function which I can hook into which will format the errors in the way I want it.
  2. I am thinking to use Lodash for this transformation, any suggestions on how can this be achieved?

Solution

  • You can use a lodash chain to group the errors by the param, and then map the items in each group to the msg property. Then you can combine the errors object with the previous result using object spread.

    const data = {"errors":[{"value":"998716***658()","msg":"10-12 characters","param":"mobno","location":"body"},{"value":"998716***658()","msg":"Numeric","param":"mobno","location":"body"}],"success":false,"msg":"Check Parameters"}
    
    const errors = _(data.errors)
      .groupBy('param')
      .mapValues(group => _.map(group, 'msg'))
      .value()
      
    const result = {
      ...data,
      errors
    }
    
    console.log(result)
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.14/lodash.js"></script>

    And a pipeline approach using lodash/fp and _.flow():

    const { flow, groupBy, mapValues, map } = _
    
    const transform = flow(
      groupBy('param'),
      mapValues(map('msg'))
    )
    
    const data = {"errors":[{"value":"998716***658()","msg":"10-12 characters","param":"mobno","location":"body"},{"value":"998716***658()","msg":"Numeric","param":"mobno","location":"body"}],"success":false,"msg":"Check Parameters"}
      
    const result = {
      ...data,
      errors: transform(data.errors)
    }
    
    console.log(result)
    <script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>