AzuraJS Logo
AzuraJSFramework
v2.2 Beta

Middleware

Create and use middleware in AzuraJS

Middleware 🔌

Middleware functions intercept requests and responses, allowing you to add authentication, logging, validation, and more.

What is Middleware? 📚

Middleware is a function that executes before your route handler. It has access to the request and response objects and can:

  • Execute code
  • Modify request/response objects
  • End the request-response cycle
  • Call the next middleware

Creating Middleware 🛠️

Basic Middleware

TypeScript

import type { RequestHandler } from "azurajs/types";

const myMiddleware: RequestHandler = async (req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  await next();
};

JavaScript

const myMiddleware = async (req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  await next();
};

Middleware with Configuration

TypeScript

function createAuthMiddleware(secret: string): RequestHandler {
  return async (req, res, next) => {
    const token = req.headers.authorization;
    
    if (!token) {
      res.status(401).json({ error: "Unauthorized" });
      return;
    }
    
    // Verify token logic here
    await next();
  };
}

JavaScript

function createAuthMiddleware(secret) {
  return async (req, res, next) => {
    const token = req.headers.authorization;
    
    if (!token) {
      res.status(401).json({ error: "Unauthorized" });
      return;
    }
    
    // Verify token logic here
    await next();
  };
}

Using Middleware 🔧

Global Middleware

Apply middleware to all routes:

TypeScript

import { AzuraClient } from "azurajs";

const app = new AzuraClient();

// Add global middleware
app.use(async (req, res, next) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
  await next();
});

app.use(async (req, res, next) => {
  res.setHeader("X-Powered-By", "AzuraJS");
  await next();
});

JavaScript

const { AzuraClient } = require("azurajs");

const app = new AzuraClient();

// Add global middleware
app.use(async (req, res, next) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
  await next();
});

app.use(async (req, res, next) => {
  res.setHeader("X-Powered-By", "AzuraJS");
  await next();
});

Built-in Logging Middleware

AzuraJS includes a logging middleware:

TypeScript

import { AzuraClient } from "azurajs";
import { createLoggingMiddleware } from "azurajs/middleware";

const app = new AzuraClient();
const logger = createLoggingMiddleware(app.getConfig());
app.use(logger);

JavaScript

const { AzuraClient } = require("azurajs");
const { createLoggingMiddleware } = require("azurajs/middleware");

const app = new AzuraClient();
const logger = createLoggingMiddleware(app.getConfig());
app.use(logger);

Middleware Examples 🎨

Authentication Middleware

TypeScript

import { HttpError } from "azurajs/http-error";
import type { RequestHandler } from "azurajs/types";

export const authMiddleware: RequestHandler = async (req, res, next) => {
  const token = req.headers.authorization?.replace("Bearer ", "");
  
  if (!token) {
    res.status(401).json({ error: "No token provided" });
    return;
  }
  
  try {
    // Verify token (example with JWT)
    const user = await verifyToken(token);
    (req as any).user = user;  // Attach user to request
    await next();
  } catch (error) {
    res.status(401).json({ error: "Invalid token" });
  }
};

JavaScript

const authMiddleware = async (req, res, next) => {
  const token = req.headers.authorization?.replace("Bearer ", "");
  
  if (!token) {
    res.status(401).json({ error: "No token provided" });
    return;
  }
  
  try {
    // Verify token (example with JWT)
    const user = await verifyToken(token);
    req.user = user;  // Attach user to request
    await next();
  } catch (error) {
    res.status(401).json({ error: "Invalid token" });
  }
};

module.exports = { authMiddleware };

CORS Middleware

TypeScript

export const corsMiddleware: RequestHandler = async (req, res, next) => {
  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
  res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
  
  if (req.method === "OPTIONS") {
    res.status(204).end();
    return;
  }
  
  await next();
};

JavaScript

const corsMiddleware = async (req, res, next) => {
  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
  res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
  
  if (req.method === "OPTIONS") {
    res.status(204).end();
    return;
  }
  
  await next();
};

module.exports = { corsMiddleware };

Rate Limiting Middleware

