Middleware in Express applications

If you have recently moved or are thinking of moving to the nodejs Express framework than you should primarily get acquainted with its routing and middleware concepts, as an Express application is essentially a series of middleware function calls. Middlewares in Express are functions executed after the incoming request from the client, the middleware then processes the request depending on its purpose and then hands over the request to the next middleware in the chain or generates a output if is the last one in the chain, terminating the request-response cycle.

Middleware in a nutshell

Middleware are functions that primarily work with the two main objects in an Express application – the request object (req) and the response object (res). It also has access to the ‘next‘ function which is the function next in the application’s request-response cycle. The next function is a function in the Express router which, when invoked, executes the middleware succeeding the current middleware.

Middleware functions primarily perform the following tasks:

a. Execute code.
b. Make changes to the request and/or the response objects.
c. End the request-response cycle, or
d. Call the next middleware in the stack using next().

If the current middleware function does not end the request-response cycle, it must call next() to pass control to the next middleware function. Otherwise, the request will be left hanging without anything to do further.

An example

Take the following basic Express application which has the singular job of printing ‘Hello World!’ in the browser.

var express = require('express');
var app = express();
 
app.get('/', function (req, res) {
  res.send('Hello World!');
})
 
app.listen(3000);

Now what we want to do is log all urls along with their access times to the console. Rather than adding the code to the ‘get’ route we can create a middleware which allows us to do that without messing around with existing code.

var express = require('express');
var app = express();
 
/* url logger middleware */
var urlLogger = function (req, res, next) {
  console.log(Date(Date.now()) + " : " + req.url);
  next();
}
 
app.use(urlLogger);
 
app.get('/', function (req, res) {
  res.send('Hello World!');
})
 
app.listen(3000);

Now each time we request the web application the url of the request is logged in the console, along with the time as shown below.

Tue Jan 15 2019 14:05:34 GMT+0530 (GMT+05:30) : /welcome

Middleware cautions

Note the next() function call at the end of the above urlLogger middleware. This essentially hands over the request to the next middleware in the chain. If this is accidentally omitted then the application will have nothing to handover the request further to and will keep waiting. In our above example the urlLogger middleware will hand over the request to the next in line – the ‘get’ route. As you can see the ‘get’ route does not have the next() call which basically means this is the last middleware in the chain.

Note: The order of middleware loading is important – middleware functions that are loaded first are also executed first. If urlLogger is loaded after the route to the root path in our example, the request never reaches the ‘get’ route and the app doesn’t print the url details, because the route handler of the root path terminates the request-response cycle.

If we define the middleware later then the middleware will not be executed on the request.

/* url logger middleware will not be executed on the following 'get' request
   as it is defined later.
 */
app.get('/', function (req, res) {
  res.send('Hello World!');
})
 
app.use(urlLogger);

As we have defined urlLogger on global app basis, this middleware will be executed on all app requests or routes. You can use the urlLogger middleware on select routes by removing the following line which defines it on a global basis.

app.use(urlLogger);

And specifying the middleware in the route as required. Lets us say we need to only log requests to the ‘/welcome’ route. The following will accomplish the same.

app.get('/welcome', urlLogger, function (req, res) {
  res.send('Welcome!');
})

Note that we can name the ‘next’ function anything, but keep it consistent throughout your application. I prefer ‘next’ as this is the official convention. Below we have name it ‘done’.

var urlLogger = function (req, res, done) {
  console.log(Date(Date.now()) + " : " + req.url);
  done();
}

In conclusion

There are many third-party middlewares that will help you to build your Express application. A commonly used is ‘body-parser‘ – a middleware that parses incoming request bodies in a middleware before your handlers and which is available under the ‘req.body’ property.

In the next post we will see more on how to define Express middleware for various routes.