Pular para o conteúdo
~/.primo-academy.sh
☰ Aulas · Backend · 0/15
Recomendado: essencial

Tratamento de Erros em uma API

1 min de leitura

fonte

Quando uma rota dá erro sem tratamento, o Express devolve um 500 genérico e imprime a stack trace no log. Pra um cliente da sua API, isso é inútil: ele não sabe se o problema foi input inválido (culpa dele), recurso inexistente (esperado) ou bug no servidor (culpa sua).

O caminho profissional é: tipos de erro bem definidos + um middleware central que formata a resposta.

O problema: erro não-tratado em async

app.get("/usuarios/:id", async (req, res) => {
  const id = Number(req.params.id);
  if (Number.isNaN(id)) {
    throw new Error("ID inválido"); // ⚠️ 500 genérico pro cliente
  }
  const usuario = await prisma.user.findUnique({ where: { id } });
  if (!usuario) {
    throw new Error("Usuário não encontrado"); // ⚠️ 500 também
  }
  res.json(usuario);
});

O Express, por padrão, não captura Promise rejeitada numa rota async. Aí ou você embrulha em try/catch em toda rota, ou usa um helper.

Passo 1: classes de erro com semântica

// errors.js
export class HttpError extends Error {
  constructor(status, mensagem) {
    super(mensagem);
    this.status = status;
  }
}

export class NotFoundError extends HttpError {
  constructor(mensagem = "Recurso não encontrado") {
    super(404, mensagem);
  }
}

export class ValidationError extends HttpError {
  constructor(mensagem = "Dados inválidos") {
    super(400, mensagem);
  }
}

Passo 2: lançar nas rotas

import { NotFoundError, ValidationError } from "./errors.js";

app.get("/usuarios/:id", async (req, res) => {
  const id = Number(req.params.id);
  if (Number.isNaN(id)) throw new ValidationError("ID inválido");

  const usuario = await prisma.user.findUnique({ where: { id } });
  if (!usuario) throw new NotFoundError("Usuário não encontrado");

  res.json(usuario);
});

Passo 3: middleware central

// middleware de erro - sempre com 4 argumentos
app.use((err, req, res, next) => {
  const status = err.status ?? 500;
  const mensagem = status === 500 ? "Erro interno do servidor" : err.message;

  if (status === 500) {
    console.error("💥 Erro não tratado:", err); // loga pra você ver
  }

  res.status(status).json({ erro: mensagem });
});

O Express reconhece um middleware como tratador de erro porque tem 4 parâmetros (err, req, res, next) - o next é a dica, mesmo que você não use. Aí, qualquer rota que chamar next(erro) ou lançar dentro de um async wrapper cai aqui.

Três conceitos pra fixar:

  • HttpError - classe base com status; subclasses (NotFoundError, ValidationError) especializam o status.
  • Middleware de erro - função com 4 parâmetros; o Express entende que é o tratador central.
  • Não vaze erro 500 - loga a stack internamente, devolve mensagem genérica pro cliente (segurança + experiência).

Dica: erros 4xx são "culpa do cliente" (input ruim, recurso que não existe) - a mensagem pode ser específica. Erros 5xx são "culpa do servidor" - a mensagem tem que ser genérica pra não vazar detalhe interno.

No próximo nó, vamos ver como organizar a API em vários endpoints REST com status codes corretos.

// recursos

// avaliação da trilha

—
ainda sem avaliações