So yeah, you’re about to start using Connect or Express and you’re super excited because:

But then you stop and wonder, “What is middleware?” I remember when I started using Connect/Express, I found it hard to find a straight to the point answer to that question, so hopefully this will help anyone else confused.

In vanilla Node.js you could create a server like this:

var http = require('http');
var server = http.createServer(function(req, res){
  res.end('Hello World!');
});
server.listen(3000);

The function provided as a callback to http.createServer() controls how every request is handled. In this case, the server always sends back “Hello World!”.

Let’s look at the same code in Connect:

var connect = require('connect');
var app = connect();
app.use(function(req, res){
  res.end('Hello World!');
});
app.listen(3000);

It looks very similar to before, except instead of passing our callback that sends “Hello World!” to http.createServer() we pass it to app.use(). You might not have realized it, but our hello world function is now… middleware!

Functions = Middleware

The abstraction that the app variable we created provides for us is letting us specify a series of steps that requests should go through until a response is returned to the user or an error is thrown (and hopefully handled).

Specifically app.use lets us specify functions for the request to flow through. Each regular middleware function passed to app.use() has three parameters: req, res, and next. The next function is a special function that when called moves on to the next function defined as middleware. If you don’t plan to call another middleware function, you can omit the next argument.

var connect = require('connect');
var app = connect();

function uselessMiddleware (req, res, next) {
  console.log('first middleware');
  next();
};

function helloWorld (req, res) {
  console.log('second middleware');
  res.end('Hello World!');
};

app.use(uselessMiddleware);
app.use(helloWorld);
app.listen(3000);

The request first goes through the uselessMiddleware() (which does nothing), logs ‘first middleware’, and then calls next() which moves on to helloWorld. helloWorld() logs ‘second middleware’ and then returns ‘Hello World!’ as a response.

Be careful about the order of your middleware! What would happen if you switched the order?

app.use(helloWorld);
app.use(uselessMiddleWwre);

You would get ‘second middleware’ on your console and a page that says “Hello World!” and that’s it. The second middleware wouldn’t be called because helloWorld already returns the response / never calls next().

Error-Handling Middleware

What if an error occurs in one of your middleware? You can specify error-handling middleware to take care of that by creating functions that use the parameters: err, req, res, and next.

Let’s imagine you have a website in which you only want to display pages to users who are logged in.

var connect = require('connect');
var app = connect();

function authentication (req, res, next) {
  console.log('first middleware');
  // Pretend we have some loggedIn function
  var authenticated = loggedIn(req);
  if (!authenticated) return next(Error('You must be logged in'));
  next();
};

function helloWorld (req, res) {
  console.log('second middleware');
  res.end('Hello World!');
};

function errorHandler(err, req, res, next) {
  res.end(err.message);
}

app.use(authentication);
app.use(helloWorld);
app.use(errorHandler);
app.listen(3000);

In the above code, if the user isn’t logged in next() is called with an error as the argument. Whenever next is called with an error, Connect skips over regular middleware and looks for the next error handler. So when the user isn’t authenticated, helloWorld() never gets called and Connect goes straight to errorHandler() and displays the message “You must be logged in” to the user.

Hopefully this answers the question, “What is middleware?” But it doesn’t answer the question, “What can you do with middleware?” Another post on mounting middleware and routing in Express coming soon!

middlewaredoge