Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

control order of express/connect middleware

I'm trying to add authentication middleware that should prevent access to part of the site:

app = express()
    .get('/api/test', function (req, res) { ... })
    .use('/api', function (req, res, next) {
        if (req.param('key')) {
            next();
        } else {
            res.json(401, {
                message : 'Authentication failed'
            });
            res.end();
        }
    })
    .get('/api/data', function (req, res) { ... });

And my expectation that calls to the /api/data will be first processed by the key checker and then (if it is successful) by the /api/data handler. But instead the request processed by the '/api/data' first.

It seems that the checker works for the /api/something_that_does_not_exist, but not for /api/something_that_exist.

Maybe I missed something in express/connect documentation?

Update I've tracked this up to the fact that the first get/post call initializes the router middleware so it is executed first.

like image 766
Alex Netkachov Avatar asked Apr 12 '13 13:04

Alex Netkachov


1 Answers

Once you declare a route, Express inserts the router middleware into the middleware stack at that point in setting up the app.

In your case, because you insert .get('/api/test', ...) before you insert your key checking middleware, the router middleware gets inserted and will take precedence (also for the /api/data route you declare later) and your key checker is never called.

Here are two solutions:

// separate middleware, used for all routes that need checking
var keyChecker = function(req, res, next) {
  ...
};
app.get('/api/test', function(req, res) { ... });
app.get('/api/data', keyChecker, function(req, res) { ... });

// or, as an alternative, create a 'catch-all' route between the routes that don't
// need to be checked, and the ones that should; this will also match non-existing
// routes (like '/api/foobar'), which might or might not be an issue;
app.get('/api/test', function(req, res) { ... });
app.all('/api/*', function(req, res, next) { // 'all' means 'all methods'
  // keychecker code
});
app.get('/api/data', function(req, res) { ... });

A third solution could be to explicitly check for /api/test in the key checking middleware itself (req.path === '/api/test'), and just call next() if it matches.

like image 185
robertklep Avatar answered Oct 26 '22 11:10

robertklep