NoteBugsDocs

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 fieldErrors e formErrors do 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

SituaçãoCódigoO que fazer
Credencial ausente ou vencida401gerar um token novo, ou refazer o login
Papel insuficiente403não insistir: a conta não alcança aquilo
Espaço de trabalho fora do alcance403pedir acesso a um administrador
Recurso inexistente404reconferir o id; ele pode ter sido apagado
Nome duplicado409escolher outro nome dentro daquele espaço
Estado incompatível409ler o estado antes de repetir (backup em curso, .zip não pronto)
Corpo inválido422corrigir a partir de details
Regra de negócio422ler a error: ela diz qual regra
Limite de requisições429esperar o que Retry-After disser
Falha do bucket502conferir credencial e conectividade do serviço de objetos

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-After diz 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/cards que já funcionou cria um segundo card, com número novo.