Middleware é uma função no pipeline de requisições que inspeciona ou modifica requisições e respostas antes de a lógica da rota rodar. Dois sentidos dividem a palavra — o sentido corporativo mais antigo (message brokers e barramentos de integração entre aplicações) e o sentido de framework web que este verbete cobre: funções dentro de uma aplicação pelas quais toda requisição flui, em ordem. O Express enuncia o modelo sem rodeios: um app “é essencialmente uma série de chamadas de funções de middleware” — e a ordem dessas chamadas é, bem literalmente, o programa.
Principais pontos
| Pergunta | Resposta |
|---|---|
| O contrato | Inspecionar/modificar → então responder (short-circuit) ou chamar next() |
| A forma | Uma cebola: requisições descem o stack, respostas sobem de volta |
| A lei | Ordem de registro = ordem de execução — a maioria dos bugs de middleware é bug de ordem |
| O stack canônico | Headers → CORS → parsing → logging → authn → authz → limites → rotas → 404 → erros |
| vs. o gateway | Middleware roda dentro de um app; um gateway fica na frente de muitos |
O stack, em ordem
// JavaScript / Node.js — Express + Parse Server
// Middleware: functions the request flows through, in registration order
const app = express();
app.use(helmet()); // 1 · security headers
app.use(cors(corsOptions)); // 2 · CORS before anything that fails
app.use(express.json({ limit: '1mb' })); // 3 · body parsing, bounded
// Parse Server IS middleware — a whole backend mounted into the stack
app.use('/parse', new ParseServer(config).app);
app.use(notFoundHandler); // 404 — after all routes
app.use(errorHandler); // error handler LAST (4 args) // Flutter / Dart — Back4app Flutter SDK
// One SDK call — and the platform's middleware stack ran the gauntlet:
final response =
await QueryBuilder<ParseObject>(ParseObject('Post')).query();
// Before your query touched data, the request passed through:
// security headers → CORS → body limits → key check → session auth
// → rate limiting → routing → (your beforeFind trigger) → the database
// You wrote none of it — that's the middleware a BaaS runs for you. // iOS / Swift — Back4app Swift SDK
// One SDK call — and the platform's middleware stack ran the gauntlet:
let posts = try await Post.query().find()
// Before your query touched data, the request passed through:
// security headers → CORS → body limits → key check → session auth
// → rate limiting → routing → (your beforeFind trigger) → the database
// You wrote none of it — that's the middleware a BaaS runs for you. // Android / Kotlin — Back4app Android SDK
// One SDK call — and the platform's middleware stack ran the gauntlet:
val posts = ParseQuery.getQuery<ParseObject>("Post").find()
// Before your query touched data, the request passed through:
// security headers → CORS → body limits → key check → session auth
// → rate limiting → routing → (your beforeFind trigger) → the database
// You wrote none of it — that's the middleware a BaaS runs for you. Cada posição tem um porquê: headers de segurança primeiro (precisam estar em toda resposta, inclusive nos erros); CORS antes de qualquer coisa que possa falhar (ou os navegadores mascaram o erro real); parsing de body limitado e antes das rotas (ou req.body fica undefined); autenticação antes de autorização (permissões checadas contra ninguém são permissões concedidas a qualquer um); rate limiting antes do trabalho caro (um limitador depois da query ao banco não protege nada); o 404 depois de todas as rotas; o handler de erro por último, sem exceção.
A cebola, desenhada corretamente
A metade que a maioria das explicações omite: o pipeline roda nos dois sentidos. A documentação do Django o desenha como uma cebola — cada middleware é uma camada em volta da view no núcleo — e o código depois da chamada a next() (ou depois de get_response) roda no caminho de volta da resposta, em ordem inversa. É ali que o tempo de resposta é medido, que os headers são carimbados e que o logging registra o que de fato aconteceu. Uma camada que faz short-circuit não pula só o handler; pula as duas metades de toda camada interna — que é exatamente a garantia que um portão de auth existe para dar.
Bugs de ordem que vão para produção
O conselho genérico é “a ordem importa”; os bugs específicos ensinam mais. Autorização antes de autenticação: a checagem de permissão roda contra um principal anônimo — 401s/403s intermitentes, nenhuma exceção em lugar algum, horas de debugging. Body parser depois das rotas: todo handler vê req.body === undefined e culpa o cliente. Auth antes de CORS: o navegador bloqueia a própria resposta 401 por falta de headers CORS, e o frontend vê um erro de rede em vez do erro real. Arquivos estáticos antes de auth: arquivos privados servidos alegremente aos não autenticados. Handler de erro que não é o último: erros lançados depois da posição dele no stack nunca chegam até ele. Cada um desses passa em um smoke test no caminho feliz — bugs de ordem são o tipo que vai para produção.
Short-circuit: quando não chamar next() é o objetivo
O contrato tem duas saídas legais: passar o controle adiante, ou encerrar o ciclo. Encerrá-lo cedo não é uma falha do middleware — é metade do trabalho dele: o 401 do portão de auth, o 429 do limitador, o cache hit, o redirect, o preflight de CORS respondido na hora. A regra que mantém as duas saídas honestas: sempre faça exatamente uma — responda, ou chame next(). Não fazer nenhuma pendura a requisição para sempre; fazer as duas lança erros de headers-already-sent que confundem todo mundo rio abaixo.
A mesma ideia em todo framework
| Framework | O middleware é | Passa o controle | No caminho de volta |
|---|---|---|---|
| Express | (req, res, next) => {} | next() | Código depois de next() (com cuidado) |
| Django | Callable envolvendo get_response | get_response(request) | Código depois da chamada — a cebola |
| Rack / Rails | Objeto com call(env) | @app.call(env) | Depois que a chamada retorna |
| Koa / Hono | async (ctx, next) => {} | await next() | Depois do await — de primeira classe |
Um modelo, quatro sotaques. O caminho de erro ganha sua própria convenção por framework — a assinatura de quatro argumentos (err, req, res, next) do Express é o mecanismo de registro, e é por isso que apagar um parâmetro “não usado” transforma silenciosamente o handler de erro em um middleware comum que nunca dispara.
Middleware vs. gateways vs. hooks
| Middleware | API gateway | Hooks de dados | |
|---|---|---|---|
| Roda | Dentro do processo de um app | Na frente de muitos apps | Em volta das operações de dados |
| Granularidade | Por requisição | Por requisição, entre serviços | Por save/delete/find |
| Dono de | O pipeline deste app | Roteamento, auth de borda, limites globais | Validação, reações a dados |
| Configurado por | Código, em ordem | Config de infraestrutura | Registro por classe |
Três camadas de interceptação, um aninhamento: o gateway fica na frente da frota, o middleware roda a esteira de cada app, e os hooks disparam onde requisições viram dados. Uma preocupação pertence à camada mais externa capaz de decidi-la — rate limits globais no gateway, auth de sessão no middleware, “essa gravação é válida?” no hook.
Casos de uso comuns
- Autenticação e gestão de sessão — estabelecer identidade uma vez, cedo, para tudo que vem depois.
- Higiene transversal — CORS, headers de segurança, compressão, IDs de requisição.
- Disciplina de entrada — parsing de body com limites de tamanho, enforcement de content-type, validação.
- Observabilidade — logging e timing envolvendo o pipeline inteiro pelo caminho de volta da cebola.
- Proteção de tráfego — rate limits e portões antiabuso que fazem short-circuit antes de o custo ser incorrido.
Em qual camada isso pertence? Matriz de decisão
| Preocupação | Camada |
|---|---|
| Vale para todo app que você roda | Gateway |
| Vale para toda requisição deste app | Middleware, posicionado deliberadamente |
| Vale para rotas específicas | Middleware em nível de rota |
| Vale quando dados são gravados ou lidos | Hooks beforeSave / beforeFind |
| Operações de negócio sob medida | Funções, não gambiarras de pipeline |
| Moldar erros | Middleware de erro — por último, quatro argumentos, sem exceções |
Limitações e trade-offs
- A ordem é invisível até deixar de ser. O stack se lê de cima para baixo, mas falha apontando para todo canto; trate o registro de middleware como código revisado e estrutural.
- Toda camada taxa toda requisição. Dez middleware de 2 ms cada são 20 ms em toda resposta; meça o stack como você mede queries.
- Estado global é uma armadilha. Middleware roda concorrentemente entre requisições; qualquer coisa mutável compartilhada vira uma corrida — anexe dados por requisição ao objeto da requisição, e em nenhum outro lugar.
- Pipelines escondem o fluxo de controle. Uma camada com short-circuit três níveis abaixo pode ser o motivo de uma rota “nunca rodar”; o movimento de debugging é sempre o mesmo: imprima o stack, em ordem.
- Nem tudo é preocupação de pipeline. Lógica de negócio contrabandeada para o middleware acopla toda rota a ela; o pipeline é para preocupações transversais, não centrais.
Middleware no Back4app
O Back4app é uma plataforma open-source de Backend as a Service (BaaS) que combina banco de dados gerenciado, APIs REST e GraphQL geradas automaticamente, autenticação, armazenamento de arquivos e funções serverless com Cloud Code. A relação aqui é excepcionalmente literal: o servidor do Back4app é, ele próprio, middleware do Express — a aba de JavaScript o mostra montado com app.use('/parse', …) em um stack padrão — e a plataforma roda a esteira canônica para toda requisição: headers de segurança, CORS, parsing limitado, checagem de chaves, autenticação de sessão e rate limits, na ordem certa, mantidos como infraestrutura. Sua lógica por requisição vai então para onde a matriz de decisão aponta, em vez de para código de pipeline artesanal: triggers beforeSave/beforeFind para regras junto aos dados, Cloud Functions para operações — cada um com o contexto do usuário da requisição anexado, que é a maior parte do que um middleware customizado sempre quis saber.
Perguntas frequentes
O que é middleware em termos simples?
É uma função que fica no caminho entre uma requisição que chega e a lógica da sua rota, processando toda requisição de passagem — como os checkpoints de segurança do aeroporto antes do portão. Cada uma inspeciona ou modifica a requisição, e então a passa adiante ou a barra na hora.
Quais são exemplos comuns de middleware?
O stack de sempre: headers de segurança, CORS, parsing de body com limite de tamanho, logging, autenticação, autorização, rate limiting, arquivos estáticos e — no fim — os handlers de 404 e de erro. Quase tudo que é transversal em uma aplicação web é middleware.
Como funciona a cadeia de middleware?
Cada função ou encerra o ciclo enviando uma resposta, ou chama next() para passar o controle à seguinte; o framework percorre o stack na ordem de registro até algo responder. O bug clássico: não responder nem chamar next() — a requisição fica pendurada para sempre.
A ordem do middleware importa?
É a fonte número um de bugs. Autorização antes de autenticação checa permissões contra ninguém; um body parser depois das rotas deixa req.body undefined; auth antes de CORS faz o navegador mascarar o erro real; um handler de erro em qualquer lugar que não o último não engole nada. A ordem é o programa.
O que é middleware de tratamento de erros?
É um middleware para o qual o framework encaminha os erros, em vez da cadeia normal — no Express, reconhecido pela assinatura de quatro argumentos (err, req, res, next) e registrado por último. Erros lançados e chamadas next(err) pulam todo o resto e caem ali, e é por isso que a posição dele é inegociável.
Qual a diferença entre middleware e um handler de rota?
Intenção e posição. Middleware trata preocupações transversais de muitas rotas e normalmente passa o controle adiante; o handler de rota é o destino que produz a resposta. Na maioria dos frameworks, são funções estruturalmente idênticas — o pipeline apenas termina em uma delas.
Qual a diferença entre middleware e um API gateway?
O escopo. Middleware roda dentro do processo de uma aplicação, por requisição; um gateway é infraestrutura na frente de muitas aplicações, cuidando de roteamento, auth e rate limits entre serviços. Um gateway é o middleware da sua arquitetura inteira — e eles se compõem em vez de competir.
Quando o middleware NÃO deve chamar next()?
Quando ele tratou a requisição por completo: uma rejeição de auth devolvendo 401, um rate limiter devolvendo 429, um cache hit, um redirect, uma resposta de preflight de CORS. O short-circuit é o recurso — a garantia de que nada depois do portão roda para requisições que falharam nele.