AzuraJS Logo
AzuraJSFramework
v2.2 Beta

Middleware

Guia completo de middleware no AzuraJS

Middleware 🔌

Middleware permite interceptar e processar requisições antes de chegarem aos seus handlers de rota.

Conceito de Middleware 💡

Middleware é uma função que tem acesso aos objetos request e response, e à função next no ciclo request-response.

import type { RequestHandler } from "azurajs/types";
import type { RequestServer, ResponseServer } from "azurajs";

type RequestHandler = (
  req: RequestServer,
  res: ResponseServer,
  next: (err?: unknown) => void
) => void | Promise<void>;

Middleware Global 🌐

Registre middleware que executa para todas as rotas:

TypeScript

import { AzuraClient } from "azurajs";

const app = new AzuraClient();

// Middleware de logging
app.use((req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  next();
});

// Middleware de autenticação
app.use((req, res, next) => {
  const token = req.headers["authorization"];
  if (!token) {
    return res.status(401).json({ error: "Não autorizado" });
  }
  // Verificar token
  next();
});

JavaScript

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

const app = new AzuraClient();

// Middleware de logging
app.use((req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  next();
});

// Middleware de autenticação
app.use((req, res, next) => {
  const token = req.headers["authorization"];
  if (!token) {
    return res.status(401).json({ error: "Não autorizado" });
  }
  // Verificar token
  next();
});

Middleware Incluído 📦

LoggingMiddleware

Registra detalhes das requisições:

TypeScript

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

const app = new AzuraClient();
app.use(LoggingMiddleware);

JavaScript

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

const app = new AzuraClient();
app.use(LoggingMiddleware);

Middleware Customizado 🛠️

Middleware de Autenticação

function authMiddleware(req: RequestServer, res: ResponseServer, next: () => void) {
  const token = req.headers["authorization"]?.replace("Bearer ", "");
  
  if (!token) {
    return res.status(401).json({ error: "Token não fornecido" });
  }

  try {
    const decoded = verifyJWT(token);
    req.user = decoded;  // Adicionar usuário ao request
    next();
  } catch (error) {
    res.status(401).json({ error: "Token inválido" });
  }
}

app.use(authMiddleware);

Middleware de Validação

function validateJSON(req: RequestServer, res: ResponseServer, next: () => void) {
  if (req.method === "POST" || req.method === "PUT") {
    const contentType = req.headers["content-type"];
    
    if (!contentType?.includes("application/json")) {
      return res.status(415).json({ 
        error: "Content-Type deve ser application/json" 
      });
    }
  }
  next();
}

app.use(validateJSON);

Middleware de Rate Limiting

const requestCounts = new Map<string, { count: number; resetAt: number }>();

function rateLimitMiddleware(req: RequestServer, res: ResponseServer, next: () => void) {
  const ip = req.ip;
  const now = Date.now();
  const windowMs = 60000; // 1 minuto
  const maxRequests = 100;

  let record = requestCounts.get(ip);

  if (!record || now > record.resetAt) {
    record = { count: 1, resetAt: now + windowMs };
    requestCounts.set(ip, record);
    return next();
  }

  record.count++;

  if (record.count > maxRequests) {
    return res.status(429).json({ 
      error: "Muitas requisições. Tente novamente mais tarde." 
    });
  }

  next();
}

app.use(rateLimitMiddleware);

Middleware de CORS

function corsMiddleware(req: RequestServer, res: ResponseServer, next: () => void) {
  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH");
  res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");

  // Lidar com preflight
  if (req.method === "OPTIONS") {
    return res.status(204).end();
  }

  next();
}

app.use(corsMiddleware);

Middleware de Compression

import { gzipSync } from "zlib";

function compressionMiddleware(req: RequestServer, res: ResponseServer, next: () => void) {
  const acceptEncoding = req.headers["accept-encoding"] || "";

  if (acceptEncoding.includes("gzip")) {
    const originalSend = res.send.bind(res);
    
    res.send = function(data: any) {
      if (typeof data === "string" || Buffer.isBuffer(data)) {
        const compressed = gzipSync(data);
        res.setHeader("Content-Encoding", "gzip");
        return originalSend(compressed);
      }
      return originalSend(data);
    };
  }

  next();
}

app.use(compressionMiddleware);

Middleware de Timeout

