Pular para conteúdo

0017 — Contrato de erro único {code, message}

Decisão obsoleta — superada pela decisão 0021

Status: Obsoleto · Responsável: Gustavo Madruga · Atualizado em: 2026-06-19 · Decidido em: 2026-06-17

Superada pela decisão 0021: o app alinhou ao default da casa (RFC 7807). O contrato de erro hoje é application/problem+json.

Contexto

A API tinha três formatos de corpo de erro convivendo: o Hateoas default do Micronaut ({message, _links, _embedded}) nas HttpStatusException; um envelope ad-hoc {error, message} no login; e o status-no-corpo do /processar (ProcessamentoResponse.httpStatus). Não havia ponto único de tradução, nem Bean Validation — toda validação era if manual. Cliente recebia formato diferente conforme o endpoint.

Decisão

  • Corpo de erro único {code, message} (ErrorResponse), renderizado num ponto só pelo UnifiedErrorResponseProcessor (@Replaces do HateoasErrorResponseProcessor). Cobre HttpStatusException, falhas de validação, 404 de rota e parse de JSON. code é estável/legível por máquina (ex.: CONFLICT); o status HTTP vai na resposta. O AuthException ganha um ExceptionHandler (rede de segurança).
  • Bean Validation ativado nos pontos limpos (@Positive no wait_secs, @Size no motivo). A trilha de segurança do login (CSRF constant-time, limite de token) fica manual de propósito: convertê-la em constraints reordenaria a sequência de checagem (CSRF-first) e genericizaria os códigos estáveis (csrf_mismatch, token_too_large). Migra junto do login no micronaut-security.

Consequências

  • Contrato de erro consistente e descobrível; um teste fixa o {code, message} em 404/400 (não existia teste de corpo de erro antes).
  • O corpo público do /processar foi preservado (status 2xx mantém o corpo de negócio, nunca o code; o httpStatus segue interno, nunca serializado) — nenhum cliente quebra.
  • Validação declarativa onde cabe; o resto (parse de data/hora, segurança) permanece manual por ser parse de formato ou ordem-sensível.

Alternativas consideradas

  • RFC 7807 / ProblemDetail: mais completo, mas o {code, message} já unifica e reaproveita o code estável que o login expunha. Descartado por simplicidade.
  • Push completo de Bean Validation (inclusive login): descartado — degrada a trilha de segurança sem ganho real (ver acima).