How to Create an Express.js Middleware

How to Create an Express.js Middleware

Context

During my interview for my programmer role at the Utah County Government, one of the questions was to explain what middleware was. Although I was familiar with the term, I could not answer it appropriately.

After my interview, I decided to dive deep into the subject. Soon I discovered that I have been using middleware all along and that it was such a fundamental part of my development workflow.

Express HTTP Requests

If you are familiar with the Node.js micro-framework Express, you will recognize this piece of code:

app.get('/route', async (request, response) => {
  return response.send('hello, world');
}

That is how we set up HTTP requests and routes to our Express.js server. What I want to emphasize here is that callback arrow function with the signature async (request, response) => {…}.

This function could be abstracted outside the app.get() method, and then referenced in it the following way:

async function sendHelloWorld(request, response) {
  return response.send('hello, world');
}
app.get('/route'/, sendHelloWorld);

There is virtually no difference in the way that both snippets handle the HTTP request. So now you might be asking, "What does it have to do with middleware?" Well, everything. You see, both the sendHelloWorld() and the callback functions are being used as a medium to handle the client request to the server. These functions are in the "middle" of the client and the server. They specify to the server the steps necessary to handle that specific request on that route. So, there you have it. Your first middleware.

Middleware Basics

Calling the previous functions middleware may not be 100% accurate. The very concept of middleware is to be a function or procedure that executes before the request functions. After all, middleware is a function in-between the client's request and the server's response.

Example

Let's imagine that I want to log the server's terminal for each request it receives, including the HTTP method type and the request's route. I also want to keep my request handling logic separated from this logging logic. I can create a middleware for that:

function logRequest(request*, response*, next) {
  console.log(`HTTP ${request.method} on ${request.baseUrl}`);
  return next();
}

Each middleware function must have at least three parameters: request, response, and next. The first two you should already know. Now, next refers to the function that will execute after the middleware (another middleware or not).

How to use a middleware

There are three ways to apply consume a middleware function in Express. Two are very similar, with a difference in routing scope.

Apply to a specific route:

app.get('/route', middleware, async (req, res) => {...});

Apply globally to all routes:

/* On the main file */
app.use(middleware);

Apply locally to a group of routes:

/* On a route file */
route.use(middleware);

Conclusion

And there you have it, express middleware. To summarize:

  • Create a function with the request, response, next parameters containing the logic that will execute before the request handling.
  • Apply the middleware to specific routes by using it as an argument before your async (request, response) function.
  • Apply it globally by using app.use(middleware) in your main file.
  • Apply it locally to a route file by using route.use(middleware).