function timeoutMiddleware(ms: number) {
  return (req: RequestServer, res: ResponseServer, next: () => void) => {
    const timeout = setTimeout(() => {
      if (!res.headersSent) {
        res.status(408).json({ error: "Request timeout" });
      }
    }, ms);

    res.on("finish", () => clearTimeout(timeout));
    next();
  };
}

app.use(timeoutMiddleware(5000));  // Timeout de 5 segundos

Middleware Async 🔄

Middleware pode ser assíncrono:

async function databaseMiddleware(
  req: RequestServer,
  res: ResponseServer,
  next: () => void
) {
  try {
    req.db = await getDatabaseConnection();
    next();
  } catch (error) {
    res.status(500).json({ error: "Erro de banco de dados" });
  }
}

app.use(databaseMiddleware);

Tratamento de Erros ⚠️

Middleware de Erro Global

function errorHandler(
  error: any,
  req: RequestServer,
  res: ResponseServer,
  next: () => void
) {
  console.error("Error:", error);

  if (error instanceof HttpError) {
    return res.status(error.statusCode).json({
      error: error.message,
      statusCode: error.statusCode
    });
  }

  res.status(500).json({ 
    error: "Erro interno do servidor" 
  });
}

// Registrar por último
app.use(errorHandler);

Ordem de Middleware ⚡

Middleware executa na ordem em que é registrado:

const app = new AzuraClient();

// 1. Logging (primeiro)
app.use(LoggingMiddleware);

// 2. CORS
app.use(corsMiddleware);

// 3. Rate limiting
app.use(rateLimitMiddleware);

// 4. Autenticação
app.use(authMiddleware);

// 5. Rotas
applyDecorators(app, [UserController]);

// 6. Error handler (último)
app.use(errorHandler);

Middleware Condicional 🎯

Execute middleware apenas para certas rotas:

function authMiddleware(req: RequestServer, res: ResponseServer, next: () => void) {
  // Pular autenticação para rotas públicas
  if (req.url.startsWith("/api/public")) {
    return next();
  }

  const token = req.headers["authorization"];
  if (!token) {
    return res.status(401).json({ error: "Não autorizado" });
  }

  next();
}

app.use(authMiddleware);

Middleware de Rota 🛣️

Aplique middleware a rotas específicas:

// Middleware aplicado antes de controllers
app.use("/api/admin", adminAuthMiddleware);
app.use("/api/users", rateLimitMiddleware);

// Depois registre controllers
applyDecorators(app, [AdminController, UserController]);

Exemplos Práticos 🎨

Middleware de Cache

const cache = new Map<string, { data: any; expires: number }>();

function cacheMiddleware(ttl: number) {
  return (req: RequestServer, res: ResponseServer, next: () => void) => {
    if (req.method !== "GET") {
      return next();
    }

    const key = req.url;
    const cached = cache.get(key);

    if (cached && Date.now() < cached.expires) {
      return res.json(cached.data);
    }

    const originalJson = res.json.bind(res);
    res.json = function(data: any) {
      cache.set(key, { data, expires: Date.now() + ttl });
      return originalJson(data);
    };

    next();
  };
}

app.use(cacheMiddleware(60000));  // Cache de 1 minuto

Middleware de Request ID

import { randomUUID } from "crypto";

function requestIdMiddleware(req: RequestServer, res: ResponseServer, next: () => void) {
  const requestId = randomUUID();
  req.id = requestId;
  res.setHeader("X-Request-ID", requestId);
  next();
}

app.use(requestIdMiddleware);

Middleware de Sanitização

function sanitizeMiddleware(req: RequestServer, res: ResponseServer, next: () => void) {
  if (req.body) {
    req.body = sanitizeObject(req.body);
  }
  next();
}

function sanitizeObject(obj: any): any {
  if (typeof obj === "string") {
    return obj.replace(/<script>/gi, "").trim();
  }
  if (Array.isArray(obj)) {
    return obj.map(sanitizeObject);
  }
  if (typeof obj === "object" && obj !== null) {
    const sanitized: any = {};
    for (const key in obj) {
      sanitized[key] = sanitizeObject(obj[key]);
    }
    return sanitized;
  }
  return obj;
}

app.use(sanitizeMiddleware);

Melhores Práticas ✨

Sempre chame next(): Sem chamar next(), a requisição fica pendurada

Trate erros adequadamente: Use try-catch em middleware async

Mantenha middleware leve: Evite operações pesadas que atrasam todas as requisições

Ordem importa: Registre middleware na ordem correta (logging → cors → auth → rotas → errors)

Próximos Passos 📖

On this page