ExpressJs Routing & Middleware

Asaf Peleg
3 min readFeb 6, 2022

Express is an extremely popular web server for Node.js because it offers a fast, unopinionated, and minimalist framework. The heart of the framework is middleware which provides a simple means of executing arbitrary code when processing requests to the server. Web developers new to Express may find middleware confusing but by starting with familiar routing examples it can more easily be understood.

express logo
logo from Expressjs.com

Routes & The Router Object

The Router object contains common HTTP methods such as router.get, router.post, and so on. The methods take two arguments: the path and a callback function that is executed when the route is requested.

router.get(‘/user/:id’, myCallback)

Callback functions will always contain at least two arguments: the request and response.

const myCallback = function(req, res) {
const userId = req.params.id
res.send(`hello user: ${userId}`)
}

Let’s put it all together in a minimal example

// Section 1
const express = require('express')
const app = express()
const router = express.Router()
const port = 3000
// Section 2
const myCallback = function(req, res) {
const userId = req.params.id
res.send(`hello user: ${userId}`)
}
router.get('/user/:id', myCallback)// Section 3
app.use('/', router)
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})

Section 1
Boilerplate import statement and instantiation of core Express objects including the Router object which is used to create the route in Section 2

Section 2
Create our function and route registration that will execute when localhost:3000/user/1 is requested

Section 3
Finally register the router with the application and start the server on the specified port.

Middleware

Middleware functions are often registered at the application level (using the app object) so the code executes for all routes. Middleware functions share the same arguments as a Route callback function and also have a third argument called next which is responsible for passing execution along to the next callback.

var express = require('express')
var app = express()
var router = express.Router()
const port = 3000
// App Level Middleware
app.use((req, res, next) => {
console.log(req.headers)
next()
})
router.get('/user/:id', (req, res) => {
const userId = req.params.id
res.send(`hello user: ${userId}`)
})
app.use('/', router)app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})

The example above adds on an application level middleware function to print all the request headers to the console and then passes execution along to the router by calling next()

Middleware functions can also…

A: optionally supply a path as the first argument to only operate on when those routes are hit
B: execute when only specific HTTP methods are requested
C: end the request cycle by sending back a response to the client
D: mix and match a combination all of any of above

// A
app.use('/user/:id', (req, res, next) => {
console.log(req.headers)
next()
})
// B
app.get('*', (req, res, next) => {
console.log('GET request called')
next()
})
// C
app.use((req, res, next) => {
res.send('You shall not pass')
})
// D
app.get('/user/:id', (req, res, next) => {
if (req.params.id < 1) res.send('Invalid userId')
next()
})

At this point you might be wondering why Middleware & Routes are so similar.

Middleware Meme

When To Use Routes vs. Middleware

Both can be used interchangeably but conventionally each are used for certain purposes.

Routes:

  • Used for defining paths
  • Call res.send and end the request cycle

Middleware:

  • Code to execute at application level for more than one route
  • Perform pre-route processing such as authorization or parsing

Go confidently using Middleware whether its your own or a third-party you install from NPM. Now that you know that Middleware works just like familiar routes you should be comfortable adding them at any level.

--

--