Tips & Tricks (Atualizado: 03/06/2026)

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.

Design de REST API com Claude Code: endpoints, erros, paginação e idempotência

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.

TermoExplicação simplesExemplo
RecursoO substantivo manipulado pela APIorders, customers
EndpointURL mais método HTTPGET /v1/orders
MétodoVerbo HTTP que indica a operaçãoGET, POST, PATCH
Status codeNúmero que sinaliza sucesso, erro de entrada, falta de autenticação etc.200, 201, 400, 404
ValidaçãoChecagem de que a requisição tem o formato corretoFormato de e-mail, quantidade mínima
IdempotênciaRepetir a mesma operação não muda o estado finalCriar 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.

ObjetivoMétodo e caminhoSucessoRegra importante
Listar pedidosGET /v1/orders?status=paid&limit=20&after=ord_123200 OKPaginação por cursor com ordenação estável
Criar pedidoPOST /v1/orders201 CreatedAceitar Idempotency-Key e retornar Location
Ver pedidoGET /v1/orders/{orderId}200 OKSe não existir, retornar 404
Atualizar pedidoPATCH /v1/orders/{orderId}200 OKAtualização parcial; patch vazio é 400
Cancelar pedidoPOST /v1/orders/{orderId}/cancel200 OKTratar 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, PATCH e DELETE
  • Sucessos distinguem 200, 201 e 204
  • 400, 401, 403, 404, 409 e 500 compartilham a mesma forma JSON
  • Listas incluem limit, after, nextCursor e hasMore
  • limit tem padrão e máximo documentados
  • Endpoints de criação não duplicam dados em retry
  • Critérios para mover breaking changes para /v2 estã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.

#claude-code #rest-api #openapi #typescript #backend
Grátis

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.

Masa

Sobre o autor

Masa

Engenheiro focado em workflows práticos com Claude Code.