javascriptnode.jsexpresscoffeescriptmiddleware

Exclude route from express middleware


I have a node app sitting like a firewall/dispatcher in front of other micro services and it uses a middleware chain like below:

...
app.use app_lookup
app.use timestamp_validator
app.use request_body
app.use checksum_validator
app.use rateLimiter
app.use whitelist
app.use proxy
...

However for a particular GET route I want to skip all of them except rateLimiter and proxy. Is their a way to set a filter like a Rails before_filter using :except/:only?


Solution

  • Even though there is no build-in middleware filter system in expressjs, you can achieve this in at least two ways.

    First method is to mount all middlewares that you want to skip to a regular expression path than includes a negative lookup:

    // Skip all middleware except rateLimiter and proxy when route is /example_route
    app.use(/\/((?!example_route).)*/, app_lookup);
    app.use(/\/((?!example_route).)*/, timestamp_validator);
    app.use(/\/((?!example_route).)*/, request_body);
    app.use(/\/((?!example_route).)*/, checksum_validator);
    app.use(rateLimiter);
    app.use(/\/((?!example_route).)*/, whitelist);
    app.use(proxy);
    

    Second method, probably more readable and cleaner one, is to wrap your middleware with a small helper function:

    var unless = function(path, middleware) {
        return function(req, res, next) {
            if (path === req.path) {
                return next();
            } else {
                return middleware(req, res, next);
            }
        };
    };
    
    app.use(unless('/example_route', app_lookup));
    app.use(unless('/example_route', timestamp_validator));
    app.use(unless('/example_route', request_body));
    app.use(unless('/example_route', checksum_validator));
    app.use(rateLimiter);
    app.use(unless('/example_route', whitelist));
    app.use(proxy);
    

    If you need more powerfull route matching than simple path === req.path you can use path-to-regexp module that is used internally by Express.

    UPDATE :- In express 4.17 req.path returns only '/', so use req.baseUrl :

    var unless = function(path, middleware) {
        return function(req, res, next) {
            if (path === req.baseUrl) {
                return next();
            } else {
                return middleware(req, res, next);
            }
        };
    };