Padrões de Design de APIs JSON: Construir Melhores APIs REST
Uma API bem concebida é um prazer de utilizar. Uma mal concebida cria erros, frustração e dívida técnica. Este guia abrange padrões testados em combate para conceber APIs REST JSON que são consistentes, descobríveis e fáceis de manter.
Nomenclatura de Recursos
Os recursos são substantivos, não verbos. Utilize substantivos no plural para coleções e recursos individuais via ID:
GET /api/users # List users
POST /api/users # Create a user
GET /api/users/123 # Get user 123
PUT /api/users/123 # Update user 123
DELETE /api/users/123 # Delete user 123
Convenções de nomenclatura:
- Utilize minúsculas com hífenes:
/api/blog-posts(nãoblogPostsoublog_posts) - Aninhe recursos relacionados:
/api/users/123/orders - Limite o aninhamento a 2 níveis:
/api/users/123/orders/456(não mais profundo) - Evite verbos nos URLs:
/api/users/123/activateé aceitável para ações que não mapeiam para CRUD
Envelope de Resposta
Envolva as respostas num envelope consistente:
{
"data": {
"id": "123",
"type": "user",
"attributes": {
"name": "Alice",
"email": "alice@example.com",
"createdAt": "2024-01-15T10:30:00Z"
}
},
"meta": {
"requestId": "req_abc123"
}
}
Para coleções:
{
"data": [
{ "id": "123", "name": "Alice" },
{ "id": "456", "name": "Bob" }
],
"meta": {
"total": 142,
"page": 1,
"perPage": 20
}
}
Valide as respostas da sua API com o nosso Validador de JSON para garantir que correspondem ao seu schema.
Paginação
Três abordagens comuns:
Baseada em Offset (Mais Simples)
GET /api/users?page=2&per_page=20
{
"data": [...],
"meta": {
"page": 2,
"perPage": 20,
"total": 142,
"totalPages": 8
}
}
Vantagem: Simples, suporta saltar para qualquer página. Desvantagem: Resultados inconsistentes com inserções/eliminações concorrentes.
Baseada em Cursor (Mais Fiável)
GET /api/users?cursor=eyJpZCI6MTIzfQ&limit=20
{
"data": [...],
"meta": {
"hasNext": true,
"nextCursor": "eyJpZCI6MTQzfQ"
}
}
Vantagem: Consistente com alterações concorrentes, performante em grandes conjuntos de dados. Desvantagem: Não permite saltar para páginas arbitrárias.
Baseada em Keyset (Mais Performante)
GET /api/users?after_id=123&limit=20
Utiliza o ID do último item (ou outro campo ordenado) para obter a página seguinte. Semelhante à baseada em cursor mas com parâmetros transparentes.
Recomendação: Utilize baseada em cursor para feeds em tempo real e grandes conjuntos de dados. Utilize baseada em offset para painéis de administração onde saltar entre páginas é importante.
Filtragem e Ordenação
Filtragem
GET /api/users?status=active&role=admin
GET /api/users?created_after=2024-01-01
GET /api/users?search=alice
Para filtros complexos, considere um parâmetro de consulta dedicado:
GET /api/users?filter[status]=active&filter[role]=admin
Ordenação
GET /api/users?sort=name # Ascending
GET /api/users?sort=-created_at # Descending (prefix with -)
GET /api/users?sort=-created_at,name # Multiple fields
Tratamento de Erros
Respostas de erro consistentes são críticas para a usabilidade da API:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": [
{
"field": "email",
"message": "Must be a valid email address",
"value": "not-an-email"
},
{
"field": "age",
"message": "Must be between 0 and 150",
"value": -5
}
]
},
"meta": {
"requestId": "req_abc123"
}
}
Códigos de estado HTTP a utilizar:
| Código | Significado | Quando |
|---|---|---|
| 200 | OK | GET, PUT com sucesso |
| 201 | Criado | POST com sucesso |
| 204 | Sem Conteúdo | DELETE com sucesso |
| 400 | Pedido Inválido | Erros de validação |
| 401 | Não Autorizado | Autenticação em falta/inválida |
| 403 | Proibido | Autenticação válida, permissões insuficientes |
| 404 | Não Encontrado | O recurso não existe |
| 409 | Conflito | Recurso duplicado, conflito de versão |
| 422 | Não Processável | Semanticamente inválido |
| 429 | Demasiados Pedidos | Limite de taxa excedido |
| 500 | Erro Interno | Erro inesperado do servidor |
Versionamento
Três abordagens:
Caminho do URL (Recomendado)
GET /api/v1/users
GET /api/v2/users
Vantagem: Explícito, fácil de encaminhar, fácil de testar.
Baseado em Cabeçalho
GET /api/users
Accept: application/vnd.myapi.v2+json
Vantagem: URLs limpos. Desvantagem: Mais difícil de testar, menos descobrível.
Parâmetro de Consulta
GET /api/users?version=2
Vantagem: Fácil de testar. Desvantagem: Semântica de parâmetro opcional.
Recomendação: O versionamento por caminho de URL é a escolha mais prática. É explícito, cacheável e funciona com todas as ferramentas HTTP.
Gestão de Datas e Horas
Utilize sempre ISO 8601 em UTC:
{
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T14:22:33Z",
"expiresAt": "2024-12-31T23:59:59Z"
}
Nunca utilize timestamps Unix nas respostas da API — são ambíguos (segundos vs milissegundos) e não são legíveis por humanos. Para mais informações sobre o tratamento de timestamps, consulte o nosso guia de Unix Timestamps.
Limitação de Taxa
Comunique os limites de taxa nos cabeçalhos de resposta:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 67
X-RateLimit-Reset: 1705312800
Retry-After: 30
Devolva 429 Too Many Requests quando o limite é excedido, com uma mensagem de erro clara e o cabeçalho Retry-After.
HATEOAS (Opcional mas Poderoso)
Inclua ligações para recursos e ações relacionados:
{
"data": {
"id": "123",
"name": "Alice",
"links": {
"self": "/api/users/123",
"orders": "/api/users/123/orders",
"avatar": "/api/users/123/avatar"
}
}
}
Isto torna a sua API autodocumentada e reduz a construção de URLs do lado do cliente.
FAQ
Devo utilizar a especificação JSON:API ou conceber o meu próprio formato?
A especificação JSON:API (jsonapi.org) fornece um padrão abrangente, mas pode ser verbosa para APIs simples. Para a maioria dos projetos, conceber um formato personalizado mais simples seguindo os padrões deste guia é mais prático. Utilize JSON:API se precisar de bibliotecas de cliente automáticas e de um padrão rigoroso.
Como devo lidar com atualizações parciais (PATCH vs PUT)?
Utilize PUT para substituição completa do recurso (o cliente envia todos os campos). Utilize PATCH para atualizações parciais (o cliente envia apenas os campos alterados). PATCH com JSON Merge Patch (RFC 7396) é a abordagem mais simples: envie um objeto JSON apenas com os campos a atualizar, e null para remover um campo.
Recursos Relacionados
- Formatador de JSON — Formate respostas de API para legibilidade
- Guia de Validação de JSON Schema — Valide payloads de API com JSON Schema
- Tokens JWT Explicados — Proteja as suas APIs com JSON Web Tokens