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 lastConditional 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
});
});