Nisanth Sojan
Nisanth Sojan

Reputation: 1099

always run a middleware in expressjs

i want an expressjs middlware to be executed always. That is even if there is an error in the next() or not.

is it possible?

example

app.get('/',[middle1,middle2],doIt)

the middle2 should always execute even if the middle1 executes next with error.

NOTE: the middle2 should always execute last and takes the values calculated by the previous middlewares. also there are lot of middlewares between middle1 and middle2.

Upvotes: 1

Views: 1289

Answers (2)

takinola
takinola

Reputation: 1763

Assuming you do not care about the order of execution, you can simply have function middle2 execute inside app.use.

app.use(middle2);

app.get('/pathx, middle1, middle3, doIt);

middle2 will always be executed on every request. However, middle2 will execute before any of the other middleware

If you require middle2 to execute last in sequence, then a simple modification using the async module should accomplish what you want

async = require('async');

function middleware(req, res, next){
    var functionList = [middle1, middle3];

    async.series(functionList, function(err, results){
        if(err){
            middle2(req, res, next);
            next(err);
        }

        middle2(req, res, next);
        next();
    }
}


app.get('/pathX', middleware, doIt);

Upvotes: 0

jfriend00
jfriend00

Reputation: 707158

If middle1 is known to not use any async operations from which it calls next(), then you can wrap it and put a try/catch around it so that if it throws, you can just call next() on its behalf.

If it does use async operations or you don't know if it will use async operations, then you will only catch its exceptions if it throws synchronously (before it goes async) and you will not be able to catch any exceptions that it throws asynchronously. About the best you could do for async behavior is to set some sort of timeout in your wrapper. If it hasn't called next() within some period of time (either because it threw an exception or just failed in some other weay), then you call next after the timeout period.

Wrapping a non-async middle1 could look like this:

function wrap(fn) {
    return function(req, res, next) {
        var nextCalled = false;
        try {
            fn(req, res, function() {
                nextCalled = true;
                next();
            });
        } finally {
            if (!nextCalled) {
                next();
            }
        }
    }
}

app.get('/',[wrap(middle1),middle2],doIt);

The wrap() function inserts a stub as the middleware function. That stud inserts its own next() function so it can tell if the actual middleware function calls next() or not. It then wraps an exception handler around the middleware function so if it throws an exception synchronously, then it can recover. After the function returns, it checks to see if next() was called and, if not, it calls it.

As explained earlier this approach only works if the middleware function is synchronous.

Upvotes: 1

Related Questions