# Middleware in Express.js

# Middleware in Express.js: The Checkpoint Between Request and Response

> Every request that hits your Express server passes through a series of
> checkpoints before it ever reaches your route handler. Those checkpoints
> are middleware — and understanding them changes how you think about
> building APIs.

---

## 1. What Is Middleware?

Middleware is any function that sits **between** the incoming request and the
final route handler. It has access to three things:

- `req` — the request object
- `res` — the response object
- `next` — a function that passes control to the next middleware in line

```js
function myMiddleware(req, res, next) {
  // do something with req or res
  next(); // hand off to the next middleware
}
```

Think of it like airport security. Your request is the passenger. Before
reaching the gate (route handler), it must pass through check-in, security,
and boarding — each one a middleware that can inspect, modify, or stop the
request entirely.

---

## 2. Where Middleware Sits in the Request Lifecycle

```mermaid
flowchart LR
    A["Client\nrequest"]:::gray
    B["Middleware 1\nLogger"]:::teal
    C["Middleware 2\nAuth check"]:::teal
    D["Middleware 3\nValidation"]:::teal
    E["Route\nhandler"]:::purple
    F["Client\nresponse"]:::gray

    A --> B --> C --> D --> E --> F

    classDef gray   fill:#F1EFE8,stroke:#5F5E5A,color:#444441
    classDef teal   fill:#E1F5EE,stroke:#0F6E56,color:#085041
    classDef purple fill:#EEEDFE,stroke:#534AB7,color:#3C3489
```

The request travels left to right. Each middleware can:

1. **Execute** any code
2. **Modify** `req` or `res`
3. **End** the request-response cycle (by sending a response)
4. **Call `next()`** to pass control forward

If a middleware neither calls `next()` nor sends a response, the request
hangs forever — a common beginner bug.

---

## 3. The Role of `next()`

`next()` is the baton in a relay race. Without it, the race stops.

```mermaid
flowchart TD
    A["Middleware receives request"]:::teal
    B{"calls next()?"}:::decision
    C["Next middleware runs"]:::teal
    D["Request hangs ❌"]:::danger
    E["OR sends response\nres.send() / res.json()"]:::purple

    A --> B
    B -->|"yes"| C
    B -->|"no"| D
    B -->|"sends response instead"| E

    classDef teal     fill:#E1F5EE,stroke:#0F6E56,color:#085041
    classDef decision fill:#FAEEDA,stroke:#854F0B,color:#633806
    classDef danger   fill:#FCEBEB,stroke:#A32D2D,color:#791F1F
    classDef purple   fill:#EEEDFE,stroke:#534AB7,color:#3C3489
```

```js
// ✅ Passes control to the next middleware
app.use((req, res, next) => {
  console.log("Request received");
  next(); // must call this
});

// ❌ Forgets next() — request hangs
app.use((req, res, next) => {
  console.log("Request received");
  // next() never called, response never sent — client waits forever
});
```

You can also pass an argument to `next()` to trigger the error-handling
middleware:

```js
next(new Error("Something went wrong")); // jumps to error handler
```

---

## 4. Types of Middleware

### Application-level middleware

Registered directly on the `app` object. Runs on every request unless
scoped to a specific path.

```js
const express = require("express");
const app = express();

// Runs on every single request
app.use((req, res, next) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
  next();
});

// Runs only on requests to /dashboard/*
app.use("/dashboard", (req, res, next) => {
  console.log("Dashboard area accessed");
  next();
});
```

### Router-level middleware

Registered on an `express.Router()` instance. Keeps your code modular —
each router manages its own middleware chain.

```js
const router = express.Router();

// Runs only for routes defined on this router
router.use((req, res, next) => {
  console.log("Router-level middleware fired");
  next();
});

router.get("/profile", (req, res) => {
  res.send("User profile");
});

app.use("/user", router);
```

### Built-in middleware

Express ships with several middleware functions out of the box:

| Middleware | What it does |
|---|---|
| `express.json()` | Parses incoming JSON request bodies |
| `express.urlencoded()` | Parses URL-encoded form data |
| `express.static()` | Serves static files from a folder |

```js
app.use(express.json());           // enables req.body for JSON payloads
app.use(express.urlencoded({ extended: true })); // enables form data
app.use(express.static("public")); // serves files from /public
```

