Skip to main content
Node.js APIs Tutorial
CHAPTER 09 Beginner

Working with Middleware

Updated: May 14, 2026
30 min read

# CHAPTER 9

Working with Middleware

1. Introduction

In the previous chapter, we magically enabled JSON parsing by calling app.use(express.json()). But what exactly is happening behind the scenes? In Express, almost everything is Middleware. Middleware functions are the unsung heroes of your API. They intercept incoming HTTP requests, modify them, log them, or block them entirely before they ever reach your core routing logic. In this chapter, we will demystify middleware and write our own custom interceptors.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Define the concept of Middleware in Express.
  • Understand the importance of the next() function.
  • Create global middleware (e.g., a custom request logger).
  • Create route-specific middleware (e.g., protecting a route).

3. Beginner-Friendly Explanation

Imagine a VIP nightclub.
  • The Customer: The HTTP Request.
  • The Dance Floor: Your API Route Logic (res.json(...)).
  • The Bouncers: The Middleware.

Before the customer can reach the dance floor, they must walk down a hallway lined with bouncers.

  1. 1. Bouncer 1 (JSON Parser): Checks if the customer has a coat (JSON data) and hangs it up (req.body).
  1. 2. Bouncer 2 (Logger): Writes down the customer's name and time of arrival in a ledger.
  1. 3. Bouncer 3 (Authentication): Checks if the customer has a VIP wristband. If they do, he says "Go ahead" (next()). If they don't, he physically throws them out the front door (res.status(401)), and they never reach the dance floor.

4. Anatomy of a Middleware Function

A middleware function looks exactly like a standard route, but it has a third argument: next.
javascript
1234567
const myMiddleware = (req, res, next) => {
    console.log("A request just arrived!");
    
    // CRITICAL: You MUST call next() to pass the request to the next bouncer.
    // If you forget next(), the request hangs forever!
    next(); 
};

5. Global Middleware (Runs on EVERY route)

To apply middleware globally, we use app.use().

Let's build a Custom Logger:

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

// Custom Global Middleware
const requestLogger = (req, res, next) => {
    const time = new Date().toLocaleTimeString();
    // Logs: "[10:05 AM] GET request made to /api/users"
    console.log(`[${time}] ${req.method} request made to ${req.url}`);
    
    next(); // Pass control to the next function
};

// Apply it globally
app.use(requestLogger);

app.get('/api/users', (req, res) => {
    res.json({ message: "Here are the users" });
});

6. Route-Specific Middleware (Runs on ONE route)

You don't want a security check to run globally; guests need to see the public homepage! You only want the security check to run on private routes.

Let's build a fake Authentication Middleware:

javascript
123456789101112131415161718
const checkApiKey = (req, res, next) => {
    const userKey = req.query.api_key;
    const secretKey = "super_secret_123";

    if (userKey === secretKey) {
        // Success! They have the wristband. Let them pass.
        next();
    } else {
        // Failure! Throw them out. DO NOT call next().
        res.status(401).json({ error: "Unauthorized! Invalid API Key." });
    }
};

// Apply it ONLY to this specific route by placing it in the middle
app.get('/api/dashboard', checkApiKey, (req, res) => {
    // This code ONLY executes if next() was called in the middleware!
    res.json({ message: "Welcome to the secret VIP dashboard." });
});

*To test this: Visiting /api/dashboard fails with 401. Visiting /api/dashboard?api_key=super_secret_123 succeeds with 200.*

7. Order of Execution

In Express, order matters absolutely. Express reads your app.js file from top to bottom. If you put your Route logic *above* your Global Middleware, the Request hits the route, sends the Response, and the Middleware is entirely ignored! Always put app.use() Global Middlewares at the very top of your file.

8. Third-Party Middleware

You rarely write everything from scratch. The Node ecosystem provides amazing pre-built middleware:
  • cors: Allows frontend frameworks (like React) on different domains to talk to your API.
  • helmet: Automatically adds secure HTTP headers to protect against attacks.
  • morgan: A professional, robust version of the logging middleware we wrote above.

9. Best Practices

  • Modifying the Request: Middleware can alter the request before the Controller sees it. For example, an Authentication middleware can find the user in the database, and attach the user object to the request: req.user = dbUser; next();. Now, the Controller instantly knows exactly who is logged in!

10. Common Mistakes

  • Forgetting next(): If your custom middleware doesn't end with res.json() (throwing an error) or next() (passing it on), the request becomes trapped in purgatory. The client's browser will spin indefinitely.

11. Exercises

  1. 1. Explain the "Bouncer Analogy" and how the next() function operates within an Express application.

12. Coding Challenges

  • Challenge: Write a custom route-specific middleware called checkAge. It should check req.body.age. If the age is less than 18, it should return a 403 Forbidden status with JSON. Apply this middleware to a POST route named /api/buy-lottery-ticket.

13. MCQs with Answers

Question 1

In an Express middleware function (req, res, next), what happens if you successfully validate the request but forget to call the next() function?

Question 2

How do you apply a middleware function so that it intercepts EVERY incoming HTTP request to your entire Express application?

14. Interview Questions

  • Q: Explain the Request-Response lifecycle in Express, specifically detailing how multiple middleware functions (a "middleware stack") are executed in sequence.
  • Q: Provide a real-world scenario where a custom middleware would modify the req object before calling next(), and explain how the subsequent route utilizes that modification.

15. FAQs

Q: What is "Error-Handling Middleware"? A: It is a special middleware with 4 arguments: (err, req, res, next). If any route in your application crashes, Express automatically skips all normal routes and drops the error directly into this special middleware so you can gracefully return a 500 JSON response instead of crashing the server.

16. Summary

In Chapter 9, we unlocked the true architectural power of Express. Middleware acts as a series of customizable checkpoints. By writing Global Middleware, we can log traffic or enforce security headers across our entire app. By writing Route-Specific Middleware, we can enforce strict authorization (like API keys) on sensitive endpoints, ensuring our core routing logic remains clean and protected.

17. Next Chapter Recommendation

We know how to route traffic, capture data, and secure endpoints. It is time to organize it into a professional structure. Proceed to Chapter 10: Building CRUD APIs with Express.js.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·