Ouvrez n'importe quelle base de code de plus de deux ans et vous y trouverez les cicatrices : /getUser, /user_list, /Users/fetchAll, trois schémas de pagination différents, et un champ customerID côtoyant order_id dans la même réponse. Rien de tout cela ne casse quoi que ce soit. Mais tout cela ralentit tout le monde.
Le nommage est la décision de conception d'API la moins coûteuse que vous prendrez et la plus chère à inverser. Une fois que les clients dépendent de /getOrders, vous êtes contraint de le supporter pendant des années. Ce guide vous offre une règle concrète pour chaque décision de nommage qu'une API REST vous impose, avec un exemple et un contre-exemple pour chacun. Il suit la même logique que nos directives générales pour les API REST à destination des développeurs, mais se concentre sur la partie pour laquelle les équipes se disputent le plus : comment nommer les choses.
Si vous préférez faire respecter ces règles avec des outils plutôt qu'avec des commentaires de révision de code, Apidog vous permet de définir chaque point d'API visuellement par rapport à un schéma partagé avant que quiconque n'écrive du code. Plus d'informations à ce sujet à la fin.
Utilisez des noms pluriels pour les collections
Une URL nomme une ressource, pas une opération. Les collections sont des ensembles de choses, nommez-les donc avec des noms pluriels.
Faites :
GET /v1/products
GET /v1/products/89
GET /v1/orders
Ne faites pas :
GET /v1/getProducts
GET /v1/product
GET /v1/productList
La forme plurielle fonctionne aux deux niveaux. /products se lit comme « la collection de produits » et /products/89 se lit comme « le produit 89 au sein de la collection ». Le nommage au singulier force des URL maladroites comme /product/89 pour un élément mais /product pour plusieurs, ce qui semble incorrect. Les directives API REST de Microsoft ont opté pour les noms pluriels précisément pour cette raison, et la plupart des API publiques (Stripe, GitHub, Shopify) ont suivi la même voie.
Une exception : les ressources singleton. Si un utilisateur a exactement un panier, /users/42/cart est acceptable. Ne mettez pas au pluriel quelque chose avec une cardinalité de un.
Évitez les verbes dans les chemins
La méthode HTTP est le verbe. Mettre un autre verbe dans le chemin duplique l'information et brise le modèle de ressource.
Faites :
GET /v1/orders/42 (lire)
DELETE /v1/orders/42 (supprimer)
PATCH /v1/orders/42 (mettre à jour)
Ne faites pas :
GET /v1/fetchOrder/42
POST /v1/deleteOrder/42
POST /v1/updateOrderStatus
Les chemins basés sur des verbes multiplient également votre surface d'exposition. Une ressource avec quatre méthodes devient quatre points d'API à documenter, tester et mettre en cache séparément. L'invalidation du cache s'aggrave également : un CDN peut mettre en cache GET /v1/orders/42 et l'invalider sur DELETE /v1/orders/42 car les deux pointent vers la même URL. Il ne peut pas connecter /fetchOrder/42 à /deleteOrder/42.
Utilisez le kebab-case dans les chemins d'URL
Les segments de chemin composés de plusieurs mots nécessitent un séparateur, et les tirets sont le bon choix.
Faites :
/v1/gift-cards
/v1/shipping-addresses
Ne faites pas :
/v1/giftCards
/v1/gift_cards
/v1/GiftCards
Trois raisons. Google traite les tirets comme des séparateurs de mots pour l'indexation, de sorte que les documentations d'API publiques sont mieux classées avec le kebab-case. Les underscores disparaissent lorsqu'une URL est soulignée dans un e-mail ou un document. Et le camelCase dans les URL invite aux bugs de sensibilité à la casse : /giftCards et /giftcards sont des URL différentes sur la plupart des serveurs, et quelqu'un tapera la mauvaise. Les directives API REST de Zalando font du kebab-case une règle OBLIGATOIRE, et elles ont appliqué cette approche à travers des centaines de services internes.
Choisissez une convention de casse JSON et documentez-la
Pour les noms de champs à l'intérieur des corps de requête et de réponse, la réponse honnête est : camelCase et snake_case fonctionnent tous les deux. Ce qui ne fonctionne pas, c'est de les mélanger.
Faites (l'un ou l'autre, de manière cohérente) :
{ "orderId": 42, "createdAt": "2026-08-30T09:15:00Z", "totalAmount": 4999 }
{ "order_id": 42, "created_at": "2026-08-30T09:15:00Z", "total_amount": 4999 }
Ne faites pas :
{ "orderId": 42, "created_at": "2026-08-30T09:15:00Z", "TotalAmount": 4999 }
Le camelCase se mappe proprement aux clients JavaScript et Java. Le snake_case est plus facile à lire et correspond à Ruby, Python et à la plupart des noms de colonnes SQL ; Stripe l'utilise partout. Choisissez en fonction de qui consomme le plus votre API, puis inscrivez ce choix dans votre guide de style afin que le débat ait lieu une seule fois au lieu de sur chaque pull request. La casse mixte est l'incohérence la plus courante dans les API réelles, car différentes équipes livrent différents points d'API. C'est un échec de gouvernance, pas un échec de goût.
Limitez l'imbrication à deux niveaux
L'imbrication exprime la propriété : /users/42/orders signifie « les commandes appartenant à l'utilisateur 42 ». C'est utile. Au-delà de deux niveaux, cela cesse d'être utile.
Faites :
GET /v1/users/42/orders
GET /v1/orders/1337/refunds
Ne faites pas :
GET /v1/users/42/orders/1337/refunds/7/status
L'imbrication profonde force les clients à transporter chaque ID ancêtre pour atteindre une ressource feuille, même lorsque la feuille a son propre ID globalement unique. Si un remboursement a l'ID 7, exposez-le à /refunds/7 ou /orders/1337/refunds/7 et arrêtez-vous là. Un bon test d'odeur : si une URL contient trois ID ou plus, aplatissez-la. Une fois qu'une commande existe, elle n'a pas besoin de son utilisateur dans le chemin ; /orders/1337 se suffit à elle-même.
Placez le filtrage, le tri et la pagination dans les paramètres de requête
Les chemins identifient les ressources. Les paramètres de requête modifient la façon dont vous les visualisez. N'encodez jamais un filtre dans le chemin.
Faites :
GET /v1/orders?status=active&sort=-created_at&limit=50&cursor=eyJpZCI6NDJ9
GET /v1/products?category=electronics&min_price=1000
Ne faites pas :
GET /v1/orders/active
GET /v1/orders/sorted-by-date-desc
GET /v1/getOrdersByStatusAndDate
Le modèle sort=-created_at (avec le préfixe moins pour le tri descendant) provient de la spécification JSON:API et vous évite un deuxième paramètre order=desc. Les chemins de filtre comme /orders/active semblent inoffensifs jusqu'à ce que vous ayez besoin de combiner des filtres, et alors vous créez un nouveau point d'API par combinaison. Les noms des paramètres de pagination méritent la même discipline : choisissez limit/cursor ou page/per_page une fois et réutilisez-les sur chaque collection. Notre guide de pagination d'API couvre en profondeur le compromis curseur vs offset ; la règle de nommage ici est simplement d'être uniforme à ce sujet.
Version dans le chemin
Vous avez deux options principales : un segment de chemin (/v1/products) ou un en-tête (Accept: application/vnd.myapi.v1+json). Le versionnement par en-tête est plus « pur » REST, car l'URL continue de nommer la même ressource à travers les versions, et les directives de conception d'API de Google notent que les deux approches existent. Mais le versionnement par chemin l'emporte sur des considérations opérationnelles : il est visible dans chaque ligne de journal, testable depuis un navigateur, cachable sans contorsions Vary, et impossible pour un client d'oublier. Tout développeur ayant débogué un problème « fonctionne avec curl, échoue en production » causé par un en-tête de version manquant connaît le coût de l'alternative. Utilisez /v1/ avec une version majeure uniquement, pas /v1.2/ ; les changements mineurs doivent être additifs et non cassants. Pour l'arbre de décision complet, y compris la négociation de contenu, consultez notre comparaison des stratégies de versionnement d'API.
Traitez les ID de ressource comme opaques et ne divulguez pas d'entiers séquentiels de manière négligente
/orders/41, /orders/42, /orders/43 : les ID entiers séquentiels indiquent à quiconque le nombre exact de commandes que vous traitez, et ils invitent aux attaques par énumération où un attaquant parcourt l'espace des ID à la recherche de failles d'autorisation. Cette classe de bug, l'autorisation au niveau de l'objet brisée, se classe au premier rang du Top 10 de la sécurité des API de l'OWASP.
Faites :
GET /v1/orders/ord_9f8e2a71b3
GET /v1/users/550e8400-e29b-41d4-a716-446655440000
Ne faites pas (quand l'énumération compte) :
GET /v1/orders/42
GET /v1/invoices/10883
Les ID aléatoires préfixés comme ord_9f8e2a71b3 de Stripe sont le modèle le plus robuste : impossible à deviner, auto-descriptif dans les journaux et sûr à exposer. Les vérifications d'autorisation restent obligatoires dans tous les cas. Les ID opaques réduisent le rayon d'impact d'une vérification manquante ; ils ne la remplacent pas. En interne, vous pouvez conserver des clés primaires entières ; la règle concerne ce que vous exposez dans les URL.
Modélisez les actions non-CRUD comme des ressources de contrôleur
Tôt ou tard, vous aurez besoin d'une action sans mappage CRUD clair : annuler une commande, relancer un paiement, renvoyer un e-mail. Ne la faites pas passer par un PATCH sur un champ de statut, et ne mettez pas un verbe au niveau supérieur.
Faites :
POST /v1/orders/42/cancel
POST /v1/payments/pay_88a1/retry
Ne faites pas :
PATCH /v1/orders/42 { "status": "cancelled" }
POST /v1/cancelOrder { "orderId": 42 }
C'est le modèle de contrôleur, et c'est la seule exception autorisée à la règle des "pas de verbes" : le verbe se place à la fin du chemin, délimité sous la ressource sur laquelle il agit. L'approche PATCH semble RESTful mais cache une machine d'état à l'intérieur d'une mise à jour de champ. L'annulation d'une commande déclenche des remboursements, libère le stock et envoie des notifications ; prétendre qu'il s'agit d'une écriture de champ force votre serveur à comparer les payloads pour détecter l'intention. Un point d'API /cancel exprime l'intention, donne à l'action ses propres permissions et piste d'audit, et laisse de la place pour des entrées spécifiques à l'action comme une raison d'annulation.
Maintenez une casse cohérente pour les en-têtes et les paramètres de requête
Deux surfaces plus petites, même discipline. Les en-têtes personnalisés utilisent le format Hyphenated-Pascal-Case, conformément à la convention HTTP : Idempotency-Key, Request-Id. Ignorez l'ancien préfixe X- ; il a été déprécié par le RFC 6648 en 2012. Les noms d'en-tête sont insensibles à la casse sur le réseau, mais vos documentations et SDK devraient quand même les orthographier d'une seule manière.
Les paramètres de requête doivent correspondre à la casse de votre corps JSON. Si vos corps utilisent le snake_case, écrivez ?min_price=1000&created_after=2026-01-01, et non ?minPrice=1000. Un développeur qui lit created_at dans une réponse et doit taper createdAfter dans une requête se trompera au premier essai, et il en sera de même pour tous ceux qui suivront.
L'ensemble complet des règles en un coup d'œil
| # | Règle | Faites | Ne faites pas |
|---|---|---|---|
| 1 | Noms pluriels pour les collections | /products, /products/89 |
/getProducts, /productList |
| 2 | Pas de verbes dans les chemins | DELETE /orders/42 |
POST /deleteOrder/42 |
| 3 | Segments de chemin en kebab-case | /gift-cards |
/giftCards, /gift_cards |
| 4 | Une seule convention de casse JSON, documentée | order_id partout |
orderId et order_id mélangés |
| 5 | Maximum deux niveaux d'imbrication | /orders/1337/refunds |
/users/42/orders/1337/refunds/7 |
| 6 | Filtres et pagination dans les paramètres de requête | ?status=active&sort=-created_at |
/orders/active |
| 7 | Version majeure dans le chemin | /v1/products |
/v1.2/products, en-têtes de version |
| 8 | ID de ressource opaques | /orders/ord_9f8e2a71b3 |
/orders/42 (public, énumérable) |
| 9 | Modèle de contrôleur pour les actions | POST /orders/42/cancel |
PATCH avec {"status":"cancelled"} |
| 10 | Casse cohérente des en-têtes et paramètres | Idempotency-Key, ?min_price= |
X-IDEMPOTENCY_KEY, ?minPrice= mélangés |
Appliquer les conventions à grande échelle
Un guide de style dans un wiki ne change rien. Les équipes dont les API restent cohérentes partagent une habitude : elles conçoivent d'abord et appliquent les conventions avant que le code n'existe, ce qui est le cœur de la gouvernance d'API en pratique.
C'est là qu'Apidog trouve sa place dans le workflow. Les points d'API sont définis dans un concepteur visuel basé sur le schéma d'abord, de sorte que le chemin, la casse et les noms des paramètres sont des artefacts de conception explicites au lieu de chaînes enfouies dans le code du contrôleur. Les composants partagés signifient que les schémas Pagination, Error et Money sont définis une fois et réutilisés sur chaque point d'API ; personne ne réinvente per_page en pageSize sur un nouveau service. Et parce que les conceptions vivent dans des espaces de travail d'équipe avec révision intégrée, un responsable peut intercepter /getUserOrders au moment de la conception, lorsque le renommage coûte un clic, au lieu de le faire après que trois clients s'y soient intégrés. La spécification pilote ensuite la documentation, les serveurs de maquette et les tests, de sorte que les noms que vous avez approuvés sont les noms que tout le monde utilise. Téléchargez Apidog et essayez-le gratuitement avec votre prochain nouveau point d'API ; moderniser une ancienne API est difficile, mais maintenir la ligne sur les nouvelles ne l'est pas.
FAQ
Les URL REST doivent-elles être au pluriel ou au singulier ?
Au pluriel, pour toute ressource avec plus d'une instance : /products, /orders, /users. La forme plurielle reste naturelle à la fois pour la collection (/orders) et pour un membre (/orders/42). Réservez les noms au singulier pour les vrais singletons comme /users/42/cart. Si vous souhaitez une explication plus approfondie derrière la modélisation des ressources, notre guide sur ce qu'est une API REST l'explique à partir des principes fondamentaux.
Le camelCase ou le snake_case est-il préférable pour les noms de champs JSON ?
Aucun ne l'emporte au mérite. Le camelCase convient aux consommateurs orientés JavaScript ; le snake_case est plus lisible et correspond à Python, Ruby et à l'API publique de Stripe. La règle décisive : choisissez-en un, inscrivez-le dans votre guide de style et faites-le respecter lors de la révision des schémas. La casse mixte entre les points d'API fait plus de mal que l'un ou l'autre choix.
Dois-je mettre la version de l'API dans l'URL ou un en-tête ?
Utilisez le chemin (/v1/orders) sauf si vous avez une forte exigence d'hypermedia. Les versions de chemin apparaissent dans les journaux, les caches et les tests de navigateur sans aucun effort côté client. Le versionnement par en-tête maintient les URL stables entre les versions mais échoue silencieusement lorsque les clients oublient l'en-tête. Versions majeures uniquement ; livrez les changements mineurs comme des mises à jour additives et non cassantes.
Les verbes sont-ils parfois acceptables dans un chemin d'API REST ?
Oui, à un seul endroit : les points d'API de contrôleur pour les actions non-CRUD, comme POST /orders/42/cancel ou POST /payments/pay_88a1/retry. Le verbe se situe à la fin du chemin, délimité sous sa ressource, et la méthode est toujours POST. Partout ailleurs, la méthode HTTP porte le verbe et le chemin reste composé uniquement de noms.
