API Design - Princípios RESTful
Esta skill implementa boas práticas para design de APIs RESTful consistentes e intuitivas.
Princípios Fundamentais
┌─────────────────────────────────────────────────────────────┐
│ 1. CONSISTÊNCIA - Padrões previsíveis em toda API │
│ 2. SIMPLICIDADE - Fácil de entender e usar │
│ 3. DOCUMENTAÇÃO - Auto-explicativa quando possível │
│ 4. VERSIONAMENTO - Evoluir sem quebrar clientes │
└─────────────────────────────────────────────────────────────┘
URL Structure
Naming Convention
# ✅ BOM - Substantivos no plural, kebab-case
GET /api/v1/users
GET /api/v1/user-profiles
GET /api/v1/order-items
# ❌ RUIM - Verbos, singular, camelCase
GET /api/v1/getUser
GET /api/v1/user
GET /api/v1/orderItems
Hierarquia de Recursos
# Recurso principal
GET /api/v1/users
# Sub-recurso (pertence a user)
GET /api/v1/users/{userId}/orders
# Máximo 2-3 níveis de aninhamento
GET /api/v1/users/{userId}/orders/{orderId}/items
# Se muito profundo, promova a recurso próprio
GET /api/v1/order-items?orderId={orderId}
HTTP Methods
| Method |
Uso |
Idempotente |
Body |
GET |
Ler recurso(s) |
Sim |
Não |
POST |
Criar recurso |
Não |
Sim |
PUT |
Substituir recurso completo |
Sim |
Sim |
PATCH |
Atualizar parcialmente |
Sim* |
Sim |
DELETE |
Remover recurso |
Sim |
Não |
Exemplos CRUD
# Listar todos os usuários
GET /api/v1/users
# Obter usuário específico
GET /api/v1/users/123
# Criar usuário
POST /api/v1/users
Body: { "name": "João", "email": "joao@email.com" }
# Atualizar usuário (completo)
PUT /api/v1/users/123
Body: { "name": "João Silva", "email": "joao@email.com", "phone": "..." }
# Atualizar usuário (parcial)
PATCH /api/v1/users/123
Body: { "name": "João Silva" }
# Remover usuário
DELETE /api/v1/users/123
Status Codes
Sucesso (2xx)
| Code |
Quando Usar |
200 OK |
GET/PUT/PATCH bem-sucedido |
201 Created |
POST criou recurso |
204 No Content |
DELETE bem-sucedido |
Erro do Cliente (4xx)
| Code |
Quando Usar |
400 Bad Request |
Dados inválidos |
401 Unauthorized |
Não autenticado |
403 Forbidden |
Autenticado mas sem permissão |
404 Not Found |
Recurso não existe |
409 Conflict |
Conflito (ex: email duplicado) |
422 Unprocessable Entity |
Validação falhou |
429 Too Many Requests |
Rate limit excedido |
Erro do Servidor (5xx)
| Code |
Quando Usar |
500 Internal Server Error |
Erro inesperado |
502 Bad Gateway |
Serviço upstream falhou |
503 Service Unavailable |
Serviço temporariamente indisponível |
Request/Response Format
Request Headers
Content-Type: application/json
Authorization: Bearer <token>
Accept: application/json
Accept-Language: pt-BR
X-Request-ID: uuid-for-tracing
Response Structure (Sucesso)
{
"data": {
"id": "123",
"name": "João",
"email": "joao@email.com",
"createdAt": "2025-01-13T10:30:00Z"
}
}
Response Structure (Lista)
{
"data": [
{ "id": "1", "name": "João" },
{ "id": "2", "name": "Maria" }
],
"meta": {
"total": 100,
"page": 1,
"perPage": 20,
"totalPages": 5
}
}
Response Structure (Erro)
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Dados inválidos",
"details": [
{
"field": "email",
"message": "Email inválido"
}
]
}
}
Paginação
Query Parameters
# Offset-based (simples)
GET /api/v1/users?page=2&perPage=20
# Cursor-based (melhor performance)
GET /api/v1/users?cursor=abc123&limit=20
Response com Paginação
{
"data": [...],
"meta": {
"total": 1000,
"page": 2,
"perPage": 20
},
"links": {
"self": "/api/v1/users?page=2",
"first": "/api/v1/users?page=1",
"prev": "/api/v1/users?page=1",
"next": "/api/v1/users?page=3",
"last": "/api/v1/users?page=50"
}
}
Filtering, Sorting, Search
Filtros
# Filtro simples
GET /api/v1/users?status=active
# Múltiplos valores
GET /api/v1/users?status=active,pending
# Operadores
GET /api/v1/orders?total[gte]=100&total[lte]=500
GET /api/v1/users?createdAt[after]=2025-01-01
Ordenação
# Ascendente
GET /api/v1/users?sort=name
# Descendente
GET /api/v1/users?sort=-createdAt
# Múltiplos campos
GET /api/v1/users?sort=-createdAt,name
Busca
# Busca simples
GET /api/v1/users?search=joão
# Busca em campo específico
GET /api/v1/users?name[contains]=silva
Versionamento
Estratégias
| Estratégia |
Exemplo |
Pros |
Cons |
| URL Path |
/api/v1/users |
Explícito, cacheável |
URL muda |
| Header |
Accept-Version: 1 |
URL limpa |
Menos visível |
| Query |
?version=1 |
Fácil testar |
Pode ser esquecido |
Recomendação: URL Path para APIs públicas
Evolução
# Versão atual
GET /api/v1/users
# Nova versão (breaking changes)
GET /api/v2/users
# Manter v1 funcionando por período de deprecação
Autenticação
Bearer Token (JWT)
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
API Key
X-API-Key: your-api-key-here
OAuth 2.0 Flows
| Flow |
Uso |
| Authorization Code |
Web apps com backend |
| PKCE |
Mobile/SPA apps |
| Client Credentials |
Server-to-server |
Rate Limiting
Headers de Resposta
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1673568000
Retry-After: 60
Resposta 429
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Limite de requisições excedido",
"retryAfter": 60
}
}
HATEOAS (Links)
{
"data": {
"id": "123",
"name": "João",
"status": "active"
},
"links": {
"self": "/api/v1/users/123",
"orders": "/api/v1/users/123/orders",
"deactivate": "/api/v1/users/123/deactivate"
}
}
Ações Não-CRUD
Opção 1: Verbo como Sub-recurso
# Ações em recurso
POST /api/v1/users/123/activate
POST /api/v1/orders/456/cancel
POST /api/v1/emails/789/send
Opção 2: Campo de Status
PATCH /api/v1/users/123
Body: { "status": "active" }
Checklist de Design
Antes de Implementar
Durante Implementação
Antes de Publicar
Anti-Patterns
| Anti-Pattern |
Problema |
Solução |
| Verbos na URL |
/getUsers, /createUser |
Use HTTP methods |
| Inconsistência |
/users vs /User |
Padronize plural/kebab |
| Expor IDs internos |
IDs sequenciais |
Use UUIDs ou slugs |
| Retornar HTML em API |
Dificulta consumo |
Sempre JSON |
| Ignorar erros |
Retornar 200 com erro |
Status codes corretos |
Esta skill ativa AUTOMATICAMENTE quando:
- Design de novos endpoints
- Discussão sobre estrutura de API
- Problemas com REST/HTTP