9

Say there are 2 router.route(), for example:

router.route('/app/:id').get(funtion(req, res, next){
    console.log("id route")
});

and

router.route('/app/:username').get(funtion(req, res, next){
    console.log("user route")
});

When GET /app/nsuzuki is called, which router.route() does it use and why?

Chris Anderson
  • 8,305
  • 2
  • 29
  • 37
NathanSuzuki
  • 157
  • 2
  • 8

1 Answers1

14

To fully understand this, please read the documentation: http://expressjs.com/api.html#router.METHOD

How Express Routes Capture Paths

When you use a :param as a part of your path, it matches everything like /*, and the captured value is stored in req.params.param.

When you have more than one rule, the first one registered is the first one checked against. It checks each call against each rule until a match is found. If you call next() with no values passed to it, it will look for the next match (either in the same route, or continue on into the next middleware).

So these three rules will all be run

var handleRoute = function(req, res, next){
   console.log(req.path + ' ' + req.params.id + ' ' + req.params.user + ' ' + req.params[0]);
   next();
}

route.route('/user/:id').get(handleRoute);
route.route('/user/:user').get(handleRoute);
route.route('/user/*').get(handleRoute);

When I request /user/foobar, I'll see the following output (and probably an error as a client because I never responded :P)

/user/foobar foobar undefined undefined
/user/foobar undefined foobar undefined
/user/foobar undefined undefined foobar

It will hit all three, but the context is different for each.

How to Capture Path Patterns with Regular Expressions

If you want to capture separate routes for id (let's say all numbers) and user name (all letters), you can do this:

var handleRoute = function(tag) {
  return function(req, res, next) {
    console.log(tag + ' ' + req.path + ' -> ' + req.params[0]);
    res.status(200)
      .json({
        success: 'yay!'
      });
  };
};

route.route(/^\/user\/([0-9]+)$/i)
  .get(handleRoute('id'));
route.route(/^\user\/([A-Za-z]+)$/i)
  .get(handleRoute('user'));
route.route('/user/*')
  .get(handleRoute('catch all'));

Note the parathesis around my capture group. Without this, params is empty. It auto captures with just * in the string because they are nice folks. I'll get the following for output when I run against the three different types.

id /user/123 -> 123
user /user/user -> user
catch all /user/user.1 -> user.1

All that explained, you're opening yourself up to some vectors for bugs to infest your system. Might want to think about your URL pattern.

Chris Anderson
  • 8,305
  • 2
  • 29
  • 37
  • thanks for the great help Chris :) I really appreciate it – NathanSuzuki Jul 26 '15 at 03:20
  • No problem. Express has a lot of functionality that can be initially confusing, but it's actually just a matter of deconstructing how the pipeline works. Always fun to just implement all the examples from the docs if you want to learn how the ins and outs work. – Chris Anderson Jul 26 '15 at 03:26