Design de APIs REST
Recursos, nomes, códigos de status e formato de erros em uma API previsível.
As decisões de desenho de uma API REST se repetem em todo projeto. Esta página compara as mais comuns. A regra que vale para todas: decida uma vez, registre num guia de estilo e aplique em toda a API.
PUT ou PATCH
PUT | PATCH | |
|---|---|---|
| Significado | Substitui o recurso inteiro pelo enviado | Altera só os campos enviados |
| Campo omitido | Fica vazio ou recebe o valor padrão | Continua como estava |
| Idempotente | Sim | Depende do formato |
| Formato | O recurso completo | JSON Merge Patch (application/merge-patch+json) ou JSON Patch |
Na prática, a maioria das APIs usa PATCH com JSON Merge Patch: o cliente envia só os campos que mudam, e null remove um campo.
PATCH /clientes/42
Content-Type: application/merge-patch+json
{ "telefone": "+55 41 99999-0000", "apelido": null }O risco do PUT mal implementado: um cliente antigo, que não conhece um campo novo, envia o recurso sem ele e apaga o valor sem perceber.
Identificadores
| Tipo | Exemplo | Vantagens | Cuidados |
|---|---|---|---|
| Sequencial | 981 | Curto, legível, ordenado | Revela volume de negócio e facilita enumerar recursos |
| UUID v4 | 7e2398da-c68a-... | Impossível de adivinhar | Longo; sem ordem, prejudica índices do banco |
| UUID v7 ou ULID | 0193f6a2-... | Impossível de adivinhar e ordenado por tempo | Revela o momento de criação |
| Prefixado | ped_2Nf8... | O tipo do recurso fica visível no próprio identificador | Convenção a manter |
Identificadores sequenciais expostos permitem que alguém percorra /pedidos/1, /pedidos/2 e assim por diante. Isso só é um problema de segurança se a autorização falhar, mas revela informação de negócio de qualquer forma: quantos pedidos a empresa recebeu ontem. Muitos sistemas usam o sequencial internamente e um identificador público diferente na API.
Listas: o que toda lista precisa
| Necessidade | Convenção comum |
|---|---|
| Paginação | Por cursor: ?limite=20&cursor=..., com o próximo cursor na resposta |
| Filtros | Parâmetros com o nome do campo: ?status=pago&clienteId=42 |
| Ordenação | ?ordem=-criadoEm (o sinal indica ordem decrescente) |
| Campos | ?campos=id,status para respostas menores (opcional) |
Toda lista precisa de paginação desde o primeiro dia. Uma lista que devolve tudo funciona com 50 registros e derruba o serviço com 500 mil. O tópico de paginação aprofunda as opções.
Formato da resposta: envelope ou não
| Recurso direto | Envelope | |
|---|---|---|
| Exemplo | { "id": "981", "status": "pago" } | { "data": { "id": "981" }, "meta": { ... } } |
| Vantagem | Simples, segue o HTTP | Lugar fixo para paginação e metadados |
| Erros | problem+json, com o status HTTP | Às vezes "success": false, o que repete o status |
Uma combinação equilibrada: recursos individuais sem envelope; listas com um objeto que contém os itens e as informações de paginação; erros sempre em problem+json, com o código de status correto.
{
"itens": [{ "id": "981", "status": "pago" }],
"proximoCursor": "eyJpZCI6OTgxfQ"
}Operações demoradas
Gerar um relatório, processar um arquivo grande ou importar mil registros pode levar minutos. Manter o pedido HTTP aberto esse tempo todo é frágil: proxies e balanceadores derrubam conexões longas.
POST /relatorios
→ 202 Accepted
Location: /relatorios/77
GET /relatorios/77
→ 200 { "status": "processando" }
→ 200 { "status": "concluido", "arquivo": "/relatorios/77/arquivo" }O pedido inicial devolve 202 Accepted com o endereço de um recurso que representa a operação. O cliente consulta esse endereço, ou recebe um webhook quando terminar.
Desenho primeiro ou código primeiro
| Abordagem | Como funciona | Quando usar |
|---|---|---|
| Contrato primeiro | Escreve o OpenAPI, revisa com quem vai consumir, gera código e testes a partir dele | APIs públicas, vários times consumindo, contratos difíceis de mudar |
| Código primeiro | Escreve o código, e o framework gera o OpenAPI | APIs internas, um único cliente, iteração rápida |
Nos dois casos, o documento OpenAPI deve existir e estar atualizado. O tópico de documentação mostra como.
Resumo da decisão
- Endereços com substantivos no plural; ações especiais como sub-recursos.
- Status previsível por operação;
201comLocationao criar. - Erros sempre em
application/problem+json, comtypeestável. - Alterações parciais com
PATCHe JSON Merge Patch. - Identificadores públicos que não revelam volume nem podem ser percorridos.
- Listas sempre paginadas; operações demoradas com
202. - Um guia de estilo curto, aplicado a todas as rotas.
O próximo nível mostra a criação de um recurso com validação e erros no formato padrão nas cinco linguagens, com o resultado de cada uma.
Prompts para aprofundar
Ao abrir no ChatGPT ou no Claude, o prompt é enviado ao serviço escolhido pela URL e também fica copiado na sua área de transferência.
Escrever o guia de estilo da nossa API
Quero escrever um guia de estilo curto para as APIs da minha equipe, para que todas as rotas sigam as mesmas regras. Pergunte qual linguagem e framework usamos, se as APIs são públicas ou internas e quantas equipes as consomem. Me ajude a decidir e registrar, uma decisão por vez, explicando as opções: 1. Convenção de endereços e nomes. 2. PUT ou PATCH, e qual formato de PATCH. 3. Formato dos erros. 4. Nomes de campos, datas, dinheiro e identificadores. 5. Formato das listas e paginação. 6. Operações demoradas. 7. Contrato primeiro ou código primeiro. Termine com o guia em uma página, pronto para o repositório.
Identificadores públicos
Quero escolher o tipo de identificador que a minha API vai expor. Compare identificadores sequenciais, UUID v4, UUID v7, ULID e identificadores prefixados: tamanho, ordenação, impacto nos índices do banco, o que cada um revela e o risco de enumeração. Explique também a estratégia de ter um identificador interno e outro público, e como migrar uma API que já expõe identificadores sequenciais. Pergunte qual banco eu uso e o volume esperado, e recomende uma opção.
Revisar o desenho de uma API existente
Vou colar abaixo a lista de rotas da minha API, ou o documento OpenAPI, com exemplos de respostas de sucesso e de erro. Revise o desenho. Verifique, e para cada item aponte os problemas com exemplos: 1. Os endereços usam substantivos, plural e um padrão consistente? 2. Há ações em GET ou verbos nos endereços? 3. Os códigos de status são adequados a cada operação? 4. Os erros seguem um formato único? 5. As respostas expõem campos internos? 6. As listas são paginadas? 7. Os nomes de campos, datas e valores monetários seguem um padrão? Para cada problema, mostre a correção e diga se ela quebraria clientes existentes, e como migrar se quebrar. Rotas e exemplos: [cole aqui]