kb.erickguedes.com
APIs: Design, Arquitetura e Implementação

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.