What is an Express Middleware and How to Create One
How to inspect, manipulate, and reject HTTP requests and responses with Express Middlewares

Prerequisites
Basic understanding of the HTTP protocol, Javascript, Node, and Express
What are Middlewares?
From the documentation,
Middlewares are functions that have access to the request object (req), the response object (res), and the next function 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.
To give you a relatable picture, Express middleware’s are the workers in a manufacturing line where each individual has a specific and unique responsibility. When a worker receives a product (request) from a previous worker they can do one of the following:
- reject the product if it doesn’t meet strict standards, thus the product ceases to continue down the production line
- add to or manipulate the product and/or allow the product to continue down the production line where the next worker (middleware) does their job
If you’ve used Express before, you may have used some middlewares:
body-parser- parses the request body and places it into thereq.bodykey of the request objectexpress.static- serves your static filesexpress.logger- uses a logger
All you had to do was add these to your Express application or route and BAM… you had more functionality! It seemed like magic but it’s actually quite simple.
In this article I’ll go over the details of middlewares and some useful examples showcasing the flexibility and power of middlewares.
Req, Res, Next
Middlewares have access to three things:
function customMiddleware (req, res, next) {
//…
}Since you have access to the request and response you can do almost anything you want. You can extract or add information to and from either one. You would call next if you want to continue the request and pass it on to the next middleware or end the request right there.
Middleware Chain
So you created the custom middleware, now what? You add it to the middleware chain. Middlewares are called in the order they’re declared.
const express = require(‘express’)
const app = express()
app.use(express.bodyParser)
app.use(customMiddleware)- On every request these two middlewares will run-
bodyParserwill run first before the one below it
const express = require(‘express’)
const app = express()
app.get(‘/some/path’, customMiddleware, customMiddleware2)const apiRouter = express.Router()
apiRouter.use(customMiddleware2)
app.use(‘/api’, apiRouter)
You can have middlewares run on specific routes:
customMiddlewarewill run first followed bycustomMiddleware2for theGETmethod on the path‘/some/path’- Only
customMiddleware2will run for all requests to theapiRouter
Cool huh? Let’s see some other useful examples!
A Simple Logger- Log Date and URL Path
In this example I extract and log some data specific to the request, then pass the request to the next middleware by using the next function. The request or response is not altered in any way. I’ll show an example of that next.
function datePathLogger (req, res, next) {
const date = new Date().toUTCString()
console.log(`Request to ‘${req.path}’ on ${date}`)
next()
}A request to a url www.foo.com/bar would log
Request to ‘/bar’ on Mon, 17 Jul 2017 01:01:38 GMTAfter the console.log function ran the next function was called. At this point the request and response would be handed to the next middleware.
Token Parser- Parse User ID from JWT Token
In this example I parse the request object for the JWT token to get the user’s id. If it doesn’t exist or the token was invalid I end the request and send back an unauthorized status code of 401. At this point the request stops. If it does exist I place the user’s id into req.user_id then call next.
Note that the key
user_idis arbitrary. I could have usedreq.users_identification_number. However, there are reserved keys on the request and response object that you shouldn’t modify. So consult the documentation to verify you’re not modifying reserved keys.
function tokenParser (req, res, next) {
// This is a made-up function that parses the user’s ID
// from the request object
const user_id = parseTokenForUserID(req) if (!user_id) {
res.sendStatus(401)
} else {
req.user_id = user_id
next()
}
}
Now in every succeeding middleware or request handler I have access to the user’s id at req.user_id.
Environment-specific Middleware
Since middleware’s are just functions you can have functionality based on different environments or configuration. Say, for example, we wanted to perform descriptive logging for development environments.
function logger (env) {
if (env === ‘development’) {
return function (req, res, next) {
// perform descriptive logs better suited
// for development environments
}
} else {
return function (req, res, next) {
// perform none or minimal logging
}
}
}Then add this middleware by calling it with the environment
const express = require(‘express’)
const app = express()
app.use(logger(process.env.NODE_ENV))These may not be practical examples you’d actually use in production but the illustrations should provide some clarity on the flexibility of middlewares.
Beauty Of Middlewares
I love how the flow in Express middleware’s are very explicit. It makes code intuitive, super flexible, and easy to read. If you’re not creating custom middlewares I highly encourage you to take advantage of their simplicity and power.
If you have any comments or questions please leave a comment or tweet me! Mahalo! 🤙
