'Express middleware - add promise rejection handlers

I have the following simplified middleware function:

router.put('/', function (req, res, next) {

  const data = req.body;
  const q = req.parsedFilterParam;
  const opts = req.parsedQueryOpts;

  ResponseCtrl.update(q, data, opts)
  .then(stdPromiseResp(res))
  .catch(next);
});

I want to add some ability to catch errors to the middleware, just to save some code, something like this:

router.put('/', function (req, res, next) {

  const data = req.body;
  const q = req.parsedFilterParam;
  const opts = req.parsedQueryOpts;

  return ResponseCtrl.update(q, data, opts)
  .then(stdPromiseResp(res));

});

so we now return the promise in the middleware function, and we can forgo the catch block.

so internally, it might look like this now:

nextMiddlewareFn(req,res,next);

just looking to change it to:

const v = nextMiddlewareFn(req,res,next);
if(v && typeof v.catch === 'function'){
   v.catch(next);
});

does anyone know how to do this with Express?



Solution 1:[1]

Use express promise router.

var router = new ExpressPromiseRouter();

router.get('/foo', function(req, res) {
  return somethingPromisey();
});
// or...
router.get('/bar', async function(req, res) {
  await somethingPromisey();
});

app.use(router);

PS: There's no need to be afraid of async/await on performance grounds. There is no appreciable difference vs regular functions with promises.

Solution 2:[2]

You may also want to try the general purpose solution: asyncback.

For usage in ExpressJS middle-ware:

const asyncback = require('asyncback');
 
app.get('/users', asyncback(async (req, res) => {
    const users = await User.find({ 'banned': false });
    const offer = await Offers.findOne({ 'active': true });
    res.json({ 'users': users, 'offer': offer });
}));

When the async function returns or throws, the next callback passed by express to asyncback is automatically called accordingly.

Solution 3:[3]

Note to the reader, the following actually doesn't work:

router.put('/', async function (req, res, next) {

  const data = req.body;
  const q = req.parsedFilterParam;
  const opts = req.parsedQueryOpts;

  await ResponseCtrl.update(q, data, opts)
  .then(stdPromiseResp(res));

});

if the promise is rejected, the try/catch that surrounds each piece of middleware won't actually pick it up, if the promise is rejected, it will bubble up to an unhandledRejection handler if there is one.

I would look forward to a good solution though which:

  1. could be typed with TypeScript
  2. doesn't use async/await.

This is the solution that worked best for me as of now:

https://medium.com/@the1mills/hacking-express-to-support-returned-promises-in-middleware-9487251ca124

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 josh3736
Solution 2
Solution 3