Home > Net >  Express: next is not called properly inside a catch after await
Express: next is not called properly inside a catch after await

Time:10-10

I have a very simple route

router.get('/', async (req, res, next) => {
  try {
    const allEmployees = await employees.find({});
    res.json(allEmployees);
  } catch (error) {
    next(error);
  }
});

It works ok. But after I refactored it with catch. it stopped working and threw UnhandledPromiseRejectionWarning:

router.get('/', async (req, res, next) => {
  const allEmployees = await employees.find({}).catch(next)
  res.json(allEmployees);
});

It seems like the next is not called correctly in the second version. But Both should be equivalent in JavaScript. not sure why the second one is broken in Express.

CodePudding user response:

Both should be equivalent in JavaScript

No, they are not.

Promise.prototype.catch() returns a new promise that resolves with the return value of the callback. Since next() returns void, this code...

employees.find({}).catch(next)

returns a successful promise, resolving with undefined. next() will be called with the failure but there's nothing stopping the rest of your code from calling res.json(undefined).

If you want to use the Promise prototype methods, the equivalent would be

router.get('/', (req, res, next) => {
  employees.find({}).then(res.json).catch(next);
});

If you wanted to keep using async / await and have the eventual promise fail, you'd need something like this

router.get("/", async (req, res, next) => {
  const allEmployees = await employees
    .find({})
    .catch((err) => Promise.reject(next())); // rejected result
  res.json(allEmployees);
});
  • Related