Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling errors in express async middleware

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?

like image 579
Marcos Casagrande Avatar asked Jul 17 '18 22:07

Marcos Casagrande


People also ask

What is error handling middleware?

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.

Can Express middleware be async?

Async MiddlewareA handy tool to write async/promise style middleware for express, connect-like.

What happens when async function throws error?

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() .

How does error handling work in Express JS?

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.


2 Answers

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

  • async-middleware
  • express-async-handler
like image 199
Marcos Casagrande Avatar answered Sep 24 '22 01:09

Marcos Casagrande


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'); 
like image 27
ama Avatar answered Sep 24 '22 01:09

ama