Tratamento de Erros no Express
Centralize respostas de erro com middleware de erro de quatro argumentos e deixe o Express 5 lidar com rejeições assíncronas automaticamente.
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";
class AppError extends Error {
constructor(
public statusCode: number,
message: string,
public code?: string
) {
super(message);
}
}
const app = express();
app.get("/users/:id", async (req, res) => {
const user = await findUser(req.params.id);
if (!user) throw new AppError(404, "Usuário não encontrado", "USER_NOT_FOUND");
res.json(user);
});
app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => {
const status = err instanceof AppError ? err.statusCode : 500;
const code = err instanceof AppError ? err.code : "INTERNAL_ERROR";
res.status(status).json({ error: err.message, code });
});Quando usar isso: Qualquer API que retorne formatos de erro consistentes em vez de traces de pilha HTML ou requisições travadas.
Exemplo de Trabalho
import express, { type Request, type Response, type NextFunction } from "express";
import { z } from "zod";
class AppError extends Error {
constructor(public statusCode: number, message: string) {
super(message);
}
}
const createUserSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
});
const app = express();
app.use(express.json());
function validateBody<T>(schema: z.ZodSchema<T>) {
return (req: Request, _res: Response, next: NextFunction) => {
const result = schema.safeParse(req.body);
if (!result.success) {
next(new AppError(422, result.error.message));
return;
}
req.body = result.data;
next();
};
}
app.post("/users", validateBody(createUserSchema), async (req, res) => {
const user = await createUser(req.body);
res.status(201).json(user);
});
app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => {
console.error(err);
const status = err instanceof AppError ? err.statusCode : 500;
res.status(status).json({
error: status === 500 ? "Erro interno do servidor" : err.message,
});
});
async function createUser(data: z.infer<typeof createUserSchema>) {
return { id: 1, ...data };
}O que isso demonstra:
AppErrorcustomizado com códigos de status- Middleware de validação chamando
next(err)em vez de tratar inline - Lançamentos assíncronos do manipulador do Express 5 encaminhados para o middleware de erro
- Mensagens de 500 seguras para produção (sem vazamento de stack)
Mergulho Profundo
Como Funciona
- Lançamentos síncronos em manipuladores de rota são capturados pelo Express
- O Express 5 captura rejeições de promessas de manipuladores
asyncautomaticamente next(err)pula o restante do middleware e vai para o primeiro manipulador de 4 argumentos- O middleware de erro deve ser registrado após todas as rotas
Padrões de Resposta de Erro
| Status | Significado | Exemplo |
|---|---|---|
| 400 | Requisição malformada | JSON inválido |
| 401 | Não autenticado | Token ausente |
| 403 | Não autorizado | Token válido, papel errado |
| 404 | Não encontrado | ID de recurso desconhecido |
| 422 | Falha na validação | Rejeição do schema Zod |
| 500 | Erro do servidor | Exceção não tratada |
Notas de TypeScript
// Manipulador de erro tipado
const errorHandler: express.ErrorRequestHandler = (err, _req, res, _next) => {
res.status(500).json({ error: "Erro interno do servidor" });
};
app.use(errorHandler);Armadilhas
- Esquecer de registrar o middleware de erro - O padrão do Express envia páginas de erro HTML. Correção: adicione um manipulador de 4 argumentos no final.
- Chamar
res.json()e depoisnext(err)- crash de resposta dupla. Correção: retorne após enviar, nunca chamenextapós responder. next(err)em middleware de erro - passa para o próximo manipulador de erro; chamarnext()sem erro pula para o middleware regular. Correção: finalize a resposta no último manipulador de erro.- Expor
err.stackem produção - vazamento de informação. Correção: registre o stack no lado do servidor, envie uma mensagem genérica para o cliente. - Não tratar 404 separadamente - rotas desconhecidas passam sem resposta. Correção: adicione um catch-all 404 antes do manipulador de erro.
- Async do Express 4 sem wrapper - rejeições não tratadas travam o processo. Correção: atualize para o Express 5 ou use try/catch.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
express-async-errors (Express 4) | Preso no Express 4 | Já está no Express 5 |
Fastify setErrorHandler | App Fastify com erros de schema | Código-fonte Express |
| Filtros de exceção NestJS | Exceções HTTP baseadas em decoradores | API Express simples |
| Tipo Result (neverthrow) | Tratamento de erro funcional em serviços | Equipe prefere throw/catch |
FAQs
O Express 5 ainda precisa de express-async-errors?
Não. O Express 5 encaminha nativamente erros assíncronos para o middleware de erro.
Como lidar com erros operacionais vs. de programador?
Erros operacionais (404, validação) recebem mensagens específicas. Erros de programador (TypeError) são registrados completamente e retornam 500 genérico.
Erros de validação devem retornar 400 ou 422?
Ambos são comuns. Escolha um e documente-o em seus padrões de API. 422 é popular para falhas de validação semântica.
Como testar middleware de erro?
Supertest: request(app).get("/missing").expect(404) e verifique o formato do erro JSON.
E rejeições não tratadas fora das rotas?
Registre process.on("unhandledRejection") para registrar e encerrar graciosamente. Não confie no Express para capturar esses.
Posso ter múltiplos manipuladores de erro?
Sim. Chame next(err) no primeiro para passar para o próximo. O último manipulador deve sempre enviar uma resposta.
Como isso se integra com OpenAPI?
Documente schemas de resposta de erro por código de status. O middleware de erro deve corresponder a esses formatos documentados.
Devo usar `res.sendStatus(500)` no manipulador de erro?
Prefira res.status(500).json({...}) para APIs. sendStatus retorna texto puro.
Relacionados
- Ordem de Middleware - posicionamento do manipulador de erro
- Migração para Express 5 - mudanças em erros assíncronos
- Middleware de Segurança - não vaze erros
- Padrões de Resposta de Erro - formatos de erro de API
- Melhores Práticas do Express - checklist da seção
Versões da Stack: Esta página foi escrita para Node.js 24.18.0 (LTS Ativo), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 e NestJS 11.