Árvore de Decisão
Comece aqui e siga o caminho que se adequa à sua situação.
A requisição foi bem-sucedida?
Sim e estou retornando dados -> 200 OK
Resposta de sucessó padrão. Use para requisições GET que retornam dados, requisições POST que realizam ações e requisições PUT/PATCH que atualizam e retornam o resultado.
Sim e criei um novo recursó -> 201 Created
Use após POST ou PUT ter criado algo novo. Inclua um cabeçalho Location com a URL do novo recurso.
Sim mas não há corpo para retornar -> 204 No Content
Use para requisições DELETE bem-sucedidas ou PUT/PATCH onde o cliente não precisa do recursó atualizado. A resposta não tem corpo.
Sim mas já fiz issó antes -> 200 OK ou 204 No Content
Para operações idempotentes (PUT, DELETE) onde o estado final é o mêsmo independente de quantas vezes for chamado, retorne o mêsmo código de sucessó que retornaria na primeira chamada.
Aceito mas ainda não terminado -> 202 Accepted
Use quando o servidor colocou a requisição na fila para processamento assíncrono. O cliente deve fazer polling ou receber um callback mais tarde. Bom para trabalhos longos, operações em lote ou entregas de webhook.
O cliente precisa ir para outro lugar?
Mudança permanente -> 301 Moved Permanently
O recursó tem uma nova URL permanentemente. Navegadores e motores de busca atualizam seus registros. Seguro para requisições GET. Nota: alguns clientes antigos mudam POST para GET no redirecionamento.
Mudança permanente, preservar método -> 308 Permanent Redirect
Como 301, mas garante que o método HTTP é preservado. Um POST continua sendo POST. Use quando a preservação do método é importante (redirecionamentos de API).
Mudança temporária -> 302 Found
O recursó está temporariamente em uma URL diferente. Navegadores armazenam em cache para a sessão mas verificam novamente depois. Na prática, o redirecionamento temporário mais comum.
Mudança temporária, preservar método -> 307 Temporary Redirect
Como 302, mas preserva o método HTTP. Use para redirecionamentos temporários de API onde um POST deve permanecer POST.
Ver outro -> 303 See Other
Use após um POST para redirecionar o cliente a um endpoint GET. Padrão comum: POST /orders retorna 303 com Location: /orders/123, então o cliente faz GET do novo pedido.
O problema está no lado do cliente?
Requisição malformada -> 400 Bad Request
A sintaxe da requisição está errada. JSON inválido, Content-Type ausente, corpo indecodificável. O cliente precisa corrigir a requisição antes de tentar novamente.
Não autenticado -> 401 Unauthorized
Nenhuma credencial fornecida, ou as credenciais estão expiradas/inválidas. O cliente deve se autenticar (login, refresh token) e tentar novamente.
Autenticado mas sem permissão -> 403 Forbidden
O servidor sabe quem é o cliente mas ele não tem permissão. Reautenticar não ajudará. Verifique papéis/permissões.
Recursó não existe -> 404 Not Found
A URL não corresponde a nenhum recurso. Também comumente usado para esconder a existência de recursos que o cliente não tem permissão de saber (em vez de 403).
Método HTTP errado -> 405 Method Not Allowed
O endpoint existe mas não suporta este método. Exemplo: tentar DELETE em um endpoint somente leitura. Inclua um cabeçalho Allow listando métodos válidos.
Conflito com estado atual -> 409 Conflict
A requisição conflita com o estado atual do recurso. Usos comuns: tentativas de criação duplicada, falhas de locking otimista (versão divergente), violações de máquina de estado (tentar publicar um post já publicado).
Recursó foi removido -> 410 Gone
Como 404, mas o servidor sabe que este recursó existia antes e foi removido intencionalmente. Sinal mais forte que 404 para motores de busca e caching.
Erro de válidação -> 422 Unprocessable Entity
A sintaxe é válida (é JSON correto) mas o conteúdo está errado. Campos obrigatórios faltando, tipos de dados errados, valores fora do intervalo. Use para falhas de válidação de lógica de negócio.
Muitas requisições -> 429 Too Many Requests
Raté limiting. Inclua um cabeçalho Retry-After informando ao cliente quando tentar novamente.
O problema está no lado do servidor?
Erro inesperado do servidor -> 500 Internal Server Error
Algo quebrou. Exceção não tratada, ponteiro nulo, erro de configuração. O para-choques para “issó é culpa nossa.” Log o erro, não exponha detalhes internos ao cliente.
Não implementado -> 501 Not Implemented
O servidor não suporta esta funcionalidade. Use para endpoints que estão definidos mas ainda não construídos, ou para métodos HTTP que o servidor não reconhece.
Serviço upstream falhou -> 502 Bad Gateway
O servidor está atuando como proxy/gateway e recebeu uma resposta inválida do serviço upstream. Comum com load balancers e reverse proxies quando um backend falha.
Serviço sobrecarregado ou em manutenção -> 503 Service Unavailable
O servidor não pode lidar com a requisição agora. Pode estar sobrecarregado, em manutenção ou inicializando. Inclua um cabeçalho Retry-After se você souber quando voltará.
Upstream timeout -> 504 Gateway Timeout
O servidor está atuando como proxy é o upstream não respondeu a tempo. Diferente de 408 (timeout do cliente): 504 significa que o próprio upstream do servidor excedeu o tempo limite.
Tabela de Referência Rápida
Sucessó (2xx)
| Código | Nome | Quando usar |
|---|---|---|
| 200 | OK | Sucessó padrão, retornando dados |
| 201 | Created | Novo recursó criado (incluir Location header) |
| 202 | Accepted | Processamento assíncrono iniciado |
| 204 | No Content | Sucesso, sem corpo (DELETE, PUT fire-and-forget) |
Redirecionamento (3xx)
| Código | Nome | Preserva método? | Permanente? |
|---|---|---|---|
| 301 | Moved Permanently | Não (pode mudar para GET) | Sim |
| 302 | Found | Não (pode mudar para GET) | Não |
| 303 | See Other | Sempre muda para GET | N/A |
| 307 | Temporary Redirect | Sim | Não |
| 308 | Permanent Redirect | Sim | Sim |
Erro do Cliente (4xx)
| Código | Nome | Quando usar |
|---|---|---|
| 400 | Bad Request | Sintaxe malformada |
| 401 | Unauthorized | Credenciais ausentes ou inválidas |
| 403 | Forbidden | Autenticado mas sem permissão |
| 404 | Not Found | Recursó não existe |
| 405 | Method Not Allowed | Método HTTP errado |
| 409 | Conflict | Conflito de estado (duplicatas, versão divergente) |
| 410 | Gone | Recursó removido permanentemente |
| 422 | Unprocessable Entity | Sintaxe válida, dados inválidos |
| 429 | Too Many Requests | Raté limit excedido |
Erro do Servidor (5xx)
| Código | Nome | Quando usar |
|---|---|---|
| 500 | Internal Server Error | Falha não tratada do servidor |
| 502 | Bad Gateway | Upstream retornou resposta inválida |
| 503 | Service Unavailable | Sobrecarregado ou em manutenção |
| 504 | Gateway Timeout | Upstream não respondeu a tempo |
Padrões Comuns de API
Operações CRUD REST
| Operação | Método | Código de sucessó | Códigos de erro |
|---|---|---|---|
| Listar recursos | GET | 200 | 401, 403 |
| Obter um recursó | GET | 200 | 401, 403, 404 |
| Criar recursó | POST | 201 | 400, 401, 403, 409, 422 |
| Atualização completa | PUT | 200 ou 204 | 400, 401, 403, 404, 422 |
| Atualização parcial | PATCH | 200 ou 204 | 400, 401, 403, 404, 422 |
| Remover recursó | DELETE | 204 | 401, 403, 404 |
Cabeçalhos que você deve incluir
| Código de status | Cabeçalho recomendado |
|---|---|
| 201 | Location: /resource/id |
| 301, 302, 307, 308 | Location: https://new-url |
| 405 | Allow: GET, POST |
| 429 | Retry-After: 60 |
| 503 | Retry-After: 300 |