Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62
Subscribe to my email list now at http://jauyeung.net/subscribe/
Middleware functions are functions that have access to the request and response objects, and the next function for call the next middleware.
In this article, we’ll look at what Express middleware does and how we can write them.
Characteristics of Middleware
Middleware functions can run any code, make changes to the request and response object, end the request-response cycle, and call the next middleware in the stack.
A middleware may look something like the following code:
app.get('/', (req, res, next) => {
next();
});
The code above has the request method in which the middleware will be called, which is the get
in app.get
.
Then we have the '/'
which is the route path.
Finally, the middleware function that we pass in has the request and response objects as the first 2 parameters respectively, and the next
function, which we call to run the next middleware.
Example
For example, we can write a middleware to log some output when we make a request to the /
route.
We can write this as follows:
const express = require('express')
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.get('/', (req, res, next) => {
console.log('middleware called');
next();
});
app.get('/', (req, res) => {
res.send();
})
app.listen(3000, () => console.log('server started'));
next
will call our route handler for the /
route.
We should get middleware called
from the console.log
output and an empty response.
To load the middleware for all routes, we can use app.use
instead of app.METHOD
where METHOD
is the request method is in lower case.
For example, we can write an app-wide middleware as follows:
const express = require('express')
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use((req, res, next) => {
console.log('middleware called');
next();
});
app.get('/', (req, res) => {
res.send();
})
app.listen(3000, () => console.log('server started'));
We should get the same thing as before, but if we have:
const express = require('express')
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use((req, res, next) => {
console.log('middleware called');
next();
});
app.get('/', (req, res) => {
res.send();
})
app.post('/foo', (req, res) => {
res.send('foo');
})
app.listen(3000, () => console.log('server started'));
We get middleware called
when we make a GET request to /
and a POST request to /foo
.
Modifying the Request and Response Objects
We can attach new properties and set values for the request and response objects.
For example, we can write:
const express = require('express')
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use((req, res, next) => {
req.requestTime = Date.now();
next();
});
app.get('/', (req, res) => {
res.json(req.requestTime);
})
app.post('/foo', (req, res) => {
res.json(req.requestTime);
})
app.listen(3000, () => console.log('server started'));
Then we get the timestamp of when the request is made when we make a GET request to /
and a POST request to /foo
.
Likewise, we can do something similar with the response object:
const express = require('express')
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use((req, res, next) => {
res.responseTime = Date.now();
next();
});
app.get('/', (req, res) => {
res.json(res.responseTime);
})
app.post('/foo', (req, res) => {
res.json(res.responseTime);
})
app.listen(3000, () => console.log('server started'));
We also will get the timestamp of when the response is made when we make a GET request to /
and a POST request to /foo
.
Configurable Middleware
We can make a function that has optional parameters and return a middleware function to create a configurable middleware function.
For example, we can write one as follows:
const express = require('express')
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
const configurableMiddleware = (options) => {
return (req, res, next) => {
req.options = options;
next();
}
}
app.use(configurableMiddleware({ date: new Date(), foo: 'bar' }));
app.get('/', (req, res) => {
res.json(req.options);
})
app.listen(3000, () => console.log('server started'));
The configurableMiddleware
function takes an options object as a parameter and then return a middleware function with the req.options
property set to the options
parameter.
Then when we make a request to the /
route then we get:
{"date":"2019-12-23T22:37:04.927Z","foo":"bar"}
as the response.
Conclusion
We can use Express middleware functions to run code before a route handler or another middleware is run.
To create a middleware function, we just have to create a function with the request and response objects as the first 2 parameters and the next function as the third parameter.
We can modify the request and response objects by adding new properties to it and set a value for them.
Then we call next
to call the next middleware or route handler.
We can create configurable middleware by creating a function that takes an options parameter and returns a middleware function.