Design de APIs REST
Aula 2 de 7
Naming Conventions
✅ Correto:
GET /users
GET /users/:id
GET /users/:id/orders
POST /users
PUT /users/:id
PATCH /users/:id
DELETE /users/:id
❌ Errado:
GET /getUsers # verbo no nome
POST /updateUser # verbo
GET /user # singular
POST /users/create # verbo na URL
DELETE /deleteUser?id=1 # query ao invés de path
PATCH /users # sem ID
Filtering, Sorting, Pagination
GET /api/v1/products
?category=electronics
&price[gte]=100
&price[lte]=1000
&sort=-created_at,name
&page=2
&limit=20
&fields=id,name,price
&include=category,variants
&search=smartphone
// Response com pagination
{
"data": [...],
"meta": {
"page": 2,
"limit": 20,
"total": 150,
"totalPages": 8
},
"links": {
"self": "/products?page=2&limit=20",
"first": "/products?page=1&limit=20",
"prev": "/products?page=1&limit=20",
"next": "/products?page=3&limit=20",
"last": "/products?page=8&limit=20"
}
}
Error Handling
// Resposta de erro consistente
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Dados inválidos",
"details": [
{
"field": "email",
"message": "Email inválido",
"code": "INVALID_FORMAT"
},
{
"field": "age",
"message": "Idade deve ser >= 18",
"code": "MIN_VALUE"
}
],
"traceId": "abc-123-def",
"timestamp": "2024-06-01T14:30:00Z"
}
}
HATEOAS — Hypermedia
{
"id": 123,
"name": "João Silva",
"email": "[email protected]",
"_links": {
"self": { "href": "/users/123" },
"orders": { "href": "/users/123/orders" },
"update": { "href": "/users/123", "method": "PUT" },
"delete": { "href": "/users/123", "method": "DELETE" }
}
}
Versionamento
Estratégias de versionamento:
URL Path (mais comum):
GET /api/v1/users
GET /api/v2/users
Header (Accept header):
Accept: application/vnd.empresa.v1+json
Accept: application/vnd.empresa.v2+json
Query parameter:
GET /api/users?version=1
Subdomínio:
https://v1.api.empresa.com/users
Lab: API Design com JSON:API
// Request
POST /api/users
Content-Type: application/vnd.api+json
{
"data": {
"type": "users",
"attributes": {
"name": "Maria",
"email": "[email protected]"
},
"relationships": {
"organization": {
"data": { "type": "organizations", "id": "1" }
}
}
}
}
// Response
{
"data": {
"type": "users",
"id": "456",
"attributes": {
"name": "Maria",
"email": "[email protected]",
"created-at": "2024-06-01T14:30:00Z"
},
"relationships": {
"organization": {
"data": { "type": "organizations", "id": "1" },
"links": {
"related": "/users/456/organization"
}
}
},
"links": {
"self": "/users/456"
}
},
"included": [
{
"type": "organizations",
"id": "1",
"attributes": {
"name": "Empresa XYZ"
}
}
]
}
Consistência > criatividade. Use sempre o mesmo padrão de response, erro e paginação. Versionamento por URL path é o mais prático. Documente com OpenAPI antes de implementar.