I have an async
middleware in express, because I want to use await
inside it, to clean up my code.
const express = require('express'); const app = express(); app.use(async(req, res, next) => { await authenticate(req); next(); }); app.get('/route', async(req, res) => { const result = await request('http://example.com'); res.end(result); }); app.use((err, req, res, next) => { console.error(err); res .status(500) .end('error'); }) app.listen(8080);
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.
app.get('/route', (req, res, next) => { throw new Error('Error'); res.end(result); });
So I'm getting UnhandledPromiseRejectionWarning
instead of entering my error handling middleware, how can I let the error bubble up, and express handle it?
The error handling middleware are defined in the same way as other middleware functions, except that error-handling functions MUST have four arguments instead of three – err, req, res, next. For example, to send a response on any error, we can use − app.
Async MiddlewareA handy tool to write async/promise style middleware for express, connect-like.
To recap: Throwing error from an async function won't spit out a "plain exception". Async functions and async methods always return a Promise, either resolved or rejected. To intercept exceptions from async functions you must use catch() .
Error Handling refers to how Express catches and processes errors that occur both synchronously and asynchronously. Express comes with a default error handler so you don't need to write your own to get started.
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
Well, I found this - https://github.com/davidbanham/express-async-errors/, then require the script and you are good to go
const express = require('express'); require('express-async-errors');
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With