ExpressJS - Error Handling

expressjs

http://thecodebarbarian.com/80-20-guide-to-express-error-handling.html

How should we handle errors?

Error handling is typically used across the whole application, therefore it’s best to implement it as a middleware. It has the same parameters plus one more, error:

app.use(function(err, req, res, next) {
  //do logging and user-friendly error message display
  res.send(500);
})

In fact, the response can be anything. It can be a JSON string:

app.use(function(err, req, res, next) {
  //do logging and user-friendly error message display
  res.send(500, {status:500, message: 'internal error', type:'internal'});
})

It can be a text message:

app.use(function(err, req, res, next) {
  //do logging and user-friendly error message display
  res.send(500, 'internal server error');
})

It can be an error page:

app.use(function(err, req, res, next) {
  //do logging and user-friendly error message display
  //assuming that template engine is plugged in
  res.render('500');
});

app.use(function(err, req, res, next) {
  //do logging and user-friendly error message display
  res.redirect('/public/500.html');
});

It can be an error HTTP response status (401, 400, 500, etc.):

app.use(function(err, req, res, next) {
  //do logging and user-friendly error message display
  res.end(500);
})

How can we trigger an error?

To trigger an error from within your request handlers and middleware you can just call:

next(error);

or

next(new Error('Something went wrong :-(');

Can we have multiple error handlers?

Yes. You can also have multiple error handlers, and use named instead of anonymous functions as its shows in Express.js Error handling guide.

How can we handle 404s?

In Express, 404s are not the result of an error. Therefore, the error-handler middleware will not capture 404s. This is because a 404 is simply the absence of additional work to do; in other words, Express has executed all middleware / routes, and found that none of them responded. All you need to do is add a middleware at the very bottom (below all others) to handle a 404:

app.use(function(req, res, next){
  res.send(404, 'Sorry cant find that!');
});

The above code should be add at the very bottom. The 404 in the above code is just an HTTP response status code. If you do not want to display the string 'Sorry cant find that!', you can replace it with your own HTML or logic that try to suggest appropriate links based on the current request parameters.

If you've done a major restructuring of your site, you may want to log all the 404 into the access log (probably done at the load balancer level), and review your access log on a daily basis for about one week or two weeks after the restructuring so that you can redirect the user to the correct URL. Perhaps you can maintain a table that contains all previously known URL. If you have a 404, you can check against this table. If the URL is used to be known, but now it is a 404, send an email to you so that you can update the code to redirect the user to the right place. If you structure the table of known URLs correctly, you just have to insert a row or update a column, and the code should be able to immediately redirect the users to the right place. This table of known URLs should be small, and should be stored in an in-memory database. Be careful with implementing this functionality, because this can open up security hole, because malicious users or bot can throws a bunch of invalid requests at your server and your server would be busy handling these 404 requests if this feature is not implement appropriately.

How can we setup an error handler?

You define error-handling middleware the same way as other middleware. However, error-handling middleware takes four arguments instead of three; specifically with the signature (err, req, res, next):

app.use(function(err, req, res, next){
  console.error(err.stack);
  res.send(500, 'Something broke!');
});

Where should we define our error-handling middlewares?

By convention you define error-handling middleware last, after other app.use() calls.

Can we have multiple error handlers?

Yes. For organizational (and higher-level framework) purposes, you may define several error-handling middleware, much like you would with regular middleware.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License