DevGuideTK
← Trilha Backend

Design de APIs REST

Recursos, nomes, códigos de status e formato de erros em uma API previsível.

Uma API é uma interface para pessoas

Quem consome uma API é um programa, mas quem escreve esse programa é uma pessoa. Ela lê a documentação, tenta um pedido, interpreta a resposta e escreve o código de integração. Uma API bem desenhada é aquela em que essa pessoa adivinha certo: depois de usar duas rotas, ela prevê como a terceira funciona.

O estilo REST, apresentado no tópico de estilos de API, organiza a API em torno de recursos manipulados pelos métodos do HTTP. Este tópico trata das decisões de desenho dentro desse estilo.

Recursos e endereços

Um recurso é qualquer coisa que a API expõe: um pedido, um cliente, os itens de um pedido. Cada recurso tem um endereço, e o endereço usa substantivos. A ação vem do método.

AçãoMétodo e endereço
Listar pedidosGET /pedidos
Criar um pedidoPOST /pedidos
Ler um pedidoGET /pedidos/981
Substituir um pedidoPUT /pedidos/981
Alterar parte de um pedidoPATCH /pedidos/981
Remover um pedidoDELETE /pedidos/981
Listar os itens de um pedidoGET /pedidos/981/itens

Os erros mais comuns de endereço:

Em vez deUsePor quê
POST /criarPedidoPOST /pedidosO método já diz a ação
GET /pedidos/981/cancelarPOST /pedidos/981/cancelamentoGET não pode alterar nada; o tópico de HTTP explica o risco
/Pedido, /pedido e /pedidos em rotas diferentesSempre /pedidosPlural e minúsculas, sempre iguais
/clientes/42/pedidos/981/itens/3/produto/pedidos/981/itens e /produtos/7Aninhar mais de um nível deixa os endereços frágeis

Ações que não são criar, ler, alterar ou remover

Nem tudo cabe nos quatro verbos. Cancelar um pedido, reenviar um e-mail, aprovar um reembolso. A forma mais consistente é tratar a ação como a criação de um recurso:

POST /pedidos/981/cancelamento
Content-Type: application/json

{ "motivo": "cliente desistiu" }

O cancelamento passa a ser algo que existe, com data, motivo e quem o fez, e pode ser consultado depois em GET /pedidos/981/cancelamento.

Códigos de status

O tópico de HTTP apresenta os códigos de status. No desenho da API, o importante é usar cada um de forma previsível:

OperaçãoSucessoErros mais comuns
GET de um recurso200404 não existe
GET de uma lista200, mesmo vazia400 filtro inválido
POST que cria201, com o cabeçalho Location apontando o recurso criado400 corpo malformado, 422 dados inválidos, 409 conflito (já existe)
POST que inicia um processo demorado202, com o endereço para acompanhar
PUT ou PATCH200 com o recurso, ou 204 sem corpo404, 409, 422
DELETE204404

A diferença entre 400 e 422 costuma gerar debate. Uma convenção comum, usada nos exemplos deste tópico: 400 quando o pedido não pode nem ser lido (JSON malformado), 422 quando foi lido, mas os dados não passam na validação.

Erros num formato único

A parte mais negligenciada de uma API é o formato dos erros. Cada rota inventando o seu cria clientes cheios de casos especiais:

{ "erro": "pedido não encontrado" }
{ "message": "Invalid quantity", "code": 4001 }
{ "success": false, "errors": ["clienteId is required"] }

O padrão Problem Details (RFC 9457) define um formato único, com o tipo de conteúdo application/problem+json:

{
  "type": "https://api.loja.com.br/erros/dados-invalidos",
  "title": "Os dados enviados são inválidos",
  "status": 422,
  "errors": {
    "clienteId": "obrigatório",
    "itens[0].quantidade": "inteiro maior que zero"
  }
}
CampoPara que serve
typeUm identificador estável do tipo de erro; o cliente decide o que fazer por ele, e não pela mensagem
titleUma descrição curta, igual para todas as ocorrências desse tipo
statusO mesmo código de status da resposta
detailUma explicação desta ocorrência específica (opcional)
instanceO endereço desta ocorrência (opcional)
Outros camposExtensões, como a lista de erros por campo

