Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to catch unhandled Promise rejections in a Restify middleware?

I'm writing a Restify application on Node.js. And I need to have a function that is called when some errors inside Restify callbacks are happening. This function should send a response to a client. If I'm not using Promises or async functions, I can do something like that:

server.on('uncaughtException', (req, res, route, err) => {
  log.error(err);
  res.send(err);
});

But if my callback is async function, then the exception inside a function isn't called, and unhandledPromiseRejection is raised instead.

How can I refactor my code so it would handle unhandled Promise rejections the same way it handles usual errors?

And yes, I know that I can check for errors inside a Restify middleware itself, but still it makes the code more complicated, it's easier to write

if (!core.validateUUID(req.params.deviceId)) {
  throw new Error(`Device ${req.params.deviceId} is wrong`)
}

then

if (!core.validateUUID(req.params.deviceId)) {
  return next(new restify.InvalidArgumentError({ body: {
    success: false,
    error: `Device ${req.params.deviceId} is wrong`,
  } }));
}
like image 744
serge1peshcoff Avatar asked Nov 07 '22 23:11

serge1peshcoff


1 Answers

I was struggling with this for a while and I came up with a simple solution. I created a simple wrapper function, that wraps the route handlers/middlewares and runs the code inside a promise. That way, unhandled rejections and uncaught exceptions can be handled is same callback:

// your error general handler
function errorResponse(req, res, err) { ... }

/**
 * When using promises inside handler, you need to return the Promise from it to allow proper rejection handling
 *
 * @param {Function} callback with `req`, `res` and `next` parameters
 * @returns {Function}
 */
function catcher(callback) {
  return (req, res, next) => {
    Promise
      .resolve()
      .then(() => callback(req, res, next))
      .catch(err => errorResponse(req, res, err));
  };
}

// use it like this
server.use(catcher(middleware1));
server.post(catcher(postRoute));
server.get(catcher(getRoute));

When using promises inside your handler, you need to return the Promise from it to allow proper rejection handling.

like image 161
Martin Adámek Avatar answered Nov 14 '22 21:11

Martin Adámek