The problem is that when it rejects, it doesn't go to my error
middleware, but if I remove the async keyword and throw inside a
middleware it does.
express
doesn't support promises currently, support may come in the future release of [email protected]
So when you pass a middleware function, express
will call it inside a try/catch
block.
Layer.prototype.handle_request = function handle(req, res, next) {
var fn = this.handle;
if (fn.length > 3) {
// not a standard request handler
return next();
}
try {
fn(req, res, next);
} catch (err) {
next(err);
}
};
The problem is that try/catch
won't catch a Promise
rejection outside of an async
function and since express
does not add a .catch
handler to the Promise
returned by your middleware, you get an UnhandledPromiseRejectionWarning
.
The easy way, is to add try/catch
inside your middleware, and call next(err)
.
app.get('/route', async(req, res, next) => {
try {
const result = await request('http://example.com');
res.end(result);
} catch(err) {
next(err);
}
});
But if you have a lot of async
middlewares, it may be a little repetitive.
Since I like my middlewares as clean as possible, and I usually let the errors bubble up, I use a wrapper around async
middlewares, that will call next(err)
if the promise is rejected, reaching the express error handler and avoiding UnhandledPromiseRejectionWarning
const asyncHandler = fn => (req, res, next) => {
return Promise
.resolve(fn(req, res, next))
.catch(next);
};
module.exports = asyncHandler;
Now you can call it like this:
app.use(asyncHandler(async(req, res, next) => {
await authenticate(req);
next();
}));
app.get('/async', asyncHandler(async(req, res) => {
const result = await request('http://example.com');
res.end(result);
}));
// Any rejection will go to the error handler
There are also some packages that can be used