exit from chain of route specific middleware in express/ nodejs

bguiz picture bguiz · Jun 21, 2013 · Viewed 10.8k times · Source

I have a chain of "route specific middleware" for this route, like so:

    var express = require('express');
    var server = express();
    var mw1 = function(req, resp, next) {
        //do stuff
        if (success) {
            next();
        } else {
            req.connection.destroy(); //without calling next()
        }
    };
    var mw2 = function(req, resp, next) {
        //do stuff
        if (success) {
            next();
        } else {
            req.connection.destroy(); //without calling next()
        }
    };
    server.post('/some/path', [mw1, mw2], function(req, resp) {
        //write response
    });

[mw1, mw2] are the middleware specific to the route /some/path.

This is different from server-wide middleware like this:

    server.use(mw1);
    server.use(mw2);

Where it applies to all routes defined.

Now my issue is that I want to exit from the chain. I.e. if success is false in mw1, I do not wish for mw2 to be called. If success is false in mw2, I do not without for the route function to be called. Presently, both mw1 and mw2 appear to be getting called whether or not next() is called - and I do not know why.

How can I go about doing this?

Answer

laconbass picture laconbass · Jun 21, 2013

You can call next( 'route' ), as said on the express api reference, application routing section:

Multiple callbacks may be given, all are treated equally, and behave just like middleware, with the one exception that these callbacks may invoke next('route') to bypass the remaining route callback(s).

Example

var express = require('express')
  , app = express()
;

// keep an eye on the function names
app.post( '/some/path', middleware1, middleware2, function route1( req, res, next ) {
      // write response
});
app.all( '*', function route2( req, res, next ) {
    // do something like handle a 404 request
});
app.use(function errorHandler( err, req, res, next ) {
    // handle error
});

function middleware1( req, res, next ) {
    // ...
    if ( !success ) {
        // bypasses middleware2 and route1, route2 will be called
        return next( 'route' );
    }
    // calls middleware2
    next();
}
// intentionally similar to middleware1 to keep things clear
function middleware2( req, res, next ) {
    if ( !success ) {
      // bypasses route1 and route2
      // errorHandler will be called with the error
      return next( Error( 'middleware 2 failed' ) );
    }
    // calls route1
    next();
}