alltools.one
API
2025-06-30
9 min
alltools.one Team
JSONAPIRESTDesign PatternsBackend

Padrões de Design de API JSON: Construindo REST APIs Melhores

Uma API bem projetada é um prazer de usar. Uma mal projetada cria bugs, frustração e dívida técnica. Este guia aborda padrões testados em batalha para projetar REST APIs JSON que sejam consistentes, descobríveis e fáceis de manter.

Nomenclatura de Recursos

Recursos são substantivos, não verbos. Use substantivos no plural para coleções e recursos individuais via ID:

GET    /api/users          # List users
POST   /api/users          # Create a user
GET    /api/users/123      # Get user 123
PUT    /api/users/123      # Update user 123
DELETE /api/users/123      # Delete user 123

Convenções de nomenclatura:

  • Use letras minúsculas com hífens: /api/blog-posts (não blogPosts ou blog_posts)
  • Aninhe recursos relacionados: /api/users/123/orders
  • Limite o aninhamento a 2 níveis: /api/users/123/orders/456 (não mais profundo)
  • Evite verbos nas URLs: /api/users/123/activate é aceitável para ações que não se encaixam no CRUD

Envelope de Resposta

Encapsule as respostas em um envelope consistente:

{
  "data": {
    "id": "123",
    "type": "user",
    "attributes": {
      "name": "Alice",
      "email": "alice@example.com",
      "createdAt": "2024-01-15T10:30:00Z"
    }
  },
  "meta": {
    "requestId": "req_abc123"
  }
}

Para coleções:

{
  "data": [
    { "id": "123", "name": "Alice" },
    { "id": "456", "name": "Bob" }
  ],
  "meta": {
    "total": 142,
    "page": 1,
    "perPage": 20
  }
}

Valide as respostas da sua API com nosso Validador JSON para garantir que elas correspondam ao seu schema.

Paginação

Três abordagens comuns:

Baseada em Offset (Mais Simples)

GET /api/users?page=2&per_page=20
{
  "data": [...],
  "meta": {
    "page": 2,
    "perPage": 20,
    "total": 142,
    "totalPages": 8
  }
}

Vantagem: Simples, permite pular para qualquer página. Desvantagem: Resultados inconsistentes com inserções/exclusões concorrentes.

Baseada em Cursor (Mais Confiável)

GET /api/users?cursor=eyJpZCI6MTIzfQ&limit=20
{
  "data": [...],
  "meta": {
    "hasNext": true,
    "nextCursor": "eyJpZCI6MTQzfQ"
  }
}

Vantagem: Consistente com alterações concorrentes, performante em grandes conjuntos de dados. Desvantagem: Não permite pular para páginas arbitrárias.

Baseada em Keyset (Mais Performante)

GET /api/users?after_id=123&limit=20

Usa o ID do último item (ou outro campo ordenado) para buscar a próxima página. Similar à baseada em cursor, mas com parâmetros transparentes.

Recomendação: Use paginação baseada em cursor para feeds em tempo real e grandes conjuntos de dados. Use baseada em offset para painéis administrativos onde a navegação por páginas importa.

Filtragem e Ordenação

Filtragem

GET /api/users?status=active&role=admin
GET /api/users?created_after=2024-01-01
GET /api/users?search=alice

Para filtros complexos, considere um parâmetro de consulta dedicado:

GET /api/users?filter[status]=active&filter[role]=admin

Ordenação

GET /api/users?sort=name          # Ascendente
GET /api/users?sort=-created_at   # Descendente (prefixo com -)
GET /api/users?sort=-created_at,name  # Múltiplos campos

Tratamento de Erros

Respostas de erro consistentes são essenciais para a usabilidade da API:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      {
        "field": "email",
        "message": "Must be a valid email address",
        "value": "not-an-email"
      },
      {
        "field": "age",
        "message": "Must be between 0 and 150",
        "value": -5
      }
    ]
  },
  "meta": {
    "requestId": "req_abc123"
  }
}

Códigos de status HTTP a usar:

CódigoSignificadoQuando
200OKGET, PUT bem-sucedido
201CriadoPOST bem-sucedido
204Sem ConteúdoDELETE bem-sucedido
400Requisição InválidaErros de validação
401Não AutorizadoAutenticação ausente/inválida
403ProibidoAutenticação válida, permissões insuficientes
404Não EncontradoRecurso não existe
409ConflitoRecurso duplicado, conflito de versão
422Não ProcessávelSemanticamente inválido
429Muitas RequisiçõesLimite de taxa excedido
500Erro InternoErro inesperado do servidor

Versionamento

Três abordagens:

Caminho da URL (Recomendado)

GET /api/v1/users
GET /api/v2/users

Vantagem: Explícito, fácil de rotear, fácil de testar.

Baseado em Header

GET /api/users
Accept: application/vnd.myapi.v2+json

Vantagem: URLs limpas. Desvantagem: Mais difícil de testar, menos descobrível.

Parâmetro de Consulta

GET /api/users?version=2

Vantagem: Fácil de testar. Desvantagem: Semântica de parâmetro opcional.

Recomendação: O versionamento por caminho da URL é a escolha mais prática. É explícito, cacheável e funciona com qualquer ferramenta HTTP.

Manipulação de Data e Hora

Sempre use ISO 8601 em UTC:

{
  "createdAt": "2024-01-15T10:30:00Z",
  "updatedAt": "2024-01-15T14:22:33Z",
  "expiresAt": "2024-12-31T23:59:59Z"
}

Nunca use timestamps Unix nas respostas da API — eles são ambíguos (segundos vs milissegundos) e não são legíveis por humanos. Para mais informações sobre manipulação de timestamps, veja nosso guia de Unix Timestamps.

Limitação de Taxa

Comunique os limites de taxa nos headers de resposta:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 67
X-RateLimit-Reset: 1705312800
Retry-After: 30

Retorne 429 Too Many Requests quando o limite for excedido, com uma mensagem de erro clara e o header Retry-After.

HATEOAS (Opcional, Mas Poderoso)

Inclua links para recursos e ações relacionados:

{
  "data": {
    "id": "123",
    "name": "Alice",
    "links": {
      "self": "/api/users/123",
      "orders": "/api/users/123/orders",
      "avatar": "/api/users/123/avatar"
    }
  }
}

Isso torna sua API autodocumentada e reduz a construção de URLs no lado do cliente.

FAQ

Devo usar a especificação JSON:API ou criar meu próprio formato?

A especificação JSON:API (jsonapi.org) fornece um padrão abrangente, mas pode ser verbosa para APIs simples. Para a maioria dos projetos, projetar um formato personalizado mais simples seguindo os padrões deste guia é mais prático. Use JSON:API se precisar de bibliotecas de cliente automáticas e de um padrão rigoroso.

Como devo lidar com atualizações parciais (PATCH vs PUT)?

Use PUT para substituição completa do recurso (o cliente envia todos os campos). Use PATCH para atualizações parciais (o cliente envia apenas os campos alterados). PATCH com JSON Merge Patch (RFC 7396) é a abordagem mais simples: envie um objeto JSON apenas com os campos a serem atualizados e null para remover um campo.

Recursos Relacionados

Published on 2025-06-30
JSON API Design Patterns: Building Better REST APIs | alltools.one