This Express Middleware Tutorial explains all, a developer must know about middleware with respect to Express.js. It’s covering all major concepts related to a middleware along with practical examples and explaining different middleware types in details. Undoubtedly Express.js plays key role for a MEAN Stack Application as a middleware, so finally explaining on how to develop our own custom middleware in Express.js?
Let’s dive deeper starting with understanding what a middleware is in general.
What is Middleware?
Express app is usually a web framework consists of middleware and router. Therefore, an express application works through a series of middleware functions.
Middleware is:
- One or a series of callback function that sits on top of the actual request handler and have the exactly same parameter as actual request.
- A series of functions are invoked by the router layer of express app before the final request handler.
- A series of functions those are invoked in order. This means the order in which they are written/included in a server.js file, are the order in which they are executed, given that the route matches.
- A function that receives the request and response objects of an HTTP request/response cycle.
- A function that can modify the request or response object before sending them to next middleware function in the series.
- It may update the response object or discontinue the chain if necessary.
- A function with a signature of (req, res, next), for example:
1234function logger(req,res,next){console.log(new Date(), req.method, req.url);next();}
Here in this example, the next() continue the chain of the series of functions known as middleware. next is the third parameter in the middleware function and need to be explicitly called at the end of the operation executed inside the function as, express has no way to understand when the function has come to end of execution of current operation and the next method in the series need to be invoked, therefore, next() method need to be called.
The following image can explain a middleware code:
What Middleware does?
Middleware functions can be used in order to perform the following tasks:
- Execute any operation coded in the method.
- Update the request and the response objects.
- End the request-response cycle. For example, if there is any exception is thrown, instead of calling the next method in the series of middleware, it can end the chain.
- As middleware in express is usually a series of methods / functions. Middleware is responsible to call the next middleware function in the series.
- The flow of middleware could be as following:

Types of Middleware?
- Application-level middleware
- Router-level middleware
- Error-handling middleware
- Built-in middleware
- Third-party middleware
Application-level middleware:
This kind of middleware method is bind to the app Object using app.use() method. For example:
|
1 2 3 4 |
app.use(function (req, res, next) { console.log('Current Time:', Date.now()) next() }) |
In this example, a middleware functions that prints the current time, has been mounted with app Object using app.use() method. However, this middleware function has neither mount path nor mount point. It is just executing a single instruction and not connecting to router.
However, in the second example,the middleware has a mount path ‘/book/:id’. Therefore app.use() accepts an optional path parameter just like the app.get() and other routes as following.
|
1 2 3 4 |
app.use('/book/:id', function (req, res, next) { console.log('Request Type:', req.method) next() } |
Now in the third example of application-level middleware has both mount-path and mount-point and instead of a single method , this example shows a series of middleware functions those are invoked one after another.
|
1 2 3 4 5 6 7 8 9 10 |
app.use('/book/:id', function (req, res, next) { console.log('Request URL:', req.originalUrl); next() }, function (req, res, next) { console.log('Request Type:', req.method); next() }, function (req, res, next) { res.send(); }) |
Another way to use application-level middleware is to call app.METHOD() . However, the only difference between app.use and app.get is that /books to an app.get(),would only be invoked when someone visited exactly /books route, however, when /books is a parameter to to app.use(), any request that starts with /books will invoke the app.use function. For example,
|
1 2 3 4 5 6 7 8 9 10 |
app.get('/book/:id', function (req, res, next) { console.log('Request URL:', req.originalUrl); next() }, function (req, res, next) { console.log('Request Type:', req.method); next() }, function (req, res, next) { res.send(); }) |
Router-level middleware:
Router-level middleware can be used by using router.use() or router.METHOD().
|
1 2 3 4 5 6 7 |
var express = require('express'); var router = express.Router(); /* GET home page. */ router.get('/', function(req, res, next) { res.render('index', { title: 'Hello World!' }); }); |
OR
|
1 2 3 4 5 6 7 |
router.use('/book/:id', function (req, res, next) { console.log('Request URL:', req.originalUrl) next() }, function (req, res, next) { console.log('Request Type:', req.method) next() }) |
Error-handling middleware:
Unlike application-level and router-level, error-handling middleware takes four argument, for example:
|
1 2 3 4 5 6 7 8 9 |
// error handler app.use(function(err, req, res, next) { // set locals, only providing error in development res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; // render the error page res.status(err.status || 500); res.render('error'); }); |
Built-in middleware:
Starting with version 4.x, there is only one built-in middleware is express.static.
|
1 |
app.use(express.static(path.join(__dirname, 'public'))); |
This middleware function is based on serve-static, and is responsible for loading static assets such as HTML files, images, and so on.The function signature is:
|
1 |
express.static(root, [options]) |
Here root is the directory name and options are several options. The following table describes the properties of the options object, see express.static.
| Property | Description | Type | Default |
| dotfiles | Determines how the files or directories that begin with a dot “.”are treated. | String | “ignore” |
| etag | Enable or disable etag generation. | Boolean | true |
| extensions | If a file is not found, search for files with the given extensions and load the first one found. Example: [‘html’, ‘htm’]. | Boolean | false |
| fallthrough | Let client errors fall-through as unhandled requests, otherwise forward a client error. | Boolean | true |
| index | Sends the specified directory index file. Set to false to disable directory indexing. | Mixed | “index.html” |
| lastModified | Set the Last-Modified header to the last modified date of the file on the OS. | Boolean | true |
| maxAge | Set the max-age property of the Cache-Control header in milliseconds or a string in ms format. | Number | 0 |
| redirect | Redirect to trailing “/” when the pathname is a directory. | Boolean | true |
| setHeaders | Function for setting HTTP headers to serve with the file. | Function |
Third-party middleware:
There are a number of third party middleware, such as body-parser.mongoose, morgan and so on. These can be installed by using command:
|
1 |
npm install <module name> |
And they can be loaded using requires and used later. For example:
|
1 2 3 |
var bodyParser = require('body-parser'); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); |
How to create a Middleware?
To create a middleware that will print the current time and save a book to database and render a message.
- First create the method for logging current time.
123456//create a method tovar requestTime = function (req, res, next) {req.requestTime = Date.now();console.log("Current Time for Request"+req.requestTime );next()}; - Use the middleware function as an application-level middleware.
12//use the middleware as an application-level middlewareapp.use(requestTime); - Create a middleware to connect to DB.
12345678910111213141516// method to conenct to bevar conencttodb = function(req, res, next){try{var path= 'mongodb://localhost:27017/library';connect = mongoose.connect(path);console.log('conencted to db!!');//mongoose.set('debug', true);}catch(e){console.log(e);}};app.use(conencttodb) - Save a book as the next in middleware.
Every method will be executed one after another in order.1234567891011121314151617181920212223242526// create a new bookvar book1 = new Book({title: 'Peter Quill',author: 'starlord55',yearpubished: 2011,id: 101,pages:56,ratings:1});// save the book in databasebook.save(function(err,req, res) {console.log(req.body);if(err) {console.log(err);res.send({message :'something went wrong'});} else {// res.contentType('application/json');res.send({message:'the book has bees saved at'+req.requestTime});}});