---

## 5. Execution Order — Sequence Matters

Middleware runs **in the order it is registered**. This is not optional
behaviour — it is the entire design of Express.

```js
app.use(middlewareA); // runs first
app.use(middlewareB); // runs second
app.use(middlewareC); // runs third

app.get("/", routeHandler); // runs last
```

```mermaid
flowchart LR
    R["Request"]:::gray
    A["middlewareA\nLogger"]:::teal
    B["middlewareB\nAuth"]:::teal
    C["middlewareC\nValidation"]:::teal
    H["Route handler\nGET /"]:::purple
    S["Response\nsent"]:::gray

    R --> A -->|"next()"| B -->|"next()"| C -->|"next()"| H --> S

    classDef gray   fill:#F1EFE8,stroke:#5F5E5A,color:#444441
    classDef teal   fill:#E1F5EE,stroke:#0F6E56,color:#085041
    classDef purple fill:#EEEDFE,stroke:#534AB7,color:#3C3489
```

**Important:** if you register `express.json()` after a route, that route
will never have access to `req.body`. Always register parsing middleware
before your routes.

---

## 6. Real-World Examples

### Logging middleware

Records every request — method, URL, and timestamp — before anything else runs.

```js
app.use((req, res, next) => {
  const timestamp = new Date().toISOString();
  console.log(`[${timestamp}] ${req.method} ${req.url}`);
  next();
});

// Output:
// [2026-05-10T08:30:00.000Z] GET /api/users
// [2026-05-10T08:30:01.000Z] POST /api/login
```

### Authentication middleware

Checks for a valid token before granting access to protected routes.
If the token is missing or invalid, the middleware ends the cycle itself
and never calls `next()`.

```js
function requireAuth(req, res, next) {
  const token = req.headers["authorization"];

  if (!token) {
    return res.status(401).json({ error: "No token provided" });
  }

  if (token !== "valid-secret-token") {
    return res.status(403).json({ error: "Invalid token" });
  }

  next(); // token is valid — proceed to the route handler
}

// Apply only to protected routes
app.get("/dashboard", requireAuth, (req, res) => {
  res.json({ message: "Welcome to the dashboard" });
});
```

### Request validation middleware

Checks that the request body contains the required fields before the
route handler ever runs.

```js
function validateUser(req, res, next) {
  const { name, email, age } = req.body;

  if (!name || !email || !age) {
    return res.status(400).json({
      error: "name, email, and age are all required"
    });
  }

  if (typeof age !== "number" || age < 0) {
    return res.status(400).json({ error: "age must be a positive number" });
  }

  next(); // validation passed — proceed
}

app.post("/users", express.json(), validateUser, (req, res) => {
  res.status(201).json({ message: "User created", user: req.body });
});
```

---

## 7. Putting It All Together

Here is a realistic Express setup that chains all three middleware types
in the correct order:

```js
const express = require("express");
const app = express();

// 1. Built-in — parse JSON bodies first
app.use(express.json());

// 2. Application-level — log every request
app.use((req, res, next) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
  next();
});

// 3. Router-level — protect the /api group
const apiRouter = express.Router();

apiRouter.use((req, res, next) => {
  const token = req.headers["authorization"];
  if (!token) return res.status(401).json({ error: "Unauthorised" });
  next();
});

apiRouter.get("/users", (req, res) => {
  res.json([{ id: 1, name: "Alice" }]);
});

app.use("/api", apiRouter);

app.listen(3000, () => console.log("Server running on port 3000"));
```

**Request flow for `GET /api/users`:**

```
express.json() → logger → auth check → route handler → response
```

---

## Key Takeaways

- Middleware is a function with `(req, res, next)` that sits between request and response
- It runs in **registration order** — sequence is everything
- Always call `next()` or send a response — never leave a request hanging
- **Application-level** middleware applies globally; **router-level** applies to a group; **built-in** handles common parsing tasks
- Use middleware for cross-cutting concerns: logging, auth, validation, rate limiting
- Pass an error to `next(err)` to jump straight to your error-handling middleware

---

*Found this useful? Follow for the next article: building a full authentication
system in Express with JWT middleware from scratch. 👇*
