Integração
Tratamento de erros
Uma forma só de recusa, e o que fazer com cada família dela.
O formato da recusa
Toda recusa, de qualquer rota e em qualquer código, devolve o mesmo objeto:
{
"error": "Card não encontrado.",
"details": null
}- `error` é uma frase em pt-BR, escrita para quem está na tela. Ela pode mudar de redação sem aviso: não construa lógica em cima do texto.
- `details` só é preenchido nas recusas de schema (422), e traz
fieldErrorseformErrorsdo zod. - O código HTTP é o contrato. É nele que a sua integração deve decidir o que fazer.
A recusa de schema, por dentro
{
"error": "Dados inválidos.",
"details": {
"formErrors": ["Nada para atualizar."],
"fieldErrors": {
"name": ["Campo obrigatório."],
"confirm": ["Envie { \"confirm\": \"APAGAR TENANT\" } para confirmar."]
}
}
}fieldErrors é por campo do corpo; formErrors guarda o que não pertence a campo nenhum, como “Nada para atualizar”, que é sobre o objeto inteiro.
As famílias, e o que fazer com cada uma
422 tem duas origens, e o details separa as duas
Com details, foi o schema: o corpo está malformado. Sem details, foi uma regra de negócio conferida dentro da transação: epic de outro projeto, epic travado, coluna fora do conjunto.
O que é seguro repetir
- 429 é a única recusa que pede repetição, e o
Retry-Afterdiz quando. - Toda escrita é transacional: uma requisição recusada não deixou metade do efeito para trás. Repetir depois de corrigir o corpo é seguro.
- Criação não é idempotente. Repetir um
POST /api/cardsque já funcionou cria um segundo card, com número novo.