Writing Middleware for Express & Node.js

Express is an extremely lightweight web framework for Node.js. It's ideal forquick routing and back end database integration. Many popular frameworks are built on Express, as itremains one of the most popular dependencies in the Node community. Through Express middleware, developersgain more control over the requets made by their web apps. This tutorial explores the basics of Expressmiddleware, from using existing libraries to writing your own middleware functions.

A Basic Express Route

If you've worked with Express at all, then you've probably seen the following syntax:

app.get('/', function(req,res){
res.send('Hello world')
})

The above is a basic GET route. The first parameter defines our route path ('/'). The second is what Express refers to as a middleware function.

What is Middleware?

If you've used this syntax at all to create Express routes, then you are already writing middleware functions. According to Express, middleware functions are those that have access to the request and response objects (req,res) as well as the next middleware function in the request-response cycle. Any time you are rendering a response back to the client (ie. res.send, res.json, res.render), you are writing middleware.

Using Existing Express Middleware

Many extensions already exist for Express. Take the popular express-force-https module. This module checks to see if the current request is over https. If not, the middleware redirects the client to the same route using https. To implement, you would simply include the module and bind it to your express app instance as follows:

var secure = require('express-force-https');
app.use(secure);
app.get('/', function(req,res){
res.send('Hello world')
})

All the app.use clause does is bind the middleware function to your app. It's important to remember that order matters with this example. While our basic GET route includes another middleware function, it comes after the express-force-https function in the request-response lifecycle. If we were to include the app.use clause AFTER we define our route, the middelware would never get called. This is because the route handler terminates the cycle via the res.send function.

Writing Your Own Middleware

Writing your own express middleware is easy. Remember that any middleware function takes three arguments: the request object(req), the response object(res), and the next function.

app.use(function(req,res,next){
console.log(res.statusCode);
next()
})

On the first line, app.use takes your function as a parameter and binds it to the app instance. The following lines prints out the response status code to the console and calls the next function in the request-response cycle. Remember that you must call next() at the end of your function, or you'll be stuck in an infinite loop.

This function is universal. It will be applied to every request made for your app. Whenever a new page is rendered, your server will log the response status code to the console.

Bringing it together: Creating a default 404 Page

By now you understand the basics behind Express middleware. You have experience in both including third party middleware libraries as well as writing your own. You understand that when using Express routes, you are already writing custom middleware for your app. Let's finish with a practical example and return a custom 404 template for any invalid url.

app.get('*', function(req,res){
res.render('404')
})

This defines a GET route for any route that isn't previously defined. A reminder that order matters. Please make sure you've placed this route function last or it will overwrite any existing routes you've defined. In this particular example, we are using EJS as a template engine, however you can render any response you'd like.

Now you should have a custom 404 error response page. You could also use Express error-handling middleware in a similar fashion.

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

Notice the additional err argument. This is the only real difference in writing error-handling middleware. Also note that you would want to catch an error event in another function and pass the error to your 'next()' function for this particular example.

Conclusion

Express middleware gives developers more control over web requests. Middleware works within the routing layer to bridge the gap between a request and its intended route. By writing simple GET routes, you are already writing middleware functions. Furthermore, it's easy to write your own custom middleware for things like error handling and custom rerouting.

Your thoughts?