> ## Documentation Index
> Fetch the complete documentation index at: https://docs.loremstock.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Express Middleware and Advanced Routing

> Understand how Express middleware works, write custom middleware, use built-in and third-party middleware, and organize routes using Express Router.

Middleware is one of the most important Express concepts. Every request flows through a chain of middleware functions before reaching the final route handler. This page covers built-in middleware, popular third-party packages, custom middleware, error handling, and how to organize large applications using Express Router.

## What Is Middleware?

Middleware is a function that runs between an incoming request and the outgoing response. It has access to `req`, `res`, and `next`.

```javascript theme={null}
function myMiddleware(req, res, next) {
  // Do something with the request
  console.log('Middleware ran!');
  next(); // Pass control to the next function
}
```

The middleware chain works like this:

```text theme={null}
Request -> Middleware1 -> Middleware2 -> Route Handler -> Response
```

<Warning>
  If a middleware does not call `next()` AND does not send a response, the request hangs forever. The client waits until a timeout. Always ensure one or the other happens.
</Warning>

## The Middleware Chain: next() Explained

<Steps>
  <Step title="Request arrives">
    Client sends HTTP request to the server.
  </Step>

  <Step title="First middleware runs">
    Express calls it with req, res, and next.
  </Step>

  <Step title="Call next() or end the response">
    If next() is called, execution moves to the next middleware. If res.send() is called, the cycle ends.
  </Step>

  <Step title="Route handler runs">
    Eventually a route matches and processes the request.
  </Step>

  <Step title="Response sent">
    The handler sends the response back to the client.
  </Step>
</Steps>

## Built-in Middleware

```javascript theme={null}
const express = require('express');
const app = express();

// Parse JSON request bodies (needed for req.body to work)
app.use(express.json());

// Parse URL-encoded form data
app.use(express.urlencoded({ extended: true }));

// Serve static files from 'public' folder
app.use(express.static('public'));
```

<Note>
  `express.json()` must be registered BEFORE routes that read `req.body`. Without it, `req.body` is `undefined`.
</Note>

## Third-Party Middleware

Install all three:

```bash theme={null}
npm install morgan cors helmet
```

```javascript theme={null}
const morgan = require('morgan');
const cors = require('cors');
const helmet = require('helmet');

// Log every HTTP request: method, URL, status, response time
app.use(morgan('dev'));
// Output: GET /users 200 12.345 ms - 234

// Allow cross-origin requests from browsers
app.use(cors());
// Restrict to specific origins in production:
app.use(cors({ origin: 'https://myfrontend.com' }));

// Set secure HTTP headers (prevents XSS, clickjacking, etc.)
app.use(helmet());
```

| Package    | Purpose                                                          |
| ---------- | ---------------------------------------------------------------- |
| **morgan** | HTTP request logging (dev: colorful, combined: production-level) |
| **cors**   | Allows browsers on other domains to call your API                |
| **helmet** | Sets security headers automatically                              |

## Writing Custom Middleware

### Request Logger

```javascript theme={null}
// middleware/logger.js
const logger = (req, res, next) => {
  const timestamp = new Date().toISOString();
  console.log(`[${timestamp}] ${req.method} ${req.url}`);
  next(); // MUST call next()
};

module.exports = logger;
```

### Request Timer

```javascript theme={null}
// middleware/timer.js
const timer = (req, res, next) => {
  req.startTime = Date.now();

  res.on('finish', () => {
    const duration = Date.now() - req.startTime;
    console.log(`Request took ${duration}ms`);
  });

  next();
};

module.exports = timer;
```

### Authentication Check Middleware

```javascript theme={null}
// middleware/auth.js
const jwt = require('jsonwebtoken');

const verifyToken = (req, res, next) => {
  const authHeader = req.headers.authorization;

  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(401).json({ message: 'No token provided' });
  }

  const token = authHeader.split(' ')[1];

  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded; // Attach user to request
    next();
  } catch (err) {
    return res.status(401).json({ message: 'Invalid or expired token' });
  }
};

module.exports = verifyToken;
```

## Error-Handling Middleware

Error middleware is special: it has 4 parameters instead of 3. Express detects it by the 4-arg signature.

```javascript theme={null}
// middleware/errorHandler.js
const errorHandler = (err, req, res, next) => {
  console.error(err.stack);

  const statusCode = err.statusCode || 500;
  const message = err.message || 'Internal Server Error';

  res.status(statusCode).json({
    success: false,
    error: message,
    ...(process.env.NODE_ENV === 'development' && { stack: err.stack })
  });
};

module.exports = errorHandler;
```

