Design de API
Escolhendo o Tipo de API Certo
| Tipo | Melhor Para | Evitar Quando |
|---|
| REST | APIs públicas, CRUD, clientes simples, IoT | Dados aninhados complexos, iteração rápida de esquema |
| GraphQL | Aplicativos móveis, dados aninhados complexos, múltiplos clientes | CRUD simples, equipes pequenas novas no assunto |
| tRPC | Monorepos TypeScript, APIs TypeScript full-stack internas | Clientes não TypeScript, APIs públicas |
| gRPC | Comunicação entre microsserviços de alto desempenho, streaming | Clientes de navegador, casos de uso simples |
Design de API REST
Convenções de URL
GET /users ← listar
GET /users/{id} ← único
POST /users ← criar
PUT /users/{id} ← substituir
PATCH /users/{id} ← atualização parcial
DELETE /users/{id} ← deletar
# Recursos aninhados
GET /users/{id}/orders
POST /users/{id}/orders
# Ações (quando os verbos REST não são suficientes)
POST /orders/{id}/cancel
POST /users/{id}/activate
Códigos de Status HTTP
| Código | Use Quando |
|---|
| 200 | GET, PUT, PATCH bem-sucedidos |
| 201 | POST bem-sucedido que cria |
| 204 | DELETE bem-sucedido (sem corpo) |
| 400 | Falha de validação, requisição inválida |
| 401 | Autenticação ausente/inválida |
| 403 | Autenticado, mas não autorizado |
| 404 | Recurso não encontrado |
| 409 | Conflito (duplicata, versão incompatível) |
| 422 | Entidade não processável (erros semânticos) |
| 429 | Limite de taxa excedido |
| 500 | Erro inesperado do servidor |
Envelope de Resposta
{
"data": [...],
"meta": { "total": 100, "page": 1, "perPage": 20 }
}
{ "data": { "id": "1", "name": "James" } }
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Falha na validação",
"details": [{ "field": "email", "issue": "Formato inválido" }]
}
}
Princípios de Design de API
Estratégia de Versionamento
# Versionamento por URL (mais visível, mais fácil de rotear)
/v1/users
/v2/users
# Versionamento por cabeçalho (URLs mais limpas)
Accept: application/vnd.api+json;version=2
Nunca quebre clientes existentes. Marque como obsoleto e depois remova.
Paginação
# Offset (simples, bom para conjuntos de dados pequenos)
GET /posts?page=2&perPage=20
# Cursor (rápido para grandes conjuntos de dados, use para rolagem infinita)
GET /posts?cursor=eyJpZCI6MTAwfQ&limit=20
Filtragem e Ordenação
GET /orders?status=pending&userId=123
GET /products?sort=-price,name # - prefix = descendente
GET /products?fields=id,name,price # conjuntos de campos esparsos
Idempotência
# Incluir chave de idempotência para operações não idempotentes
POST /payments
Idempotency-Key: uuid-único-gerado-pelo-cliente
Design GraphQL
Regras de Design de Esquema
- Descreva o domínio do negócio, não a estrutura do banco de dados
- Use o padrão de conexões para listas (pronto para paginação)
- Mutações retornam o objeto modificado
- Use enums para conjuntos finitos de valores
- Adicione descrições a todos os tipos e campos
type Query {
user(id: ID!): User
users(filter: UserFilter, pagination: PaginationInput): UserConnection!
}
type Mutation {
createUser(input: CreateUserInput!): CreateUserPayload!
updateUser(id: ID!, input: UpdateUserInput!): UpdateUserPayload!
}
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
Lista de Verificação de Segurança de API