TypeScript

const requests = new Map<string, number[]>();

export function rateLimitMiddleware(limit: number, windowMs: number): RequestHandler {
  return async (req, res, next) => {
    const ip = req.socket.remoteAddress || "unknown";
    const now = Date.now();
    
    const userRequests = requests.get(ip) || [];
    const recentRequests = userRequests.filter(time => now - time < windowMs);
    
    if (recentRequests.length >= limit) {
      res.status(429).json({ error: "Too many requests" });
      return;
    }
    
    recentRequests.push(now);
    requests.set(ip, recentRequests);
    await next();
  };
}

JavaScript

const requests = new Map();

function rateLimitMiddleware(limit, windowMs) {
  return async (req, res, next) => {
    const ip = req.socket.remoteAddress || "unknown";
    const now = Date.now();
    
    const userRequests = requests.get(ip) || [];
    const recentRequests = userRequests.filter(time => now - time < windowMs);
    
    if (recentRequests.length >= limit) {
      res.status(429).json({ error: "Too many requests" });
      return;
    }
    
    recentRequests.push(now);
    requests.set(ip, recentRequests);
    await next();
  };
}

module.exports = { rateLimitMiddleware };

await next(); }; }

// Usage app.use(rateLimitMiddleware(100, 60000)); // 100 requests per minute


### Request ID Middleware

```typescript
import { randomUUID } from "crypto";

export const requestIdMiddleware: RequestHandler = async (req, res, next) => {
  const requestId = randomUUID();
  (req as any).id = requestId;
  res.setHeader("X-Request-ID", requestId);
  await next();
};

Error Handling Middleware

export const errorMiddleware: RequestHandler = async (req, res, next) => {
  try {
    await next();
  } catch (error: any) {
    console.error("Error:", error);
    
    if (error instanceof HttpError) {
      res.status(error.status).json({
        error: error.message
      });
    } else {
      res.status(500).json({
        error: "Internal server error"
      });
    }
  }
};

Body Parser Middleware

export const jsonParserMiddleware: RequestHandler = async (req, res, next) => {
  if (req.headers["content-type"]?.includes("application/json")) {
    let body = "";
    
    req.on("data", (chunk) => {
      body += chunk.toString();
    });
    
    req.on("end", () => {
      try {
        req.body = JSON.parse(body);
      } catch (error) {
        req.body = {};
      }
      next();
    });
  } else {
    await next();
  }
};

Middleware Chains 🔗

Stack multiple middleware functions:

const app = new AzuraClient();

// Order matters!
app.use(requestIdMiddleware);
app.use(corsMiddleware);
app.use(createLoggingMiddleware(app.getConfig()));
app.use(authMiddleware);  // This runs last

Conditional Middleware ⚡

Apply middleware conditionally:

const conditionalAuth: RequestHandler = async (req, res, next) => {
  // Skip auth for public routes
  if (req.url?.startsWith("/api/public")) {
    await next();
    return;
  }
  
  // Apply auth for other routes
  await authMiddleware(req, res, next);
};

app.use(conditionalAuth);

Middleware Best Practices ✨

Always call next(): Unless you're ending the response, always call next()

Order matters: Middleware executes in the order it's added

Don't forget async/await: Always use async functions with await next()

Error handling: Wrap risky code in try-catch blocks

Middleware Timing ⏱️

Measure middleware execution time:

const timingMiddleware: RequestHandler = async (req, res, next) => {
  const start = Date.now();
  
  await next();
  
  const duration = Date.now() - start;
  res.setHeader("X-Response-Time", `${duration}ms`);
  console.log(`${req.method} ${req.url} - ${duration}ms`);
};

Testing Middleware 🧪

import { describe, it, expect } from "bun:test";

describe("Auth Middleware", () => {
  it("should reject requests without token", async () => {
    const req = { headers: {} } as any;
    const res = {
      status: (code: number) => ({
        json: (data: any) => ({ code, data })
      })
    } as any;
    const next = async () => {};
    
    await authMiddleware(req, res, next);
    
    // Assertions
  });
});

Next Steps 📖

On this page