Search code examples
restexpressroutermiddleware

Router-level middleware order using Express.js


I have the following routers:

/* GET /users/username */
router.get("/:username", function(req, res, next) {
  User.findOne({
    username: req.params.username
  }).exec(function(err, user) {
    if (err) return next(error);
    res.json(user);
  });
});

/* GET /users/id */
router.get("/:id", function(req, res, next) {
  User.findById(req.params.id, function(err, user) {
    if (err) return next(err);
    res.json(user);
  });
});

In the above order, /* GET /users/id */ will return null, and if I swap the order the /* GET /users/username */ will result in this error:

Cast to ObjectId failed for value "Guest" at path "_id" for model "User"

Basically, the second middleware is being ignored. However, both are needed for different behaviors. I'm using AngularJS $resource to interact with RESTful server-side data sources.

  1. Why can't I use both simultaneously? Why is the second middleware ignored?
  2. In which order should these two routers be to both working?

Solution

  • The second middleware is ignored, because the url pattern is the same... How do you want the router make the differenciation between an 'username' or an 'id';

    You've got to check if it's an id first per exemple.

    router.get("/:username", function(req, res, next) {
      const username = req.params.username;
      if (!isNaN(parseInt(username)) {     // <------ Check if it's an ID
         next();
      } else {
      User.findOne({
        username: req.params.username
      }).exec(function(err, user) {
        if (err) return next(error);
        res.json(user);
      });
       }
    });
    
    /* GET /users/id */
    router.get("/:id", function(req, res, next) {
      User.findById(req.params.id, function(err, user) {
        if (err) return next(err);
        res.json(user);
      });
    });