Error handling in express

In my last post, I gave an introduction to using express to serve up your HTTP content to users. It walked through most of the features needed to get started, but there was one thing that was missing, but still very important, and that is error handling. However good you are at coding, you will get errors. It will obviously not be your fault, but you never know what the user manages to do… ;)

So it is definitely important for us to handle errors in a graceful way. Luckily, this is pretty simple to do… But first, we need to create a simple express-based webserver to work with…

So to get that done, I create a new folder for my app, use npm to install express and add a server.js file that looks like this

var express = require('express');

var app = express();

app.get('/', function(req,resp) { resp.send('Hello World'); });

app.listen(8080);
console.log('Listening on port 8080');

Cool, that’s all that I need to get started!

The next step is to see how I can plug in some form of error handling into the request/response pipe. Luckily, once again, this is not hard. As with anything we want to add to the request/response pipe, we just give express another method using the use() method. In this case, the method takes 4 parameters, the error, the request, the response and a “next” object.

The 4th parameter, the “next” parameter, contains a reference to the next error handler, which indicates just how the error handling works. It works as a pipe of handlers, where the first one is handed the error, and if it can’t handle it, it hands it off to the next one. It then keeps going like this, until the last handler, which handles it by sending back an HTTP 500 and a stack trace.

Ok, let’s try this out! First off, I will create a new path that will throw and exception

...

app.get('/error', function(req,resp) { throw new Error('failure!'); });

...

Ok, now that I have an exception being thrown, let’s see what happens if we request that path

image

...

var app = express();

app.use(function(err, req, resp, next) {
resp.send('Ooops, something went wrong');
});

app.get('/', function(req,resp) { resp.send('Hello World'); });

...

Just as expected, we get a stack trace, so I guess it is time to handle it. I do this by adding a new exception handler to express

 

And then I browse to http://localhost:8080/error. And BOOM!

image

Wait a minute! That is the same error again… My exception handler isn’t working! And this is where it gets a little tricky…

When you pass a function to the app’s use() method, you are adding something called middleware. Middleware is basically functions being run as part of the request/response pipe. The order that these functions are inserted is important as they work in the same way as the error handler, which means that they execute, and then call next to get the request/response through the pipe.

One of those middleware pieces that express uses by default is the “router”. The router is the middleware that is responsible for routing the requests to your request handlers. In other words, it is responsible for finding the correct function to call based on the requested path…

By default, the router is added at the same time as the first route is added. In my case, I happened to add my error handler before I added my first route, which causes problems, as the router won’t know about it.

There are two ways of solving this. Either, I move the error handler registration to after the routes are added, or I manually add the router manually at the beginning…

In this case, I will add the router manually

...

var app = express();
app.use(app.router);

app.use(function(err, req, resp, next) {
resp.send('Ooops, something went wrong');
});

app.get('/', function(req,resp) { resp.send('Hello World'); });

...

If I try to browse to the error path again, I am now face with this

image

Sweet! My error handling works! I now have a very generic handler that catches and handles all exceptions in the same way. Unfortunately, the response code is 200, which means that everything was ok. I really want this to be a 500, as it is a server error. Luckily, the send() method has an overload that takes the response code to use as well, so I just change the handler as follows

...

app.use(function(err, req, resp, next) {
resp.send(500, 'Ooops, something went wrong');
});

...

But what if I want to handle specific error differently? Well, I just add another handler before this one, checking if it is this special case and handler it. And if it isn’t this special case, I just call next(), passing it the error object.

Let’s add a new route that causes a specific error

...

app.get('/specialerror', function(req,resp) { throw new Error('special case'); });

...

And then another error handler to handle this special case

...

app.use(function(err, req, resp, next) {
if (err.message == 'special case')
{
resp.send(500, 'Special case error!');
return;
}
next(err);
});

app.use(function(err, req, resp, next) {
resp.send(500, 'Ooops, something went wrong');
});

...

That’s all there is to it! Browsing to that special error path, I now get this

image

Just a thing to note here is that debugging these handlers can be a bit complicated to us .NET people who can normally just put a breakpoint to see what is going wrong. There are debugging for node as well, but that is a bit outside of the scope of this post. But a couple of well placed console.log() can often help a whole lot…

There is just one more thing I want to highlight in this post… When adding middleware or functions to the request/response pipe, there is an overload that lets you limit which paths will use them. So to get specific error handling for specific paths, one only have to change the way that the use() method is called. Like this for example

...

app.use('/specialcase', function(err, req, resp, next) {
resp.send(500, 'Special case bro!');
});

...

app.get('/specialcase', function(req,resp) { throw new Error('special case'); });

...

Just make sure that the special cases are registered before the more generic ones…

That’s all! Handling error shouldn’t be hard, and it really isn’t in express! So make sure you do it. And you can of course combine error handling with view engines instead of just simple text messages like I did.

Code is available for download here: errorhandling-express.zip (735.00 bytes)

And once again, required modules are not included, so an “npm install” is required…

Cheers!

Add comment