Implementamos esse formato nas cinco linguagens e executamos quatro delas. TypeScript, Python, Go e C# responderam com application/problem+json e status 422 aos dados inválidos e 400 ao JSON malformado. Os detalhes variaram: o C# coloca as mensagens em listas e acrescenta um traceId; o FastAPI usa as mensagens de validação do Pydantic, em inglês. O nível Implementação mostra a comparação completa.

Representações

DecisãoRecomendação
Nomes de camposUm padrão único em toda a API: camelCase ou snake_case, nunca os dois
DatasISO 8601 com fuso: 2026-03-10T14:02:00Z
DinheiroInteiro em centavos, ou texto decimal ("199.90"), com a moeda; nunca número de ponto flutuante
IdentificadoresTexto, mesmo que sejam numéricos no banco; o cliente não deve fazer contas com eles
Campos vaziosUma regra só: omitir, ou devolver null
Campos internosNunca na resposta: senhas, hashes, colunas de controle, chaves de outros sistemas

A última linha merece atenção. Devolver a entidade do banco diretamente, em vez de um formato desenhado para a API, expõe campos que deveriam ser internos e prende o contrato da API ao esquema do banco: uma coluna renomeada quebra os clientes.

Por que isso importa quando a IA escreve o código

Um assistente gera rotas que funcionam isoladamente, e cada uma pode sair com um estilo diferente:

  • Verbos nos endereços (/getPedido, /cancelarPedido) e ações em GET.
  • 200 para tudo, com o erro dentro do corpo.
  • Um formato de erro diferente em cada rota, ou o formato padrão do framework misturado com um próprio.
  • A entidade do banco devolvida inteira, com campos internos.
  • 403 para recursos de outros usuários, revelando quais identificadores existem.

O próximo nível compara as decisões de desenho que mais aparecem e quando escolher cada lado.

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.

  • Design de APIs REST em cinco minutos

    Explique em no máximo cinco minutos de leitura o que torna uma API REST bem desenhada, para alguém que já criou rotas mas nunca pensou na API como um contrato.
    
    Cubra só o essencial: recursos e endereços com substantivos, o método como ação, os códigos de status por operação e por que todos os erros devem seguir um único formato.
    
    Use o exemplo de uma API de pedidos. No final, me faça três perguntas curtas para eu verificar se entendi, e corrija as minhas respostas.
  • Desenhar os endereços de uma API

    Quero aprender a desenhar os endereços e métodos de uma API REST.
    
    Aja como um mentor. Use como exemplo uma loja virtual com clientes, pedidos, itens, produtos e pagamentos.
    
    Conduza assim:
    1. Peça que eu proponha os endereços e métodos para criar, listar, ler, alterar e remover pedidos. Corrija o que estiver fora do padrão.
    2. Peça os endereços para os itens de um pedido e discuta até que nível aninhar.
    3. Peça como eu modelaria cancelar um pedido, aprovar um reembolso e reenviar um e-mail, e explique a ideia de tratar ações como recursos.
    4. Mostre cinco endereços com problemas comuns e peça que eu encontre o erro em cada um.
    
    Explique cada correção com o motivo prático.
  • Códigos de status e formato de erros

    Quero aprender a escolher os códigos de status e a desenhar as respostas de erro de uma API.
    
    Explique:
    1. O código de sucesso adequado para cada operação, inclusive 201 com Location, 202 e 204.
    2. A diferença entre 400, 401, 403, 404, 409 e 422, com exemplos.
    3. Por que responder 404, e não 403, para recursos de outros usuários.
    4. O formato Problem Details (RFC 9457): cada campo e para que serve.
    5. Como representar erros de validação de vários campos.
    
    Depois me apresente oito situações e pergunte o status e o corpo de erro que eu devolveria em cada uma. Corrija as minhas respostas.
  • Representações que não prendem a API ao banco

    Quero entender como desenhar o formato das respostas de uma API sem prendê-lo ao banco de dados.
    
    Explique:
    1. Por que devolver a entidade do banco diretamente é um problema, com exemplos de campos que vazam e de mudanças que quebram clientes.
    2. Como representar datas, dinheiro, identificadores e campos vazios.
    3. A escolha entre camelCase e snake_case e por que a consistência importa mais que a escolha.
    4. Como evoluir a representação sem quebrar clientes: acrescentar campos é seguro, remover e renomear não.
    
    Depois me mostre a resposta de uma API com cinco problemas e peça que eu os encontre.