Express Middleware

Aug 29, 2019

When an Express server receives an HTTP request, it executes a list of middleware functions. The middleware functions are responsible for handling the request and crafting a response.

You will usually see middleware defined as a function with 3 parameters: req, res, and next. The biggest exception to this rule is error handling middleware. To add a middleware function to your Express app, you call app.use().

const app = require('express')();

app.use((req, res, next) => {
  req; // The request
  res; // The response
  next; // A function that you must call to trigger the next middleware
});

Under the hood, when you call app.use(), Express adds your function to its internal middleware stack. Express executes middleware in the order they're added, so if you call app.use(fn1); app.use(fn2);, Express will execute fn1 before fn2.

Middleware vs Route Handlers

Suppose you have a simple Express server that responds to GET requests with the string 'Hello, World' as shown below.

const app = require('express')();

app.get('/', function routeHandler(req, res) {
  res.send('Hello, World');
});

In Express, a route handler is just a special type of middleware that never calls next(). You could also write a middleware that does the same thing.

app.use(function(req, res, next) {
  // Do nothing if the request isn't `GET /`
  if (req.method !== 'GET' || req.url !== '/') {
    return next();
  }
  res.send('Hello, World');
});

Routing

The app.use() function takes 2 parameters: an optional path, and a middleware function callback. If the first parameter to app.use() is a string, Express will only execute the corresponding middleware function if the URL matches.

// Express will only call `middleware()` if `req.url` is equal to '/'
app.use('/', function middleware(req, res, next) {
  // Do nothing if the request isn't a 'GET' request
  if (req.method !== 'GET') {
    return next();
  }
  res.send('Hello, World');
});

The next() Function

If you have multiple middleware functions, you need to make sure your middleware either calls next() or send a response. If you write Express middleware, this is your responsibility. Express will not throw an error if your middleware doesn't call next(), it will simply hang.

// If you open this page in Chrome, it will just keep loading forever.
app.use('/', function middleware(req, res, next) {
  console.log('Test');
});

In general, it is best practice to call next() unless you explicitly do not want the rest of the middleware stack to run. Calling next() if there's no more middleware is perfectly fine.

// It is OK to call `next()` even if there's no more middleware.
app.use((req, res, next) => {
  res.send('Hello, World');
  next();
});

If you call next() with a parameter, Express will treat that parameter as an error and trigger error handling middleware. The below middleware will cause Express to respond with an HTTP 500 and a stack trace.

app.use((req, res, next) => {
  next(new Error('Fail!'));
});

If you open the above middleware in Chrome, you'll see something like this:


More Express Tutorials