Abra qualquer base de código com mais de dois anos e você encontrará as cicatrizes: /getUser, /user_list, /Users/fetchAll, três esquemas de paginação diferentes e um campo customerID ao lado de order_id na mesma resposta. Nada disso quebra nada. Tudo isso atrasa a todos.
A nomeação é a decisão de design de API mais barata que você fará e a mais cara de reverter. Uma vez que os clientes dependem de /getOrders, você fica preso a ela por anos. Este guia oferece uma regra concreta para cada decisão de nomeação que uma API REST impõe a você, com um exemplo e um contra-exemplo para cada. Ele segue o mesmo raciocínio de nossas diretrizes mais amplas de API REST para desenvolvedores, mas se aprofunda na parte sobre a qual as equipes mais discutem: como chamar as coisas.
Se você preferir impor essas regras com ferramentas em vez de comentários de revisão de código, o Apidog permite que você defina cada endpoint visualmente contra um esquema compartilhado antes que qualquer pessoa escreva código. Mais sobre isso no final.
Use substantivos no plural para coleções
Uma URL nomeia um recurso, não uma operação. Coleções são conjuntos de coisas, então nomeie-as como substantivos no plural.
Correto:
GET /v1/products
GET /v1/products/89
GET /v1/orders
Errado:
GET /v1/getProducts
GET /v1/product
GET /v1/productList
A forma plural funciona em ambos os níveis. /products é lido como “a coleção de produtos” e /products/89 é lido como “o produto 89 dentro da coleção”. A nomeação no singular força URLs estranhas como /product/89 para um item, mas /product para muitos, o que soa errado. As diretrizes de API REST da Microsoft optaram por substantivos no plural exatamente por essa razão, e a maioria das APIs públicas (Stripe, GitHub, Shopify) seguiu o mesmo caminho.
Uma exceção: recursos singleton. Se um usuário tem exatamente um carrinho, /users/42/cart está bom. Não pluralize algo com cardinalidade de um.
Mantenha os verbos fora dos caminhos
O método HTTP é o verbo. Colocar outro verbo no caminho duplica informações e quebra o modelo de recurso.
Correto:
GET /v1/orders/42 (lê-lo)
DELETE /v1/orders/42 (excluí-lo)
PATCH /v1/orders/42 (atualizá-lo)
Errado:
GET /v1/fetchOrder/42
POST /v1/deleteOrder/42
POST /v1/updateOrderStatus
Caminhos baseados em verbos também multiplicam sua área de superfície. Um recurso com quatro métodos se torna quatro endpoints para documentar, testar e armazenar em cache separadamente. A invalidação de cache também piora: uma CDN pode armazenar em cache GET /v1/orders/42 e invalidar em DELETE /v1/orders/42 porque ambos apontam para a mesma URL. Ela não consegue conectar /fetchOrder/42 a /deleteOrder/42.
Use kebab-case em caminhos de URL
Segmentos de caminho com várias palavras precisam de um separador, e hifens são o correto.
Correto:
/v1/gift-cards
/v1/shipping-addresses
Errado:
/v1/giftCards
/v1/gift_cards
/v1/GiftCards
Três razões. O Google trata hifens como separadores de palavras para indexação, então a documentação de APIs públicas classifica melhor com kebab-case. Sublinhados desaparecem quando uma URL é sublinhada em um e-mail ou documento. E camelCase em URLs convida a bugs de diferenciação de maiúsculas e minúsculas: /giftCards e /giftcards são URLs diferentes na maioria dos servidores, e alguém digitará o errado. As diretrizes de API REST da Zalando tornam o kebab-case uma regra OBRIGATÓRIA, e eles aplicaram essa abordagem em centenas de serviços internos.
Escolha um padrão de maiúsculas/minúsculas para JSON e documente-o
Para nomes de campos dentro de corpos de requisição e resposta, a resposta honesta é: camelCase e snake_case funcionam. O que não funciona é misturá-los.
Correto (um ou outro, consistentemente):
{ "orderId": 42, "createdAt": "2026-08-30T09:15:00Z", "totalAmount": 4999 }
{ "order_id": 42, "created_at": "2026-08-30T09:15:00Z", "total_amount": 4999 }
Errado:
{ "orderId": 42, "created_at": "2026-08-30T09:15:00Z", "TotalAmount": 4999 }
camelCase mapeia de forma limpa para clientes JavaScript e Java. snake_case é mais fácil de escanear e corresponde a Ruby, Python e a maioria dos nomes de colunas SQL; o Stripe o usa em todos os lugares. Escolha com base em quem mais consome sua API, então coloque a escolha em seu guia de estilo para que o debate aconteça uma vez, em vez de em cada pull request. A mistura de padrões de maiúsculas/minúsculas é a inconsistência mais comum em APIs do mundo real porque diferentes equipes entregam diferentes endpoints. Isso é uma falha de governança, não uma falha de gosto.
Limite o aninhamento a dois níveis
O aninhamento expressa propriedade: /users/42/orders significa “pedidos pertencentes ao usuário 42”. Isso é útil. A partir de dois níveis, deixa de ser útil.
Correto:
GET /v1/users/42/orders
GET /v1/orders/1337/refunds
Errado:
GET /v1/users/42/orders/1337/refunds/7/status
O aninhamento profundo força os clientes a carregar cada ID ancestral para alcançar um recurso folha, mesmo quando a folha tem um ID globalmente único próprio. Se um reembolso tem ID 7, exponha-o em /refunds/7 ou /orders/1337/refunds/7 e pare por aí. Um bom teste olfativo: se uma URL contém três ou mais IDs, achate-a. Uma vez que um pedido existe, ele não precisa de seu usuário no caminho; /orders/1337 se sustenta por si só.
Coloque filtragem, ordenação e paginação em parâmetros de consulta
Caminhos identificam recursos. Parâmetros de consulta modificam como você os visualiza. Nunca codifique um filtro no caminho.
Correto:
GET /v1/orders?status=active&sort=-created_at&limit=50&cursor=eyJpZCI6NDJ9
GET /v1/products?category=electronics&min_price=1000
Errado:
GET /v1/orders/active
GET /v1/orders/sorted-by-date-desc
GET /v1/getOrdersByStatusAndDate
O padrão sort=-created_at (prefixo de menos para descendente) vem da especificação JSON:API e economiza um segundo parâmetro order=desc. Caminhos de filtro como /orders/active parecem inofensivos até que você precise combinar filtros, e então você está criando um novo endpoint por combinação. Nomes de parâmetros de paginação merecem a mesma disciplina: escolha limit/cursor ou page/per_page uma vez e reutilize-os em cada coleção. Nosso guia de paginação de API cobre o trade-off cursor-versus-offset em profundidade; a regra de nomeação aqui é simplesmente ser uniforme sobre isso.
Versionamento no caminho
Você tem duas opções principais: um segmento de caminho (/v1/products) ou um cabeçalho (Accept: application/vnd.myapi.v1+json). O versionamento por cabeçalho é mais “puro” REST, já que a URL continua nomeando o mesmo recurso entre as versões, e as diretrizes de design de API do Google observam que ambas as abordagens existem. Mas o versionamento por caminho ganha em termos operacionais: é visível em cada linha de log, testável de um navegador, armazenável em cache sem malabarismos com Vary, e impossível para um cliente esquecer. Todo desenvolvedor que depurou um problema de “funciona no curl, falha em produção” causado por um cabeçalho de versão ausente sabe o custo da alternativa. Use /v1/ apenas com uma versão principal, sem /v1.2/; pequenas alterações devem ser aditivas e não disruptivas. Para a árvore de decisão completa, incluindo negociação de conteúdo, veja nossa comparação de estratégias de versionamento de API.
Trate IDs de recursos como opacos e não vaze inteiros sequenciais descuidadamente
/orders/41, /orders/42, /orders/43: IDs de inteiros sequenciais dizem a qualquer um que olhar exatamente quantos pedidos você processa, e convidam a ataques de enumeração onde um invasor percorre o espaço de IDs procurando por falhas de autorização. Esta classe de bug, autorização em nível de objeto quebrada, está em primeiro lugar no Top 10 de Segurança de API da OWASP.
Correto:
GET /v1/orders/ord_9f8e2a71b3
GET /v1/users/550e8400-e29b-41d4-a716-446655440000
Errado (quando a enumeração importa):
GET /v1/orders/42
GET /v1/invoices/10883
IDs aleatórios prefixados como ord_9f8e2a71b3 do Stripe são o padrão mais forte: impossíveis de adivinhar, auto-descritivos em logs e seguros para expor. Verificações de autorização ainda são obrigatórias de qualquer forma. IDs opacos reduzem o raio de impacto de uma verificação ausente; eles não a substituem. Internamente, você pode manter chaves primárias inteiras; a regra é sobre o que você expõe nas URLs.
Modele ações não-CRUD como recursos de controlador
Mais cedo ou mais tarde, você precisará de uma ação sem um mapeamento CRUD limpo: cancelar um pedido, tentar novamente um pagamento, reenviar um e-mail. Não a 'tunelize' através de PATCH em um campo de status, e não coloque um verbo no nível superior.
Correto:
POST /v1/orders/42/cancel
POST /v1/payments/pay_88a1/retry
Errado:
PATCH /v1/orders/42 { "status": "cancelled" }
POST /v1/cancelOrder { "orderId": 42 }
Este é o padrão de controlador, e é a única exceção sancionada à regra de 'sem verbos': o verbo vai no final do caminho, com escopo sob o recurso em que atua. A abordagem PATCH parece RESTful, mas esconde uma máquina de estados dentro de uma atualização de campo. Cancelar um pedido dispara reembolsos, libera estoque e envia notificações; fingir que é uma escrita de campo força seu servidor a diferenciar os payloads para detectar a intenção. Um endpoint /cancel declara a intenção, dá à ação suas próprias permissões e trilha de auditoria, e deixa espaço para entradas específicas da ação, como um motivo de cancelamento.
Mantenha a consistência de maiúsculas/minúsculas para cabeçalhos e parâmetros de consulta
Duas superfícies menores, a mesma disciplina. Cabeçalhos personalizados usam Hyphenated-Pascal-Case, seguindo a convenção HTTP: Idempotency-Key, Request-Id. Ignore o antigo prefixo X-; ele foi descontinuado pelo RFC 6648 em 2012. Nomes de cabeçalhos são insensíveis a maiúsculas e minúsculas no envio, mas sua documentação e SDKs ainda devem escrevê-los de uma única forma.
Parâmetros de consulta devem corresponder ao padrão de maiúsculas/minúsculas do seu corpo JSON. Se seus corpos usam snake_case, escreva ?min_price=1000&created_after=2026-01-01, não ?minPrice=1000. Um desenvolvedor que lê created_at em uma resposta e precisa digitar createdAfter em uma consulta errará na primeira tentativa, e o mesmo acontecerá com todos os outros depois dele.
O conjunto completo de regras em um relance
| # | Regra | Correto | Errado |
|---|---|---|---|
| 1 | Substantivos no plural para coleções | /products, /products/89 |
/getProducts, /productList |
| 2 | Sem verbos nos caminhos | DELETE /orders/42 |
POST /deleteOrder/42 |
| 3 | Segmentos de caminho em kebab-case | /gift-cards |
/giftCards, /gift_cards |
| 4 | Um padrão de maiúsculas/minúsculas para JSON, documentado | order_id em todos os lugares |
orderId e order_id misturados |
| 5 | Máximo de dois níveis de aninhamento | /orders/1337/refunds |
/users/42/orders/1337/refunds/7 |
| 6 | Filtros e paginação em parâmetros de consulta | ?status=active&sort=-created_at |
/orders/active |
| 7 | Versão principal no caminho | /v1/products |
/v1.2/products, cabeçalhos de versão |
| 8 | IDs de recurso opacos | /orders/ord_9f8e2a71b3 |
/orders/42 (público, enumerável) |
| 9 | Padrão de controlador para ações | POST /orders/42/cancel |
PATCH com {"status":"cancelled"} |
| 10 | Consistência de maiúsculas/minúsculas para cabeçalhos e parâmetros | Idempotency-Key, ?min_price= |
X-IDEMPOTENCY_KEY, ?minPrice= misturados |
Impondo convenções em escala
Um guia de estilo em uma wiki não muda nada. As equipes cujas APIs permanecem consistentes compartilham um hábito: elas projetam primeiro e impõem as convenções antes que o código exista, o que é o cerne da governança de API na prática.
É aqui que o Apidog ganha seu lugar no fluxo de trabalho. Os endpoints são definidos em um designer visual com foco no esquema, de modo que o caminho, o padrão de maiúsculas/minúsculas e os nomes dos parâmetros são artefatos de design explícitos, em vez de strings enterradas no código do controlador. Componentes compartilhados significam que os esquemas de Pagination, Error e Money são definidos uma vez e reutilizados em cada endpoint; ninguém reinventa per_page como pageSize em um novo serviço. E como os designs vivem em workspaces de equipe com revisão incorporada, um líder pode detectar /getUserOrders no momento do design, quando a renomeação custa um clique, em vez de depois que três clientes já se integraram a ele. A especificação então impulsiona documentação, servidores mock e testes, de modo que os nomes aprovados são os nomes que todos implementam. Baixe o Apidog e experimente gratuitamente com seu próximo novo endpoint; adaptar uma API antiga é difícil, mas manter a linha em novas não é.
Perguntas Frequentes
As URLs REST devem ser no plural ou singular?
No plural, para qualquer recurso com mais de uma instância: /products, /orders, /users. A forma plural permanece natural tanto para a coleção (/orders) quanto para um membro (/orders/42). Reserve nomes singulares para singletons verdadeiros como /users/42/cart. Se você quiser o raciocínio mais profundo por trás da modelagem de recursos, nosso guia sobre o que é uma API REST o aborda desde os princípios básicos.
camelCase ou snake_case é melhor para nomes de campos JSON?
Nenhum ganha por mérito. camelCase é adequado para consumidores que usam muito JavaScript; snake_case é mais legível e corresponde a Python, Ruby e à API pública do Stripe. A regra importante: escolha um, escreva-o em seu guia de estilo e imponha-o na revisão de esquemas. A mistura de padrões de maiúsculas/minúsculas entre endpoints prejudica mais do que qualquer uma das escolhas.
Devo colocar a versão da API na URL ou em um cabeçalho?
Use o caminho (/v1/orders) a menos que você tenha um forte requisito de hipermídia. As versões no caminho aparecem em logs, caches e testes de navegador com zero esforço do cliente. O versionamento por cabeçalho mantém as URLs estáveis entre as versões, mas falha silenciosamente quando os clientes esquecem o cabeçalho. Apenas versões principais; implemente pequenas alterações como atualizações aditivas e não disruptivas.
Verbos são aceitáveis em um caminho de API REST?
Sim, em um lugar: endpoints de controlador para ações não-CRUD, como POST /orders/42/cancel ou POST /payments/pay_88a1/retry. O verbo fica no final do caminho, com escopo sob seu recurso, e o método é sempre POST. Em todos os outros lugares, o método HTTP carrega o verbo e o caminho permanece apenas com substantivos.
