bitHound Blog

Using Closure to Write Express Middleware

When starting out on a new web application with node, it can be overwhelming with how much there is to learn. Express is a great npm package for running your web server, but there are still many questions surrounding the best way to write code for and with Express. The basic concept of wiring up a route for your app is given in some examples on the Express web site, like this one:

app.get('/example/b', function (req, res, next) {  
  console.log('response will be sent from the next function...');
  next();
}, function (req, res) {
  res.send('Hello from B!');
});

In this example, the first parameter is a string specifying the route to match, and the second two parameters are functions. With Express, you can pass in 1 or more functions in this way, which will act together as ‘middleware’.

The basics of this aren’t intuitive, but simple once you learn them. When a client accesses the route, the functions provided will be called sequentially in the order they appear, with a small caveat (explained below). Each function will automagically be passed three parameters by Express.

  • A ‘req’ object: Contains data and functions regarding the http request from the client
  • A ‘res’ object: Represents the http response which should be sent to the client
  • A ‘next’ function: A “callback” that is actually called to proceed to the next function

Beware: The request from the client demands a response, make sure that under no circumstances in your middleware and final function do you fail to use ‘res’ to send one.

If we wanted to create a middleware that authenticated the request (likely using passport), we might modify the first function like this.

app.get('/example/b', function (req, res, next) {

  if (req.isAuthenticated()) next();
  else res.send(401); // Don't call the next function, just send the response and stop here

}, function (req, res) {
  res.send('Hello from B!');
});

But what if we have more than one route that we want authentication on?
We could always just copy - paste the code…
Let’s come back to that, and talk about ‘closure’ for a moment.

What is a closure?

Closures can be a complex concept, certainly when you look it up on wikipedia, but we’re going to work with a simplified and useful definition here.

Mozilla provides this: Closures are functions that refer to independent (free) variables. In other words, the function defined in the closure 'remembers' the environment in which it was created.

To accomplish this, we will leverage the idea of writing a function, which when called returns a function. Using this strategy can help reduce code duplication, make our code more readable, and give us some other new options as well.

function auth() {  
  return function (req, res, next) {
    if (req.isAuthenticated()) next();
    else res.send(401);
  };
}

app.get('/example/a', auth(), function (req, res) {  
  res.send('Hello from A!');
});
app.get('/example/b', auth(), function (req, res) {  
  res.send('Hello from B!');
});

But why do it this way? We could have just written a named function, and passed it in as the middleware, unexecuted. Well, our closure helps us when and if we want to introduce the concept of some variation within our authentication middleware. We haven’t really leveraged the power or idea of a closured function yet at all.

Let’s say that we have the unrealistic situation of, in some circumstances, only wanting a user with the name Francis to make it through our authentication middleware. We can call ‘auth’ with a name to also validate, for the routes where we want that behaviour.

function auth(name) {  
  return function (req, res, next) {
    if (req.isAuthenticated() && name && req.user.name === name) next();
    else if (req.isAuthenticated() && !name) next();
    else res.send(401);
  };
}

app.get('/example/a', auth(), function (req, res) {  
  res.send('Hello from A!');
});
app.get('/example/b', auth('Francis'), function (req, res) {  
  res.send('Hello from B!');
});

The function returned by ‘auth’ is now a useful closured function, with the value of 'name' encapsulated as it was at the the time ‘auth’ was called.

There is a downside in the sense that we’ve sacrificed a little bit of readability, as code moves out of the context in which it’s called, but we’ve also gained a fair bit of readability, in the route handler calls themselves. Certainly, when you increase the number of middleware functions to three and beyond, having all that code inline at the route handler turns into a readability and indentation nightmare, and also likely leads to duplicate code.

My hope is that you will consider using a closure technique right from the start of writing Express middleware. Believe me, it will save a ton of hassle down the road.

Have any other thoughts on Express middleware? We'd love to hear from you! Just tweet us @bithoundio.

bitHound identifies risks and priorities in your Node.js projects.