1. JSON-document = JSON-valeur
Quand une personne voit JSON pour la première fois, elle se souvient souvent de « quelque chose entre accolades ». C’est une illusion de départ normale, un peu comme penser qu’Internet, ce sont « des pages dans un navigateur ». En réalité, JSON est beaucoup plus simple et à la fois plus strict : JSON-document = une seule JSON-valeur. Oui, parfois cette valeur ressemble à un objet {...} ou à un tableau [...], mais « l’atome » de JSON est justement une valeur, et cette valeur a un type.
Il existe seulement six sortes de valeurs en JSON : chaîne, nombre, booléen, null, objet et tableau. Aujourd’hui, nous ne prenons délibérément que les types « simples » (scalaires) : chaîne, nombre, boolean et null. On les rencontre dans littéralement chaque API : title et author sont des chaînes, id et count sont des nombres, certains isAvailable sont des boolean, et comment peut être null. Et c’est là que les choses deviennent intéressantes : le type d’une valeur n’est pas défini par « ce que ça signifie en français », mais par la façon dont c’est écrit.
Pour saisir l’idée, il est utile de voir qu’un « petit » JSON comme celui-ci est aussi valide et constitue un JSON-document à part entière :
// Chacun de ces littéraux est un document JSON distinct (une seule valeur JSON)
String jsonDoc1 = "true"; // boolean
String jsonDoc2 = "2008"; // number
String jsonDoc3 = "\"Clean Code\""; // string (les guillemets font partie de JSON, donc ils sont échappés dans la chaîne Java)
String jsonDoc4 = "null"; // null
Les quatre chaînes ci-dessus sont des JSON-documents valides (chacun pris individuellement). Dans une API réelle, on ne fait presque jamais cela au niveau racine (là on a généralement un objet ou un tableau), mais à l’intérieur d’un objet, on rencontre constamment de telles valeurs. Et si vous apprenez à voir rapidement le type d’une valeur, votre niveau d’anxiété baissera nettement à la lecture de réponses réelles : vous saurez où se trouve du texte, où un nombre, où un indicateur, et où « il n’y a pas de valeur ».
Pour illustrer, voici une petite « carte du terrain » de l’endroit où s’inscrivent nos types aujourd’hui :
flowchart TD V["JSON value"] --> S["String"] V --> N["Number"] V --> B["Boolean"] V --> Z["Null"] V --> O["Object"] V --> A["Array"]
2. Les chaînes en JSON : guillemets et échappement
Les chaînes sont le type le plus « humain » en JSON. Les titres de livres, les noms d’auteurs, les statuts comme "PLANNED" – tout cela, ce sont des chaînes. Et justement, à cause de cette familiarité, beaucoup de débutants commettent les erreurs les plus vexantes : utiliser des guillemets simples, oublier l’échappement, ou transformer accidentellement un nombre en chaîne (et ensuite s’étonner que "10" ne se comporte pas comme 10). Alors, mettons-nous d’accord sur quelques règles en acier, et la vie deviendra plus sereine.
Première règle : le type chaîne en JSON se reconnaît aux guillemets doubles. Si vous voyez "Clean Code", c’est une chaîne. Sans guillemets, ce n’est plus une chaîne JSON, et les guillemets simples ne conviennent pas non plus.
Voici des exemples minimaux de chaînes JSON (en tant que documents JSON distincts) :
// À l’intérieur d’une chaîne Java, on stocke une chaîne JSON, donc les guillemets JSON doivent être échappés
String jsonTitle = "\"Clean Code\"";
String jsonAuthor = "\"Robert C. Martin\"";
// On imprime tel quel : vous verrez exactement la représentation JSON avec parenthèses et guillemets
System.out.println(jsonTitle); // "Clean Code"
System.out.println(jsonAuthor); // "Robert C. Martin"
Notez cette « double réalité » : on écrit une chaîne Java qui contient une chaîne JSON. Donc les guillemets doivent être échappés. Oui, cela ressemble à des « guillemets dans les guillemets », et c’est normal. Habituez-vous : en développement backend, vous décrivez constamment des données à l’intérieur d’autres données (HTTP dans du code, JSON dans HTTP, puis DTO dans JSON… et ainsi de suite par spirale de maturité).
Deuxième règle : à l’intérieur d’une chaîne, il faut parfois échapper des caractères. Par exemple, si vous voulez transmettre un guillemet comme partie du texte, en JSON, il doit être écrit \". De même, un antislash s’écrit \\. Exemple :
// Ici, la chaîne JSON contient des guillemets, donc ils deviennent \" (et dans la chaîne Java, cela donne \\")
String jsonWithQuotes = "\"He said: \\\"hi\\\"\"";
System.out.println(jsonWithQuotes); // "He said: \"hi\""
Pour ne pas transformer cette leçon en cours « Vaincre les antislashs », retenez simplement les séquences d’échappement courantes. Voici un petit tableau qui couvre généralement 90% de la réalité :
| Ce qu’on veut à l’intérieur de la chaîne | Comment l’écrire dans une chaîne JSON |
|---|---|
| " | \" |
| \ | \\ |
| retour à la ligne | \n |
| tabulation | \t |
Et encore une nuance pratique : en JSON, il n’y a pas de type séparé « caractère » (comme le char en Java). Il n’y a que des chaînes. Donc "A" est une chaîne de longueur 1, et c’est normal.
Si on relie cela à notre projet ReadLater Starter, presque tous les champs « humains » seront des chaînes : title, author, status, externalId, comment. Même si status ressemble à une « énumération », au niveau JSON, c’est toujours une chaîne (nous parlerons de la discipline des DTO dans une leçon ultérieure, mais pour lire le contrat, c’est ce qui importe).
3. Les nombres en JSON : format et guillemets
Avec les nombres en JSON, tout semble simple jusqu’à la première vraie API. Ensuite, on découvre soudainement que 2008 et "2008" sont des choses différentes, que 3,14 n’est pas un nombre (à cause de la virgule), que 01 est une notation suspecte, et que « pourquoi mon id est soudainement une chaîne » n’est pas une question philosophique, mais une douleur concrète d’intégration. Maintenant, voyons les bases, sans académisme mathématique, mais honnêtement.
Règle principale : un nombre en JSON s’écrit sans guillemets. Si vous voyez 2008, c’est un nombre. Si vous voyez "2008", c’est une chaîne, même si, à vue d’œil, on a envie de crier « mais c’est une année ! ». JSON ne regarde pas avec les yeux, il regarde avec la syntaxe.
Un mini-ensemble d’exemples de nombres en tant que documents JSON :
// Ces valeurs ressemblent à des nombres et sont écrites sans guillemets – ce sont donc des JSON-number
String jsonYear = "2008";
String jsonCount = "0";
String jsonRating = "4.5";
String jsonNegative = "-1";
Oui, la partie décimale s’écrit avec un point, pas une virgule. En ce sens, JSON est « international » et suit un format machine, pas les habitudes d’une personne et de son clavier.
Parfois, vous rencontrerez aussi la notation scientifique (surtout si le JSON provient de sources scientifiques ou financières). Au niveau de la lecture du contrat, il est utile d’au moins connaître cette forme :
String jsonScientific = "1e3"; // notation scientifique : cela vaut 1000
Parlons maintenant de la discipline. Dans la spécification JSON, les nombres sont décrits de manière assez stricte (par exemple, les zéros non significatifs comme 01 ne sont pas autorisés). Mais en pratique, en tant que développeur, vous faites une chose très simple : vous convenez quels champs du contrat sont des nombres et vous veillez à ce qu’ils ne « s’échappent » pas vers des chaînes.
Dans ReadLater, il y aura presque certainement des nombres pour les identifiants et les compteurs : id, count. Plus tard, quand nous renverrons une liste, apparaîtra count : 0, 1, 42. Il est important que ce soient des nombres et non des chaînes – sinon le client (que ce soit un script Postman ou une application) devra faire des conversions inutiles.
L’exemple le plus parlant de l’importance du type est le tri. Les chaînes sont triées comme du texte, les nombres comme des nombres. Dans le monde textuel, "10" est « plus petit » que "2" parce que '1' vient avant '2'. Dans le monde numérique, 10 est plus grand que 2. Et si vous voyez un jour un tri ou un filtrage étrange, la première pensée devrait être : « Avons-nous bien transformé des nombres en chaînes ? ».
Au fait, si vous lisez du JSON avec les yeux (dans Postman ou en lisant simplement une réponse), vous pouvez presque toujours distinguer une chaîne d’un nombre d’un seul geste : la chaîne a des guillemets, le nombre non.
4. Booléen en JSON : true/false sans guillemets
Les valeurs booléennes en JSON sont de petits indicateurs honnêtes. Elles sont idéales pour les champs du type « activé/désactivé », « disponible/indisponible », « présent/absent ». Elles sont les plus faciles à lire à l’œil, et c’est justement pourquoi on les abîme le plus souvent… avec des « améliorations ». Par exemple, quelqu’un décide d’écrire "True" avec une majuscule, quelqu’un d’autre "yes", un autre "0" et "1". Et là, le cirque commence, et les clients doivent dépiler tout ça à la main.
En JSON, tout est strict : une valeur booléenne, c’est seulement true ou false, obligatoirement en minuscules, et sans guillemets.
Un mini-ensemble d’exemples :
// De vrais boolean en JSON : seulement true/false et sans guillemets
String jsonTrue = "true";
String jsonFalse = "false";
// En revanche, ceci est une chaîne, même si ça ressemble à false
String jsonTextFalse = "\"false\"";
System.out.println(jsonTrue); // true
System.out.println(jsonFalse); // false
System.out.println(jsonTextFalse); // "false"
Le troisième exemple n’est pas un booléen, mais une chaîne contenant le mot false. Pour un humain, « le sens est clair », mais pour un contrat, c’est un type différent, et un client qui attend un booléen aura le droit de dire : « Désolé, je ne peux pas ingérer ça ».
Où des booléens peuvent-ils apparaître dans ReadLater Starter ? Dans notre domaine d’apprentissage, il y en a peu, mais ils sont tout à fait possibles comme indicateurs de service. Par exemple, dans /health (qui viendra plus tard), on pourrait théoriquement avoir healthy : true. Ou dans le catalogue externe, un livre peut avoir hasCover : true. Peu importe le champ exact – ce qui compte, c’est qu’une fois que nous choisissons le type booléen, nous nous en tenons à un vrai booléen, pas à un « pseudo-booléen textuel ».
Autre nuance : le booléen en JSON est un type logique, pas une « économie technique de symboles ». Par conséquent, les idées du genre « stockons les indicateurs en 0/1 » nuisent le plus souvent à la lisibilité et ajoutent une conversion côté client.
5. null en JSON : absence de valeur
null est peut-être le mot le plus utile et le plus mal compris en JSON. Les débutants le perçoivent souvent comme « vide » au sens large : chaîne vide, zéro, absence de champ – tout ça mélangé. Mais au niveau du contrat API, null signifie une chose très précise : la valeur est explicitement absente. En d’autres termes, nous n’avons pas « oublié » d’envoyer le champ, mais nous disons consciemment : « le champ existe, mais pour l’instant il n’a pas de valeur ».
En JSON, null s’écrit exactement comme ceci : null, sans guillemets.
// null en JSON est une valeur à part entière, sans guillemets
String jsonNull = "null";
System.out.println(jsonNull); // null
Dans les API réelles, null apparaît particulièrement souvent dans les champs facultatifs. Par exemple, dans ReadLater, un livre peut ne pas avoir de externalId (si nous l’avons ajouté manuellement et non depuis un catalogue), ou l’utilisateur peut ne pas avoir laissé de commentaire. On rencontre alors ces fragments :
// Bloc textuel : pratique pour montrer du JSON sans échapper les guillemets dans une chaîne Java
String jsonCommentNull = """
{ "comment": null }
""";
String jsonExternalIdNull = """
{ "externalId": null }
""";
Je vous montre cela exprès dans un objet pour que vous voyiez le contexte « naturel », mais dans cette leçon nous n’avons pas besoin d’analyser l’objet lui-même – seulement la valeur null.
Il est important de ne pas confondre null avec « chaîne vide » et « zéro ». Si le champ est "comment": "", cela signifie : le commentaire existe, il est textuel, mais vide. Si "count": 0, cela signifie : la valeur existe, elle est numérique, et c’est zéro. Si "comment": null, cela signifie : le commentaire en tant que valeur n’existe pas (il est inconnu ou non défini – et le contrat doit l’expliquer).
Et oui, je sais que le cerveau a envie de dire « mais tout ça revient presque au même sens ». En API, ce n’est pas le cas. Le client (et vous-même dans quelques semaines) remerciera le contrat pour sa précision, même si sur le coup on voudrait quelque chose de plus simple.
Pour finir, un petit « accroche » pour la prochaine leçon : null est un état, mais il en existe un autre : « le champ est absent ». C’est différent. Nous comparerons cela en détail plus tard, mais il est déjà utile de garder en tête : null est l’absence explicite de valeur.
6. Analyseur visuel basé sur les premiers caractères
Quand JSON devient long et imbriqué, on a très envie de « saisir le sens » en une seconde : où est la chaîne, où est le nombre, où est l’objet, où est le tableau. Bonne nouvelle : en ce sens, JSON est friendly. Le type d’une valeur se devine presque toujours à ses premiers caractères, si vous regardez non pas le sens des mots, mais la forme de l’écriture. C’est une de ces petites compétences qui rendent soudain la lecture des réponses API plus calme.
L’heuristique la plus simple est la suivante : regardez le premier caractère « significatif » (après les espaces et les retours à la ligne). Si c’est " – c’est une chaîne. Si c’est un chiffre ou - – c’est probablement un nombre. Si c’est t ou f – c’est un booléen. Si n – c’est null. Si { – c’est un objet. Si [ – c’est un tableau.
On peut même fabriquer un petit « aide-mémoire » sous forme de tableau :
| Premier caractère (après les espaces) | Type de la valeur |
|---|---|
| " | chaîne |
0…9 ou |
nombre |
t / |
true / false |
| n | null |
| { | objet (leçon suivante) |
| [ | tableau (leçon suivante) |
Si vous voulez ancrer cela au niveau du code (simplement comme illustration, pas comme un véritable analyseur), vous pouvez écrire une mini-fonction « devine le type à la vue » – et voir que la logique est vraiment élémentaire :
static String guessJsonType(String json) {
// On enlève les espaces/retours à la ligne : seul le premier caractère « significatif » compte
String t = json.trim();
// Une chaîne en JSON commence toujours par un guillemet double
if (t.startsWith("\"")) return "STRING";
// Boolean – seulement true/false (sans guillemets)
if (t.equals("true") || t.equals("false")) return "BOOLEAN";
// null – valeur à part entière (sans guillemets)
if (t.equals("null")) return "NULL";
// Aux premiers caractères, on reconnaît facilement objet/tableau
if (t.startsWith("{")) return "OBJECT";
if (t.startsWith("[")) return "ARRAY";
// Si ça ne ressemble à rien de ce qui précède, c’est le plus souvent un nombre (mais on ne le valide pas ici)
return "NUMBER (ou quelque chose d’étrange)";
}
Cette fonction ne fait pas de validation et ne comprend pas les subtilités des nombres – et nous n’en avons pas besoin pour l’instant. Elle montre l’essentiel : JSON est construit de façon à ce que le type se « lise » dans la forme, non qu’il se devine par le contexte.
7. Les types et le contrat API
Au niveau « je lis avec les yeux », les types semblent être un détail. Mais le développement backend apprend vite : un contrat n’existe pas pour la beauté, mais pour que deux parties indépendantes puissent interagir de manière fiable. Le client n’est pas dans votre tête et ne devine pas ce que vous « vouliez dire ». Il voit des octets concrets et tente de les transformer en une structure de données. Et si le type « dérape », une chaîne de désagréments commence.
Imaginez un scénario typique pour notre future API locale : vous renvoyez une liste d’éléments de lecture et à côté vous écrivez count. Si vous avez renvoyé count comme une chaîne ("count": "2"), alors le client qui attend un nombre soit plantera avec une erreur, soit devra faire une conversion. Dans Postman, cela se voit aussi immédiatement : des guillemets autour d’un nombre, c’est comme un drapeau rouge « nous ne sommes pas d’accord sur les termes ».
Ou un autre scénario : le statut de lecture. Si vous avez renvoyé "status": "FINISHED", c’est une chaîne, et le client peut la comparer aux options attendues. Si vous avez renvoyé "status": true (oui, cela arrive aussi dans la vraie vie, quand quelqu’un a « optimisé » le modèle), alors le client ne pourra pas comprendre ce que cela signifie : lu ? Pas lu ? Et où est IN_PROGRESS dans tout ça ? Le problème n’est pas seulement le type, mais aussi le sens que le type aide à maintenir.
Autre source fréquente de douleur : null. Pour les champs facultatifs comme comment ou externalId, null est un état normal, mais seulement si il est attendu selon le contrat. Si le client pense que c’est toujours une chaîne, et que le serveur envoie parfois null, des histoires à la NPE apparaissent (dans différents langages, cela se manifeste différemment, mais le fond est le même : « j’attendais du texte, j’ai reçu une absence de valeur »).
Par conséquent, la règle « voir le type » n’est pas une théorie pour la théorie. C’est une protection pratique contre la situation où vous avez l’impression de « donner les bonnes données », mais le système s’effondre parce que les données sont d’un autre type. Et ce qui est particulièrement important pour nous dans ce cours : tant que nous n’utilisons aucun framework, nous devons apprendre à repérer nous-mêmes ces problèmes à l’œil, avant même l’apparition de DTO pratiques et de mappages automatiques.
8. Erreurs typiques avec les valeurs simples
Les erreurs avec les valeurs simples JSON sont généralement sournoises parce qu’elles ont l’air « presque juste ». Le cerveau comble le sens, et tout semble ok – jusqu’à ce que vous essayiez de les envoyer à un vrai client, d’ouvrir la réponse dans Postman ou de demander à un programme de traiter les données. Voici les râteaux les plus fréquents sur lesquels les débutants tombent, et les raisons pour lesquelles ces râteaux sont si populaires.
Erreur n°1 : guillemets simples au lieu de guillemets doubles dans les chaînes.
Une écriture comme 'Clean Code' semble souvent « presque la même chose ». Mais pour JSON, ce n’est plus une valeur de type chaîne, c’est un fragment invalide. Dès que des guillemets simples apparaissent dans les chaînes à la place des guillemets doubles, le client n’a rien à analyser sans béquilles.
Erreur n°2 : nombres entre guillemets « au cas où ».
Une pensée très courante : « Bon, mettons-en une chaîne, ce sera plus sûr ». Résultat : 2008 devient "2008", count devient "0", et le client ne peut soudain plus effectuer d’opérations numériques sans conversion. Cela casse les tris, les filtres et ajoute simplement de la friction. Si la valeur est numérique par le sens du contrat, elle doit être numérique aussi dans la forme.
Erreur n°3 : valeurs booléennes en tant que chaînes – "true" et "false".
Cela arrive presque toujours à cause de la logique « je vois un mot, donc c’est une chaîne ». Mais en JSON, le booléen est un type séparé, et false diffère de "false". Si vous envoyez "false" au lieu de false, le client peut l’interpréter comme « chaîne non vide », donc « vrai » dans certains langages/vérifications, et vous obtenez un bug très amusant : « j’ai false, mais ça se comporte comme true ».
Erreur n°4 : virgule décimale au lieu du point dans les nombres.
3,14 est familier pour l’humain, mais pas pour JSON. JSON utilise le point : 3.14. La virgule en JSON est un séparateur d’éléments, pas une partie du nombre. Par conséquent, une écriture avec une virgule rend le document invalide ou conduit à une interprétation complètement différente.
Erreur n°5 : null perçu comme une chaîne vide, zéro ou « faux ».
null est une valeur distincte qui signifie « absence de valeur ». La chaîne vide "" signifie « la chaîne existe mais est vide ». Le zéro 0 signifie « le nombre existe et vaut zéro ». false signifie « la valeur logique existe et est fausse ». Si on mélange ces états, le contrat devient flou : le client doit deviner ce que vous vouliez dire exactement.
GO TO FULL VERSION