<Warning>
  Error-handling middleware must be registered LAST in app.js, after all routes. Otherwise errors from routes cannot reach it.
</Warning>

To trigger it from a route:

```javascript theme={null}
app.get('/test', (req, res, next) => {
  const error = new Error('Test error');
  error.statusCode = 400;
  next(error); // Pass to error handler
});
```

## Express Router

Use `express.Router()` to organize routes in separate files. This keeps `app.js` clean.

```javascript theme={null}
// routes/userRoutes.js
const express = require('express');
const router = express.Router();
const verifyToken = require('../middleware/auth');

router.get('/', verifyToken, userController.getAllUsers);
router.get('/:id', verifyToken, userController.getUserById);
router.post('/', userController.createUser);
router.put('/:id', verifyToken, userController.updateUser);
router.delete('/:id', verifyToken, userController.deleteUser);

module.exports = router;
```

Mount in app.js:

```javascript theme={null}
const userRoutes = require('./routes/userRoutes');
app.use('/api/v1/users', userRoutes);
```

Now all user routes are accessible at `/api/v1/users`.

## Route Parameters vs Query Strings

| Feature  | Route Parameter              | Query String           |
| -------- | ---------------------------- | ---------------------- |
| Syntax   | `/users/:id`                 | `/users?name=john`     |
| Purpose  | Identify a specific resource | Filter, sort, paginate |
| Required | Usually                      | Optional               |
| Access   | `req.params.id`              | `req.query.name`       |

```javascript theme={null}
// Route parameter: /users/42
app.get('/users/:id', (req, res) => {
  console.log(req.params.id); // "42"
});

// Query string: /users?role=admin&page=2
app.get('/users', (req, res) => {
  console.log(req.query.role);  // "admin"
  console.log(req.query.page);  // "2"
});
```

## Chaining Middleware on Routes

You can chain multiple middleware functions before the route handler:

```javascript theme={null}
const authenticate = (req, res, next) => { /* check token */ next(); };
const authorize = (role) => (req, res, next) => {
  if (req.user.role !== role) return res.status(403).json({ message: 'Forbidden' });
  next();
};
const validate = (req, res, next) => { /* check body */ next(); };

// Chain: authenticate -> authorize('admin') -> validate -> handler
router.post('/admin/users',
  authenticate,
  authorize('admin'),
  validate,
  userController.createUser
);
```

## API Versioning

Prefix all routes with a version number from day one:

```javascript theme={null}
const v1Routes = require('./routes/v1');
const v2Routes = require('./routes/v2');

app.use('/api/v1', v1Routes);
app.use('/api/v2', v2Routes);
```

This lets you change v2 without breaking clients still using v1.

## Complete app.js Structure

```javascript theme={null}
const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const morgan = require('morgan');

const errorHandler = require('./middleware/errorHandler');
const userRoutes = require('./routes/userRoutes');

const app = express();

// Security and parsing
app.use(helmet());
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(morgan('dev'));

// Routes
app.use('/api/v1/users', userRoutes);

// 404 handler
app.use((req, res) => {
  res.status(404).json({ message: 'Route not found' });
});

// Error handler (MUST BE LAST)
app.use(errorHandler);

module.exports = app;
```

## Key Terms

| Term                  | Definition                                                                           |
| --------------------- | ------------------------------------------------------------------------------------ |
| **Middleware**        | A function running between request arrival and response sending. Has req, res, next. |
| **next()**            | Function that passes control to the next middleware or route handler.                |
| **Router**            | An Express object grouping related routes into a mountable, modular unit.            |
| **CORS**              | Cross-Origin Resource Sharing. Allows browsers to call your API from other domains.  |
| **Request lifecycle** | The full path a request takes from arrival, through middleware, to response.         |
| **morgan**            | HTTP logging middleware. Logs method, URL, status, and response time.                |
| **helmet**            | Security middleware that sets HTTP headers to protect against common attacks.        |

## Common Mistakes

<Accordion title="Registering error handler before routes">
  Error-handling middleware placed before routes will never receive errors from those routes. Always put it last.
</Accordion>

<Accordion title="Confusing req.params and req.query">
  `req.params.id` is for URL path segments like `:id`. `req.query.page` is for query strings like `?page=2`. They are not interchangeable.
</Accordion>

<Accordion title="Not using express.json()">
  Without this middleware, `req.body` is undefined. Every POST and PUT endpoint needs it.
</Accordion>

<Accordion title="Forgetting to export the router">
  A router file that does not have `module.exports = router` at the bottom will throw an error when imported in app.js.
</Accordion>
