Design de REST API com Claude Code: endpoints, erros, paginação e idempotência
Desenhe REST APIs com Claude Code antes do código: OpenAPI, erros, paginação, idempotência e checklist.
Uma REST API não está pronta só porque algumas rotas foram criadas. Antes da implementação, defina o que é recurso, qual método HTTP cada operação usa, o que a API retorna quando falha, como as listas serão paginadas e como uma requisição repetida será tratada. Se isso ficar em aberto, Claude Code pode escrever código rápido, mas frontend, app móvel e integrações externas vão interpretar contratos diferentes.
Este artigo mostra como usar Claude Code para fechar o design da REST API antes do código. REST significa Representational State Transfer, mas na prática basta entendê-lo como um conjunto de regras para operar recursos como pedidos, usuários e faturas via HTTP. O recurso é o objeto, o método é a operação e o status code é o sinal do resultado.
Como referências oficiais, use HTTP request methods e HTTP response status codes da MDN, além da OpenAPI Specification. Em 3 de junho de 2026, a página latest do OpenAPI aponta para 3.2.0; o exemplo usa openapi: 3.1.0 porque muitos linters e geradores ainda lidam melhor com essa versão.
Para a parte de implementação, veja também desenvolvimento de API com Claude Code, testes de API com Claude Code e code review com Claude Code. Templates e checklists reutilizáveis estão em /products/, e treinamento para padronizar revisões de design de API em equipe está em /training/.
Alinhar O Vocabulário Primeiro
Iniciantes costumam se confundir porque os termos de REST são próximos. Antes de pedir implementação ao Claude Code, use estas palavras com o mesmo significado no time.
| Termo | Explicação simples | Exemplo |
|---|---|---|
| Recurso | O substantivo manipulado pela API | orders, customers |
| Endpoint | URL mais método HTTP | GET /v1/orders |
| Método | Verbo HTTP que indica a operação | GET, POST, PATCH |
| Status code | Número que sinaliza sucesso, erro de entrada, falta de autenticação etc. | 200, 201, 400, 404 |
| Validação | Checagem de que a requisição tem o formato correto | Formato de e-mail, quantidade mínima |
| Idempotência | Repetir a mesma operação não muda o estado final | Criar um pedido para a mesma chave |
Claude Code lê contexto bem, mas não garante adivinhar a intenção de design. “Crie a API de pedidos” pode virar /createOrder, /orders/create ou POST /orders. Passar vocabulário e regras antes do código melhora muito o resultado.
Decidir Com Três Casos De Uso
A mesma API de pedidos pede prioridades diferentes conforme o uso.
O primeiro caso é uma integração B2B SaaS. Se um parceiro reenviar o mesmo CSV noturno, POST /v1/orders precisa de Idempotency-Key para não criar pedidos duplicados. Retentativas aparecem em recuperação de incidentes, então idempotência é difícil de acrescentar depois.
O segundo caso é uma lista administrativa. Uma pessoa filtra por status=paid, avança para a próxima página e outra pessoa cria um pedido ao mesmo tempo. page=2 pode deslocar os resultados. Use paginação por cursor com limit e after, e fixe a ordenação, por exemplo createdAt desc, id desc.
O terceiro caso é uma API para aplicativo móvel. Se versões antigas ficam instaladas por meses, nomes de campos de resposta não podem mudar de repente. Novos campos obrigatórios ou novo formato de erro devem ir para /v2, enquanto o contrato /v1 permanece no OpenAPI. Campos opcionais pequenos normalmente não exigem nova versão.
Um quarto caso comum é API interna entre serviços. É mais fácil atualizar consumidores juntos, mas monitoramento e alertas costumam ser mais fracos. Mesmo internamente, status codes e formatos de erro inconsistentes fazem cada chamador criar tratamento próprio.
Ver O Fluxo De Design
Fixe o design nesta ordem antes de entregar a tarefa ao Claude Code. Isso evita que a implementação se afaste do contrato enquanto os arquivos são editados.
flowchart TD
A["Use cases"] --> B["Resources and endpoints"]
B --> C["OpenAPI contract"]
C --> D["Errors, pagination, idempotency"]
D --> E["Claude Code implementation"]
E --> F["Tests and review"]
Fixar A Tabela De Endpoints Antes Do Código
O primeiro entregável não é código. É uma tabela de endpoints. Entregue-a ao Claude Code para que rotas, OpenAPI, testes e documentação partam do mesmo contrato.
| Objetivo | Método e caminho | Sucesso | Regra importante |
|---|---|---|---|
| Listar pedidos | GET /v1/orders?status=paid&limit=20&after=ord_123 | 200 OK | Paginação por cursor com ordenação estável |
| Criar pedido | POST /v1/orders | 201 Created | Aceitar Idempotency-Key e retornar Location |
| Ver pedido | GET /v1/orders/{orderId} | 200 OK | Se não existir, retornar 404 |
| Atualizar pedido | PATCH /v1/orders/{orderId} | 200 OK | Atualização parcial; patch vazio é 400 |
| Cancelar pedido | POST /v1/orders/{orderId}/cancel | 200 OK | Tratar transições de estado com consistência |
A regra geral é “substantivos na URL, verbos no método”. Algumas ações de negócio, como cancelar pedido, são mais claras como subação explícita do que forçadas em DELETE. O essencial é documentar a exceção e usar o mesmo padrão em operações semelhantes.
Usar OpenAPI Como Fonte Do Design
OpenAPI descreve caminhos, parâmetros, requisições e respostas em formato legível por ferramentas. Ao dizer a Claude Code que esse contrato OpenAPI é a fonte da verdade, você limita a liberdade de implementação ao espaço certo.
openapi: 3.1.0
info:
title: Acme Orders API
version: 1.0.0
servers:
- url: https://api.example.com
paths:
/v1/orders:
get:
operationId: listOrders
summary: List orders
parameters:
- $ref: "#/components/parameters/StatusParam"
- $ref: "#/components/parameters/LimitParam"
- $ref: "#/components/parameters/AfterParam"
responses:
"200":
description: Orders are returned in a stable cursor order.
content:
application/json:
schema:
$ref: "#/components/schemas/OrderListResponse"
"400":
$ref: "#/components/responses/BadRequest"
post:
operationId: createOrder
summary: Create an order
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateOrderRequest"
responses:
"201":
description: Order created.
headers:
Location:
schema:
type: string
description: URL of the created order.
content:
application/json:
schema:
$ref: "#/components/schemas/OrderResponse"
"400":
$ref: "#/components/responses/BadRequest"
"409":
$ref: "#/components/responses/Conflict"
/v1/orders/{orderId}:
get:
operationId: getOrder
summary: Get one order
parameters:
- $ref: "#/components/parameters/OrderId"
responses:
"200":
description: Order found.
content:
application/json:
schema:
$ref: "#/components/schemas/OrderResponse"
"404":
$ref: "#/components/responses/NotFound"
patch:
operationId: updateOrder
summary: Update mutable order fields
parameters:
- $ref: "#/components/parameters/OrderId"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateOrderRequest"
responses:
"200":
description: Order updated.
content:
application/json:
schema:
$ref: "#/components/schemas/OrderResponse"
"400":
$ref: "#/components/responses/BadRequest"
"404":
$ref: "#/components/responses/NotFound"
components:
parameters:
OrderId:
name: orderId
in: path
required: true
schema:
type: string
StatusParam:
name: status
in: query
schema:
type: string
enum: [draft, paid, canceled]
LimitParam:
name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 20
AfterParam:
name: after
in: query
schema:
type: string
description: Cursor returned by the previous response.
IdempotencyKey:
name: Idempotency-Key
in: header
required: false
schema:
type: string
minLength: 16
maxLength: 128
schemas:
CreateOrderRequest:
type: object
required: [customerId, items]
properties:
customerId:
type: string
items:
type: array
minItems: 1
items:
type: object
required: [sku, quantity]
properties:
sku:
type: string
quantity:
type: integer
minimum: 1
UpdateOrderRequest:
type: object
minProperties: 1
properties:
status:
type: string
enum: [draft, paid, canceled]
OrderResponse:
type: object
required: [data]
properties:
data:
$ref: "#/components/schemas/Order"
OrderListResponse:
type: object
required: [data, pageInfo]
properties:
data:
type: array
items:
$ref: "#/components/schemas/Order"
pageInfo:
type: object
required: [nextCursor, hasMore]
properties:
nextCursor:
type: [string, "null"]
hasMore:
type: boolean
Order:
type: object
required: [id, status, totalCents, createdAt]
properties:
id:
type: string
status:
type: string
totalCents:
type: integer
createdAt:
type: string
format: date-time
ErrorResponse:
type: object
required: [error]
properties:
error:
type: object
required: [code, message, requestId]
properties:
code:
type: string
message:
type: string
requestId:
type: string
details:
type: array
items:
type: object
responses:
BadRequest:
description: Request validation failed.
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
Conflict:
description: Idempotency key conflicts with a different request.
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
NotFound:
description: Resource was not found.
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
Salve como openapi.yaml e diga ao Claude Code para não propor implementação que se desvie dele. Depois, npx @redocly/cli lint openapi.yaml pode checar sintaxe e referências. Se você gerar tipos ou clientes TypeScript a partir do OpenAPI, revise antes o sentido humano da tabela de endpoints.
Padronizar Erros E Status Codes
O status code é o sinal HTTP externo. O corpo JSON traz o detalhe para pessoas e programas. Retornar 200 OK com { "success": false } faz monitoramento, SDKs e lógica de retry tratarem falha como sucesso. Defina antes: entrada inválida é 400, autenticação ausente é 401, permissão insuficiente é 403, recurso inexistente é 404, duplicidade ou conflito de idempotência é 409.
{
"error": {
"code": "VALIDATION_FAILED",
"message": "Request body has invalid fields.",
"requestId": "req_01J0RESTAPI001",
"details": [
{
"field": "items[0].quantity",
"reason": "must be greater than or equal to 1"
}
]
}
}
{
"error": {
"code": "IDEMPOTENCY_CONFLICT",
"message": "The same Idempotency-Key was used with a different request body.",
"requestId": "req_01J0RESTAPI002"
}
}
{
"error": {
"code": "ORDER_NOT_FOUND",
"message": "Order was not found.",
"requestId": "req_01J0RESTAPI003"
}
}
Para iniciantes: code é o nome curto para o programa decidir o caminho, message é a explicação para log ou interface, e requestId ajuda o suporte a encontrar logs no servidor. Use details principalmente quando a validação precisa apontar campos específicos.
Não Deixar Paginação, Idempotência Ou Versão Ambíguas
APIs de lista precisam de paginação desde o começo. Retornar todos os pedidos funciona com poucos dados, mas quando a tabela cresce mudar a resposta vira breaking change. Com cursor, o cliente envia o nextCursor da resposta anterior como novo after.
{
"data": [
{
"id": "ord_100",
"status": "paid",
"totalCents": 4800,
"createdAt": "2026-06-03T09:00:00Z"
}
],
"pageInfo": {
"nextCursor": "ord_099",
"hasMore": true
}
}
Idempotência evita que requisições repetidas criem efeitos duplicados. POST /orders é sensível porque clientes reenvias depois de falhas de rede. Guarde Idempotency-Key e um hash do body por tempo limitado. Mesma chave e mesmo body retornam o resultado anterior; mesma chave com body diferente retorna 409.
Versionamento dá tempo de migração aos consumidores. Remover campo obrigatório, trocar tipo, mudar ordenação padrão ou adicionar campo obrigatório no request é breaking change e deve ir para /v2. Adicionar campo opcional normalmente pode continuar em /v1.
Pedir Revisão De Design Ao Claude Code
Antes de implementar, use um prompt concreto.
Review this OpenAPI design.
Check:
- Resource names are nouns
- HTTP methods and status codes match MDN semantics
- 400/401/403/404/409/500 errors share the same JSON shape
- List pagination is unambiguous
- POST creation endpoints that need idempotency keys are identified
- No response change breaks the v1 contract
- Return a table of issues to fix before TypeScript implementation and tests
Assim, Claude Code atua como revisor de design antes de editar arquivos. Peça a implementação apenas depois de salvar o OpenAPI revisado.
Falhas Comuns
A primeira falha é criar endpoints em estilo de ação. Se POST /createOrder, POST /updateOrderStatus e GET /deleteOrder convivem, a URL deixa de comunicar recurso e operação. Prefira POST /v1/orders, PATCH /v1/orders/{orderId} e DELETE /v1/orders/{orderId}, documentando exceções.
A segunda falha é misturar status codes. Se entrada inválida retorna 500, recurso ausente retorna 200 e criação bem-sucedida alterna entre 200 e 201, clientes não conseguem decidir corretamente. Padronize também os códigos de sucesso.
A terceira falha é paginação ambígua. Se page=2 não define se a ordem é por criação ou atualização, dados novos causam duplicidade ou lacunas. Documente ordenação, limit máximo e forma de detectar próxima página.
A quarta falha é esconder validação só na implementação. Se quantity >= 1 está no código, mas não no OpenAPI, frontend e SDKs gerados não conseguem reutilizar a regra. Restrições precisam estar na especificação e no código.
Checklist De Revisão
- Recursos usam substantivos no plural de forma consistente
- Métodos respeitam a semântica de
GET,POST,PATCHeDELETE - Sucessos distinguem
200,201e204 400,401,403,404,409e500compartilham a mesma forma JSON- Listas incluem
limit,after,nextCursorehasMore limittem padrão e máximo documentados- Endpoints de criação não duplicam dados em retry
- Critérios para mover breaking changes para
/v2estão escritos - Regras de validação aparecem no OpenAPI
- Tabela de endpoints e OpenAPI batem antes de passar a tarefa ao Claude Code
Design de REST API não é desenhar URLs bonitas. É transformar promessas para consumidores em texto legível e especificação que ferramentas entendem. Claude Code acelera a implementação, mas as promessas que o sistema deve cumprir continuam sendo decisão humana.
Ao testar na API de pedidos de Masa, preparar OpenAPI, tabela de endpoints e JSONs de erro antes de pedir a implementação ao Claude Code reduziu claramente o retrabalho em revisão. Colocar Idempotency-Key e paginação por cursor no design também evitou correções posteriores para pedidos duplicados e registros faltando em listas.
PDF grátis: cheatsheet do Claude Code
Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.
Cuidamos dos seus dados e não enviamos spam.
Sobre o autor
Masa
Engenheiro focado em workflows práticos com Claude Code.
Artigos relacionados
Escada de segurança de permissões no Claude Code
Amplie de read-only para edições limitadas, comandos de prova e deploy checks sem perder controle.
Claude Code Small PR Proof Pack: pequenas mudanças fáceis de revisar
Um pacote de prova para PRs do Claude Code: diff, checks, URL pública, CTA e rollback.
Gate de revisão antes do commit com Claude Code
Revisão antes do commit com Claude Code: diff, build, URL pública, Gumroad, consultoria, testes e arquivos fora do escopo.