Formatos de Resposta de API: Boas Práticas para APIs Consistentes
Respostas de API inconsistentes são uma das principais reclamações dos desenvolvedores frontend. Quando cada endpoint retorna dados em um formato diferente, o código do cliente fica cheio de casos especiais. Um formato de resposta consistente melhora a experiência do desenvolvedor, reduz bugs e torna sua API autodocumentável.
O Envelope de Resposta
Envolva toda resposta em uma estrutura consistente:
Sucesso (Recurso Único)
{
"data": {
"id": "user_123",
"name": "Alice",
"email": "alice@example.com",
"createdAt": "2024-01-15T10:30:00Z"
},
"meta": {
"requestId": "req_abc123"
}
}
Sucesso (Coleção)
{
"data": [
{ "id": "user_123", "name": "Alice" },
{ "id": "user_456", "name": "Bob" }
],
"meta": {
"total": 142,
"page": 1,
"perPage": 20,
"requestId": "req_def456"
}
}
Erro
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": [
{ "field": "email", "message": "Invalid email format" }
]
},
"meta": {
"requestId": "req_ghi789"
}
}
O princípio fundamental: os clientes sempre verificam data ou error no nível superior. Nunca misture dados de sucesso e informações de erro na mesma resposta.
Valide seu formato de resposta com nosso Validador JSON.
Códigos de Status HTTP
Use os códigos de status corretamente — eles são a primeira coisa que os clientes verificam:
Códigos de Sucesso
| Código | Quando Usar |
|---|---|
| 200 OK | Sucesso em GET, sucesso em PUT/PATCH |
| 201 Created | POST que criou um recurso |
| 204 No Content | Sucesso em DELETE (sem corpo) |
Códigos de Erro do Cliente
| Código | Quando Usar |
|---|---|
| 400 Bad Request | Sintaxe de requisição malformada |
| 401 Unauthorized | Autenticação ausente ou inválida |
| 403 Forbidden | Autenticado, mas não autorizado |
| 404 Not Found | Recurso não existe |
| 409 Conflict | Conflito de estado do recurso (duplicata) |
| 422 Unprocessable | Sintaxe válida, mas erros semânticos |
| 429 Too Many Requests | Limite de requisições excedido |
Códigos de Erro do Servidor
| Código | Quando Usar |
|---|---|
| 500 Internal Server Error | Falha inesperada no servidor |
| 502 Bad Gateway | Falha no serviço upstream |
| 503 Service Unavailable | Sobrecarga temporária ou manutenção |
Design de Resposta de Erro
Boas respostas de erro ajudam desenvolvedores a depurar rapidamente:
{
"error": {
"code": "RESOURCE_NOT_FOUND",
"message": "User with ID 'user_999' not found",
"details": [],
"documentationUrl": "https://api.example.com/docs/errors#RESOURCE_NOT_FOUND"
},
"meta": {
"requestId": "req_xyz789",
"timestamp": "2024-01-15T10:30:00Z"
}
}
Regras:
codeé legível por máquina (string constante, não o status HTTP)messageé legível por humanos (pode mudar sem quebrar os clientes)detailsfornece erros a nível de campo para falhas de validaçãorequestIdpermite que a equipe de suporte rastreie a requisição nos logs
Padrões de Paginação
Baseada em Offset
Simples e suporta navegação para páginas arbitrárias:
{
"data": ["..."],
"meta": {
"page": 2,
"perPage": 20,
"total": 142,
"totalPages": 8
},
"links": {
"first": "/api/users?page=1&per_page=20",
"prev": "/api/users?page=1&per_page=20",
"next": "/api/users?page=3&per_page=20",
"last": "/api/users?page=8&per_page=20"
}
}
Baseada em Cursor
Melhor para dados em tempo real e grandes conjuntos de dados:
{
"data": ["..."],
"meta": {
"hasNext": true,
"hasPrev": true
},
"links": {
"next": "/api/users?cursor=eyJpZCI6MTQzfQ&limit=20",
"prev": "/api/users?cursor=eyJpZCI6MTIzfQ&limit=20&direction=prev"
}
}
Data e Hora
Sempre use ISO 8601 com informação de fuso horário:
{
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T14:22:33+00:00",
"expiresAt": "2024-12-31T23:59:59Z"
}
Nunca use:
- Timestamps Unix (ambíguo: segundos ou milissegundos?)
- Datas locais sem fuso horário
- Formatos personalizados como MM/DD/AAAA
Para mais informações sobre tratamento de timestamps, veja nosso guia de Timestamps Unix.
Null vs Campos Ausentes
Duas abordagens comuns:
Incluir com null (explícito):
{ "name": "Alice", "avatar": null, "bio": null }
Omitir campos ausentes (esparso):
{ "name": "Alice" }
Recomendação: Seja consistente dentro da sua API. Nulls explícitos são melhores para linguagens tipadas (os clientes sabem que o campo existe). Esparso é melhor para ambientes com restrição de banda.
Versionamento de Respostas
Quando o formato de resposta muda, versione sua API:
GET /api/v2/users/123
Mudanças que quebram compatibilidade e exigem versionamento:
- Remover um campo
- Alterar o tipo de um campo
- Renomear um campo
- Alterar a estrutura do envelope de resposta
Mudanças não destrutivas (seguras sem versionamento):
- Adicionar novos campos
- Adicionar novos endpoints
- Adicionar novos valores enum
FAQ
Devo encapsular respostas de sucesso em uma chave data ou retornar o recurso diretamente?
Usar um wrapper data fornece uma estrutura consistente para todas as respostas e deixa espaço para metadados, paginação e links ao lado dos dados. Retornar o recurso diretamente é mais simples para endpoints de recurso único. A maioria das APIs modernas usa a abordagem de wrapper para consistência.
Como devo lidar com falhas parciais em operações em lote?
Retorne 200 com uma resposta que inclua tanto sucessos quanto falhas no objeto data. Usar 207 Multi-Status (WebDAV) é outra opção, mas menos comum em APIs REST.
Recursos Relacionados
- Formatador JSON — Formate respostas de API
- Padrões de Design de API JSON — Guia completo de design de API
- Validação com JSON Schema — Valide estruturas de resposta