Express Router param validation

The express 4x api docs claim that you can pass regex as a second argument to router.param in order validate params.

The method could now be used to effectively validate parameters (and
optionally parse them to provide capture groups)

It then provides the following examples.

// validation rule for id: should be one or more digits
router.param('id', /^\d+$/);

router.get('/user/:id', function(req, res) {
  res.send('user ' + req.params.id);
});

// validation rule for range: should start with one more alphanumeric characters, followed by two dots, and end with one more alphanumeric characters
router.param('range', /^(\w+)\.\.(\w+)?$/);

router.get('/range/:range', function(req, res) {
  var range = req.params.range;
  res.send('from ' + range[1] + ' to ' + range[2]);
});

But, this doesn’t actually seem to work. Taking a deeper dive, it doesn’t look as if the express code actually supports what the docs claim. In fact, passing anything other than a function will get you a tidy invalid param() call exception.

Using

express 4.12.3
node 0.12.4

So my question is whether this functionality actually exists or if I’m doing something wrong. I’m trying to accomplish the same thing provided in the doc but am receiving the error mentioned above. Any guidance would be greatly appreciated 🙂

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

The answer can be found here.

Essentially the following snippet would need to be run prior to leveraging the router.param(fn) method as outlined above if you’re using express <= 4.11.

express 4.11

router.param(function(name, fn) {
  if (fn instanceof RegExp) {
    return function(req, res, next, val) {
      var captures;
      if (captures = fn.exec(String(val))) {
        req.params[name] = captures;
        next();
      } else {
        next('route');
      }
    }
  }
});

express 4.12

If you’re using express >= 4.12 you can accomplish the same without the need of router.param(fn) using the following. In fact, the pre 4.12 example above will pop a deprecation warning.

app.get('/user/:userId([0-9]+)', fn);

While this is stated in the doc, it isn’t quite clear.
Hope this helps.

Solution 2

I was facing the same issue and I got it resolved by converting my code

exports.customerValidator = () => {
    return [
        body("name").trim().toString(),
        body("email")
          .isEmail()
          .withMessage("Please enter a valid email id")
          .custom((value, { req }) => {
            return Customer.findOne({ email: value })
              .then((customer) => {
                if (customer) {
                  return Promise.reject("E-mail address is already exists!");
                }
              })
          })
          .normalizeEmail(),
        body("address").trim().toString(),
        body("city").trim().toString()
    ]
}

to this:

exports.customerValidator = () => {
    return [
      body('name').trim(),
      body("email")
        .isEmail()
        .normalizeEmail()
        .custom((value, { req }) => {
          return Customer.find({ email: value })
            .then((customer) => {
              if (customer) {
                return Promise.reject("E-mail address is already exists!");
              }
            })
        }),
      body("address").trim(),
      body("city").trim(),
    ];
  };

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply