API Design - Princípios RESTful
Esta skill implementa boas práticas para design de APIs RESTful consistentes e intuitivas.
Princípios Fundamentais
code
┌─────────────────────────────────────────────────────────────┐ │ 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
code
# ✅ 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
code
# 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
bash
# 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
http
Content-Type: application/json Authorization: Bearer <token> Accept: application/json Accept-Language: pt-BR X-Request-ID: uuid-for-tracing
Response Structure (Sucesso)
json
{
"data": {
"id": "123",
"name": "João",
"email": "joao@email.com",
"createdAt": "2025-01-13T10:30:00Z"
}
}
Response Structure (Lista)
json
{
"data": [
{ "id": "1", "name": "João" },
{ "id": "2", "name": "Maria" }
],
"meta": {
"total": 100,
"page": 1,
"perPage": 20,
"totalPages": 5
}
}
Response Structure (Erro)
json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Dados inválidos",
"details": [
{
"field": "email",
"message": "Email inválido"
}
]
}
}
Paginação
Query Parameters
bash
# 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
json
{
"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
bash
# 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
bash
# 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
bash
# 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
code
# 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)
http
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
API Key
http
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
http
X-RateLimit-Limit: 100 X-RateLimit-Remaining: 95 X-RateLimit-Reset: 1673568000 Retry-After: 60
Resposta 429
json
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Limite de requisições excedido",
"retryAfter": 60
}
}
HATEOAS (Links)
json
{
"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
bash
# 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
bash
PATCH /api/v1/users/123
Body: { "status": "active" }
Checklist de Design
Antes de Implementar
- • Recursos identificados como substantivos?
- • Hierarquia de recursos definida?
- • Versionamento planejado?
- • Autenticação definida?
Durante Implementação
- • Status codes corretos?
- • Validação de input?
- • Error handling consistente?
- • Rate limiting configurado?
Antes de Publicar
- • Documentação atualizada?
- • Exemplos funcionando?
- • Testes de integração?
- • Monitoring configurado?
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