Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NodeJS Express nested input body object validation

I have some trouble validating my nested object request body with "express-validator" package. Let's say we have a method to collect user input with a body like this :

{
    "general": {
        "sessionId": "a2957207-e033-49e7-b9da-1c5f946a1074",
        "os": "android",
        "vendor": "htc"
    },
    "data": [
        {
            "target": "logPageVisits",
            "pageName": "users/packages",
            "engagementTime": 350
        }
    ]
}

express-validator only offers validation like this :

req.checkBody('engagementTime')
        .notEmpty()
        .withMessage('Engagement-Time is required')

It seems there's no clean way to validated nested objects like this :

req.checkBody('data.engagementTime')
        .notEmpty()
        .withMessage('Engagement-Time is required')

I've found an closed issue on Github! but it doesn't fulfill my concerns!

Any better suggestions?

like image 407
Armin Abbasi Avatar asked Jan 23 '19 14:01

Armin Abbasi


3 Answers

You can always create your custom middleware for express.
For example, in your case, very simplified it would look like this:

const checkNestedBodyMiddleware = (req, res, next) => {
  const { data } = req.body;

  // As I see, here is array in data, so we use simple find
  const engTimeInArr = data.find(d => d.engagementTime);

  if(!engTimeInArr){
    return res.status(400).send('Engagement-Time is required');
  }

  next();
}

And then use it in your route:

app.post('/some-route', checkNestedBodyMiddleware, (req, res) => {
   // your route logic here.
})

So, in this case you hide validation logic in middleware and can assign any number of middlewares to route.

like image 63
Grynets Avatar answered Nov 15 '22 03:11

Grynets


Use .*. for iterating this

req.checkBody('data.*.engagementTime')
         .notEmpty()
         .withMessage('Engagement-Time is required')
like image 33
Prakhar Goel Avatar answered Nov 15 '22 04:11

Prakhar Goel


I am a bit late, but here is what you can do as of v6.12.0. To validate a schema, you can use checkSchema method:

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

checkSchema({
  'general': {
    in: 'body', // the location of the field
    exists: {
      errorMessage: 'Field `general` cannot be empty',
      bail: true
    },
    isObject: {
      errorMessage: 'Field `general` must be an object',
      bail: true
    }
  },
  // to check a nested object field use `object.nestedField` notation
  'general.sessionId': {
    trim: true,
    isString: {
      errorMessage: 'Field `sessionId` must be a string',
      bail: true
    }
  },
  'data': {
    in: 'body', 
    exists: {
      errorMessage: 'Field `data` cannot be empty',
      bail: true
    },
    isArray: {
      errorMessage: 'Field `data` must be an array',
      bail: true
    }
  },
  // use `*` to loop through an array
  'data.*.engagementTime': { 
    notEmpty: {
      errorMessage: 'Field `engagementTime` should not be empty',
      bail: true
    }
  }
})

References:

  • Express Validator: Schema Validation
like image 43
Seid Akhmed Agitaev Avatar answered Nov 15 '22 03:11

Seid Akhmed Agitaev