Lesson 19 +10 XP

Writing Custom Middleware Functions

Creating Reusable Middleware

Custom middleware allows modularizing logic such as authentication checks, request validation, rate limiting, and request transformation.

Example 1: API Key Authentication Middleware

function requireApiKey(req, res, next) {
  const apiKey = req.headers["x-api-key"];

  if (!apiKey || apiKey !== "secret-token-123") {
    return res.status(401).json({ error: "Unauthorized: Invalid or missing API Key" });
  }

  // API Key valid -> attach context and call next()
  req.apiClient = { role: "admin" };
  next();
}

// Mounting middleware on specific routes
app.get("/api/protected-data", requireApiKey, (req, res) => {
  res.json({ data: "Top secret content", client: req.apiClient });
});

Example 2: Configurable Middleware Factory Function

// Factory function returning custom middleware
function restrictToRoles(...allowedRoles) {
  return (req, res, next) => {
    if (!req.user || !allowedRoles.includes(req.user.role)) {
      return res.status(403).json({ error: "Forbidden: Insufficient privileges" });
    }
    next();
  };
}

// Usage in routes
app.delete("/api/users/:id", requireApiKey, restrictToRoles("admin", "superadmin"), (req, res) => {
  res.json({ message: "User deleted" });
});

TL;DR

  • Custom middleware can inspect headers, modify req objects, or return early responses.
  • Use higher-order factory functions to pass configurable parameters into middleware.