Padrão de Middleware
Construa pipelines de requisição a partir de funções pequenas e compostas que cada uma lida com uma preocupação antes de passar o controle para o próximo manipulador.
Receita
Cartão de receita de referência rápida - pronto para copiar e colar.
import express, { type Request, type Response, type NextFunction } from "express";
const app = express();
// Middleware é executado na ordem de registro
app.use((req, _res, next) => {
req.headers["x-request-start"] = String(Date.now());
next();
});
app.get("/users", (req, res) => {
res.json({ startedAt: req.headers["x-request-start"] });
});
// Middleware de erro de quatro argumentos (Express 5)
app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => {
res.status(500).json({ error: err.message });
});Quando usar isso: Qualquer aplicativo HTTP que precise de preocupações transversais (logging, autenticação, parsing, CORS) aplicadas consistentemente em todas as rotas.
Exemplo de Trabalho
Um executor de middleware mínimo sem Express, depois a mesma cadeia no Express 5.
import express from "express";
// --- Tipos de middleware Node puros ---
type Req = { headers: Record<string, string | undefined>; body?: unknown };
type Res = { statusCode: number; body?: unknown; status(n: number): Res; json(d: unknown): void };
type Next = (err?: Error) => void;
type Middleware = (req: Req, res: Res, next: Next) => void;
function runMiddleware(
middlewares: Middleware[],
req: Req,
res: Res,
finalHandler: () => void
) {
let index = 0;
const next: Next = (err) => {
if (err) throw err;
const fn = middlewares[index++];
if (fn) fn(req, res, next);
else finalHandler();
};
next();
}
// --- Equivalente do Express 5 ---
const app = express();
app.use(express.json({ limit: "1mb" }));
function requestId(req: express.Request, _res: express.Response, next: express.NextFunction) {
req.headers["x-request-id"] = crypto.randomUUID();
next();
}
function requireAuth(req: express.Request, res: express.Response, next: express.NextFunction) {
const token = req.headers.authorization;
if (!token?.startsWith("Bearer ")) {
res.status(401).json({ error: "Unauthorized" });
return;
}
next();
}
app.use(requestId);
app.get("/public", (_req, res) => res.json({ ok: true }));
app.get("/private", requireAuth, (_req, res) => res.json({ secret: true }));O que isso demonstra:
- Middleware é uma função com a assinatura
(req, res, next) - Chame
next()para continuar; omita para encerrar a resposta - A ordem importa: parsers antes das rotas, manipuladores de erro por último
- Middleware de rota (
requireAuth) limita a autenticação a caminhos específicos
Mergulho Profundo
Como Funciona
- Cada middleware pode mutar
req/res, encerrar a resposta ou chamarnext() - A cadeia é uma invocação ligada:
m1 -> m2 -> m3 -> manipulador de rota - Middleware de erro tem 4 parâmetros
(err, req, res, next)e só é executado quandonext(err)é chamado - Fastify usa hooks (
onRequest,preHandler) em vez de uma única cadeia; NestJS usa guards, interceptors e pipes
Categorias de Middleware
| Categoria | Exemplos | Posição Típica |
|---|---|---|
| Parsing de Requisição | express.json(), express.urlencoded() | Cedo |
| Segurança | helmet, cors, limitador de taxa | Após parsers |
| Contexto | ID da requisição, logging, tempo | Antes das rotas |
| Autenticação | Verificação de JWT, verificação de chave de API | Por rota ou grupo de roteador |
| Negócios | Manipuladores de rota | Meio |
| Tratamento de Erros | Middleware de erro de 4 argumentos | Último |
Notas de TypeScript
// Estende o Request do Express para contexto de middleware tipado
declare global {
namespace Express {
interface Request {
userId?: string;
}
}
}
function attachUser(req: express.Request, _res: express.Response, next: express.NextFunction) {
req.userId = "user-42";
next();
}Armadilhas
- Chamar
next()apósres.send()- envia respostas duplicadas e falha comERR_HTTP_HEADERS_SENT. Correção: retorne imediatamente após encerrar a resposta. next()esquecido - a requisição fica pendente até o tempo limite. Correção: cada caminho de código deve chamarnext()ou encerrar a resposta.- Middleware de erro registrado antes das rotas - nunca é executado. Correção: registre manipuladores de 4 argumentos após todas as rotas.
- Middleware assíncrono sem encaminhamento de erro - promessas rejeitadas são perdidas em padrões mais antigos. Correção: Express 5 captura erros assíncronos; caso contrário, use
try/catchenext(err). - Autenticação global em arquivos estáticos - bloqueia
favicon.icoe verificações de integridade. Correção: monte a autenticação em roteadores específicos, nãoapp.use(auth)globalmente. - Ordem dos parsers de corpo -
express.json()após as rotas significa que os corpos POST nunca são analisados. Correção: parsers primeiro. Veja Ordem de Middleware.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| Hooks do Fastify | Precisa de estágios de ciclo de vida (preValidation, preSerialization) | Equipe só conhece Express |
| Guards, Interceptors & Pipes do NestJS | Cross-cutting orientado a decoradores com DI | API CRUD simples |
| Lógica de manipulador inline | Script de endpoint único | Mais de 2 preocupações compartilhadas |
| Middleware Hono | Edge + Node com bundle minúsculo | Ecossistema de plugins Express pesado necessário |
FAQs
Qual é a diferença entre `app.use(fn)` e `app.get(path, fn)`?
app.use corresponde a todos os métodos e caminhos (a menos que um prefixo de caminho seja fornecido). app.get corresponde apenas a requisições GET para um caminho específico. Middleware de autenticação geralmente vai em app.use("/api", auth).
Quantas funções de middleware é demais?
Não há limite rígido, mas se a cadeia exceder 10 middlewares globais, audite por redundância. Combine logging + ID da requisição em um único middleware.
Middleware pode ser assíncrono?
Sim. Express 5 captura automaticamente erros assíncronos. Em Node puro ou Express 4, envolva com um helper que chama next(err) em caso de rejeição.
Como isso se relaciona com os plugins do Fastify?
Plugins Fastify encapsulam rotas + hooks + decoradores em um escopo. Middleware é plano; plugins evitam vazamento de decoradores entre módulos de recursos.
Devo usar middleware para lógica de negócios?
Não. Middleware lida com infraestrutura transversal. Regras de negócios pertencem a funções de serviço chamadas por manipuladores de rota finos.
Como testar middleware isoladamente?
Chame a função com req, res mockados e um spy de next. Afirme que next foi chamado, ou que res.status foi definido. Supertest testa a cadeia completa.
E o padrão `ctx` do Koa?
Koa usa middleware assíncrono com ctx em vez de (req, res, next). Veja Koa & Polka.
O middleware é executado em requisições 404?
Somente se registrado antes do manipulador 404. Adicione uma rota catch-all ou middleware de erro no final da cadeia.
Relacionados
- Ordem de Middleware - sequência de registro correta
- Tratamento de Erros no Express - padrões de middleware de erro
- Middleware de Segurança - helmet, cors, limites de taxa
- Guards, Interceptors & Pipes - equivalente NestJS
- Melhores Práticas de Fundamentos HTTP - checklist da seção
Versões da Stack: Esta página foi escrita para Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 e NestJS 11.