Dans la conception architecturale des systèmes distribués, les API ne sont pas seulement des conduits pour l'interaction système ; ce sont des contrats connectant différentes piles technologiques, cultures organisationnelles, et même des époques de développement. Au sein des détails de conception des API RESTful, un sujet apparemment mineur suscite un débat sans fin : Les noms de champs JSON doivent-ils utiliser le camelCase ou le snake_case ?
Ce n'est pas seulement un choix esthétique. Cela touche au "mismatch d'impédance" entre les couches de persistance backend et les couches de présentation frontend, impliquant les performances de sérialisation, l'efficacité de la transmission réseau, l'expérience développeur (DX) et la psychologie cognitive.
Basé sur l'histoire des langages de programmation, les mécanismes d'implémentation technique sous-jacents, et les décisions architecturales de géants de l'industrie comme Google et Stripe, cet article fournit un guide de décision de niveau expert.
1. Origines historiques : un choix sémiotique
Pour comprendre ce débat, nous devons retracer l'évolution des langages informatiques. Les conventions de nommage n'apparaissent pas de nulle part ; elles sont le produit des limitations matérielles et des cultures communautaires d'époques spécifiques.
L'origine du snake_case : C et la philosophie Unix
La popularité du snake_case (par exemple, user_id) remonte à C et Unix dans les années 1970. Bien que les premiers claviers (comme le Teletype Model 33) aient des touches Maj, de nombreux compilateurs étaient insensibles à la casse. Pour distinguer clairement les mots sur des écrans basse résolution, les programmeurs ont introduit le trait de soulignement pour simuler des espaces dans le langage naturel. Cette habitude s'est profondément enracinée dans les standards de base de données SQL. À ce jour, le style de nommage par défaut des colonnes pour PostgreSQL et MySQL reste le snake_case, jetant les bases des futures frictions de mappage entre les API et les bases de données.
L'essor du camelCase : l'hégémonie de Java et JavaScript
Le camelCase (par exemple, userId) a pris son essor avec la programmation orientée objet (Smalltalk, C++, Java). Java a établi la norme industrielle "PascalCase pour les classes, camelCase pour les méthodes/variables". Le tournant décisif fut la naissance de JavaScript. Bien que JSON provienne des littéraux d'objets JS, la bibliothèque standard JS (par exemple, getElementById) a adopté le camelCase sur toute la ligne. Alors qu'AJAX et JSON remplaçaient XML comme formats d'échange de données dominants, le camelCase a acquis un statut "natif" dans le domaine du Web.
2. Conflit principal : désaccord d'impédance des piles technologiques
Lorsque les données circulent entre différents langages, elles rencontrent inévitablement un "désaccord d'impédance".
La perspective backend (Python/Ruby/SQL)
Dans le backend, les communautés Python (PEP 8) et Ruby recommandent fortement le snake_case.
- Python/Django/FastAPI : Vos modèles Pydantic correspondent généralement directement aux structures de table de base de données :
class UserProfile(BaseModel):
first_name: str # Convention Python
last_name: strSi l'API impose le camelCase, vous devez configurer des alias ou des convertisseurs dans la couche de sérialisation. Bien que cela soit faisable, cela ajoute une couche de logique de mappage.
- Bases de données SQL : La plupart des noms de colonnes de base de données utilisent le
snake_case. Si l'API utilise lecamelCase, la couche ORM doit gérer la conversion de manière cohérente. - Le choix de Stripe : La raison pour laquelle Stripe et GitHub ont fermement choisi le
snake_caseest largement due au fait que leurs architectures initiales étaient construites sur la pile Ruby. L'exposition directe des modèles internes assurait la cohérence du backend.
La perspective frontend (JavaScript/TypeScript)
Dans le navigateur, le camelCase est le souverain absolu.
- Fragmentation du style de code : Si une API renvoie du
snake_case, le code frontend devient incohérent :
const user = await fetchUser();
console.log(user.first_name); // Viole la règle ESLint camelcase
render(user.email_address);ESLint signalera cela comme un avertissement, forçant les développeurs à désactiver la règle ou à convertir les données immédiatement après réception.
- La douleur du déstructuration : Dans le développement JS/TS moderne, la déstructuration d'objets est omniprésente. Si les champs sont en
snake_case, ils doivent être renommés lors de la déstructuration pour éviter de polluer la portée locale :
// Renommage verbeux
const { first_name: firstName, last_name: lastName } = response.data;Cela augmente le code passe-partout et la probabilité d'erreurs.
3. Mythes de performance : sérialisation et transmission réseau
En ce qui concerne les performances, il existe deux mythes courants : "La conversion des noms de champs est trop lente" et "Les traits de soulignement augmentent la taille de la charge utile." Clarifions avec des données.
Mythe 1 : Surcharge de conversion à l'exécution
- Langages dynamiques : En Python ou Ruby, la conversion des noms de champs via un remplacement d'expressions régulières à chaque requête consomme du CPU. Cependant, les frameworks modernes (comme Pydantic v2, réécrit en Rust) minimisent cette surcharge grâce à des mappages de schémas pré-calculés.
- Langages statiques (Go/Java/Rust) : Cela est effectivement "sans coût". Les balises de structure de Go (
json:"firstName") ou les caches de mappage de Java Jackson sont déterminés au moment de la compilation ou du démarrage. L'exécution à l'exécution implique une simple copie d'octets, et non un calcul dynamique.
Note : Ne jamais effectuer de conversion récursive globale dans le frontend (thread principal du navigateur) en utilisant des intercepteurs (par exemple, Axios). Pour les grandes réponses, cela provoque des saccades de page et une forte consommation de mémoire. Conclusion : Le backend doit gérer la conversion.
Mythe 2 : Taille de transmission et compression
Théoriquement, first_name est un octet plus long que firstName. Cependant, avec la compression Gzip ou Brotli activée (configuration HTTP standard), cette différence disparaît virtuellement.
- Principe : Les algorithmes de compression reposent sur le "référencement de chaînes dupliquées". Dans un tableau JSON, les clés sont très répétitives. L'algorithme stocke
first_namedans un dictionnaire lors de la première rencontre et remplace les occurrences ultérieures par un minuscule pointeur. - Benchmarks : Des tests montrent qu'avec Gzip niveau 6, la différence de taille entre les deux styles est généralement comprise entre 0,5 % et 1 %. À moins que vous ne transmettiez des données via des liaisons satellites, ce n'est pas un problème.
4. Expérience développeur (DX) et psychologie cognitive
L'architecture ne concerne pas seulement les machines ; elle concerne les personnes.
- Lisibilité du
snake_case: La psychologie cognitive suggère que les traits de soulignement offrent une séparation visuelle claire.parse_db_xmlest traité par le cerveau plus rapidement queparseDbXml, surtout lorsqu'il s'agit d'acronymes consécutifs (par exemple,XMLHTTPRequestcontreXmlHttpRequest). C'est l'une des raisons pour lesquelles la documentation de Stripe est considérée comme très lisible. - Cohérence du
camelCase: L'état de fluidité apporté par une cohérence complète de la pile est plus critique. Pour les équipes JS/TS full-stack, l'utilisation ducamelCaseà travers le frontend et le backend permet la réutilisation directe des définitions de types (Interface/Zod Schema), éliminant complètement la charge cognitive de la "traduction mentale".
5. Normes industrielles et justification
| Organisation | Choix | Logique principale & Contexte |
|---|---|---|
| camelCase | Le guide API de Google (AIP-140) exige le lowerCamelCase pour JSON. Même si les définitions Protobuf internes utilisent le snake_case, la couche de conversion externe bascule automatiquement vers le camelCase pour s'aligner avec l'écosystème Web. |
|
| Microsoft | camelCase | Avec l'adoption de l'open source par .NET Core et l'invention de TypeScript, Microsoft a entièrement basculé vers les standards Web, abandonnant l'ancien PascalCase. |
| Stripe | snake_case | Une entreprise typique de la pile Ruby. Ils masquent la différence en fournissant des SDK clients extrêmement robustes. Lorsque vous utilisez le SDK Node, bien que le snake_case soit transmis, les signatures des méthodes du SDK suivent généralement les conventions JS. |
| JSON:API | camelCase | La spécification pilotée par la communauté recommande explicitement le camelCase, reflétant le consensus de la communauté Web. |
6. Conseils architecturaux approfondis : découplage et DTO
Un anti-pattern courant est le "Pass-through" : sérialiser directement les entités de la base de données pour les renvoyer.
- Si vous faites cela, et que vos colonnes de base de données sont en
snake_case, votre API devientsnake_case. - Risque : Cela viole le principe de l'information cachée, expose les structures de table et crée un couplage fort entre l'API et la base de données. Si la base de données est renommée, l'API est rompue.
Meilleure pratique : Introduisez une couche DTO (Data Transfer Object). Indépendamment de la façon dont la base de données sous-jacente est nommée, vous devriez définir un contrat API indépendant (DTO). Puisque vous définissez un DTO, pourquoi ne pas le définir en camelCase pour adhérer aux standards Web ? Les outils de mappage modernes (MapStruct, AutoMapper, Pydantic) gèrent cette conversion sans effort.
7. Perspectives d'avenir : GraphQL et gRPC
GraphQL : La communauté adopte presque à 100 % le camelCase. Si votre équipe prévoit d'introduire GraphQL à l'avenir, la conception des API REST avec le camelCase dès maintenant est une stratégie de "compatibilité ascendante" judicieuse.
gRPC : Le standard Protobuf dicte : les fichiers .proto utilisent le snake_case pour les définitions de champs, mais ils doivent être convertis en camelCase lorsqu'ils sont mappés en JSON. C'est la solution standard de Google pour les environnements multilingues.
8. Résumé et matrice de décision
Il n'y a pas de bien ou de mal absolu, seulement des compromis. Voici le cadre de décision final :
Recommandé : Par défaut en camelCase
Pour la grande majorité des nouvelles API RESTful à usage général destinées aux clients Web/App, le camelCase est fortement recommandé.
Raison : S'aligner avec la dominance de JSON/JavaScript/TypeScript, adoptant les habitudes de 90 % des consommateurs.
Outils : Bénéficiez du meilleur support des générateurs de code OpenAPI, de Swagger UI et des IDE modernes.
Quand utiliser le snake_case ?
1. Consommateurs spécifiques : Les utilisateurs principaux de l'API sont des data scientists Python ou des opérateurs système (Curl/Bash).
2. Systèmes hérités : Les API existantes sont déjà en snake_case. Cohérence > Meilleure pratique. Ne mélangez pas les styles au sein du même système.
3. Extrémisme de vélocité backend : Utilisation de Python/Ruby sans les ressources pour maintenir une couche DTO, en transmettant directement les modèles de base de données.
Tableau de décision
| Dimension | Style recommandé |
|---|---|
| Frontend Web / Application Mobile | camelCase (Zéro impédance, sûreté des types) |
| Analyse de Données / Calcul Scientifique | snake_case (Convient aux habitudes Python/R) |
| Backend Node.js / Go / Java | camelCase (Support natif ou parfait des bibliothèques) |
| Backend Python / Ruby | camelCase (Convertisseur recommandé) ou snake_case (Outils internes uniquement) |
| Équipe Full-Stack | Plus le degré full-stack est élevé, plus le camelCase est recommandé |
L'essence de la conception d'API est l'empathie. Dans le contexte des API Web, encapsuler la complexité dans le backend (gestion du mappage) et laisser la commodité à l'utilisateur (adhérer aux habitudes JS) est le choix qui reflète le plus grand professionnalisme.
