These free mini-courses will give you a strong foundation in web development. Track your progress and access advanced courses on HTML/CSS, Ruby and JavaScript for free inside our student portal.
Scroll down...
Look at how the Express documentation defines Middleware:
Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle
Does any of that ring a bell? We've already dealt with functions that access the request and response objects. Our route handling functions dealt with the req
and res
. However, they could not access "the next middleware function in the application’s request-response cycle." So those handler functions weren't technically Middleware, but they were not very different either.
Middleware allows you build a pipeline of functions that can react to or transform the request and response. A simple example would be a piece of logging middleware. Say we want our application to function precisely as it had been, except we want to add a layer of logging that prints out each request URL and to the console—if you think layers, you should think Middleware.
Let's see we could add some logging to our wonderfully basic application.
Connecting a simple middleware function doesn't look too much different than our earlier route handler functions. Here's how we can add a piece of middleware to our basic "Hello World" application.
app.use(function (req, res, next) {
console.log(req.url + " — " + new Date())
next()
})
There are three differences between this and a route handler. Firstly, we are passing this function to use
rather than one of the HTTP method functions like get
(remember Express provides you with helper methods that map to HTTP verbs: get()
for GET requests, post()
for POST requests, etc.). Secondly, we are only passing in a function, there is no path string. You can pass a path string as the first argument, and if you do so, the middleware will only execute on requests to the given path. When no path string is supplied, such as in our example, the middleware will execute on every request. Finally, our middleware function has the next
parameter. This is a function that lets Express continue on to the next piece of middleware. If you forget to pass in and call next
, then your application will hang indefinitely; watch out for this! Always call next()
at the end of the middleware method (next()
tells Express to move on to next middleware or to the callback function associated with your endpoint).
Here's our application with our new slice of middleware.
const express = require('express')
const app = express()
app.set('view engine', 'hbs')
app.use(function (req, res, next) {
console.log(req.url + " — " + new Date())
next()
})
app.get('/', function (req, res) {
res.render('hello')
})
app.get('/names/:name', function (req, res) {
const name = req.params.name
res.render('hello', {name})
})
app.listen(3001, function () {
console.log('Odin is listening on port 3000!')
})
Middleware isn't much more than a pile of functions. It's not so intimidating once you realize there isn't any hidden magic. Because they are just JavaScript functions, your Middleware can be as small or as powerful as you want it to be. Express is all about building with small, composable pieces, and now most of those pieces are in your reach.