Formatage, validation et schéma JSON en pratique

Publié le 2026-04-13 8 min de lecture

Résumé (TL;DR)

Une équipe avec laquelle j’ai travaillé le mois dernier a livré une modification d’une ligne à feature_flags.json. JSON.parse l’a acceptée, la CI était verte, et une fois arrivée en staging chaque branche de paiement est retombée sur le chemin de code historique parce que flags.checkout_v2 était la chaîne "true" au lieu du booléen true. « Vérifier le JSON » était silencieusement devenu trois activités différentes, et ils n’avaient effectué que les deux premières. Le pretty-printing remet en forme les espaces pour qu’un humain puisse lire un blob ; il ne vérifie rien. La validation syntaxique confirme qu’une chaîne est analysable comme JSON selon la RFC 8259 — crochets appariés, guillemets corrects, littéraux numériques corrects — et c’est précisément ce que fait JSON.parse. La validation structurelle est une étape séparée qui demande si la valeur analysée a la forme que votre programme attend : champs requis, types corrects, valeurs d’enum autorisées, longueurs de chaînes, plages numériques. Cette dernière étape est exactement pour ce à quoi JSON Schema a été conçu, et c’est celle que la plupart des équipes sautent jusqu’à ce qu’un bug de production comme celui ci-dessus les force à l’ajouter. Un pipeline fiable utilise les trois à la bonne couche : formater quand vous avez besoin de lire les données, parser pour attraper les entrées mal formées, et lancer une vérification de schéma de style Ajv aux frontières de confiance — requêtes API entrantes, fichiers de configuration et messages inter-services.

Contexte et concepts

JSON est défini par la RFC 8259 (et l’équivalent ECMA-404). La grammaire est intentionnellement petite. Un document JSON est l’un parmi : une chaîne, un nombre, true, false, null, un tableau ou un objet. Les chaînes sont entre guillemets doubles et prennent en charge une courte liste d’échappements dont \n, \t, \", \\ et \uXXXX pour les unités de code Unicode. Les nombres suivent une grammaire décimale avec signe optionnel, partie fractionnaire et exposant, mais il n’y a pas de distinction entre entier et virgule flottante au niveau syntaxique. Les objets sont des collections non ordonnées de membres à clés-chaînes, les tableaux sont des listes ordonnées, et les espaces hors chaînes ne sont pas significatifs.

Ce que JSON n’inclut intentionnellement pas est presque aussi important. Il n’y a pas de commentaires, pas de virgules traînantes, pas de chaînes entre guillemets simples, et pas de littéraux hexadécimaux ou binaires. Les caractères Unicode hors plage ASCII doivent apparaître soit comme octets UTF-8 bruts dans le flux encodé, soit comme échappements \u. Des extensions comme JSON5 et HJSON assouplissent certaines de ces règles, mais ce sont des formats séparés et les parsers qui acceptent du JSON strict les rejetteront.

Une fois qu’un document est analysé, sa validité syntaxique ne dit rien sur le fait qu’il s’agisse des bonnes données. Une charge utile de login comme {"user": "x", "pass": "y"} est un JSON parfaitement valide, même si votre endpoint attendait {"username": "...", "password": "..."}. Pour attraper cette classe d’erreurs vous avez besoin d’un schéma : une description lisible par machine de ce qui compte comme document acceptable. JSON Schema (le méta-schéma actuellement recommandé est Draft 2020-12) comble ce vide. Il prend en charge les champs requis, les contraintes de type, enum et const, les motifs de chaînes via regex, les plages numériques, les items et l’unicité de tableaux, les properties et additionalProperties d’objets, et la composition via allOf, oneOf, anyOf et $ref. Ajv 8.12 compile un schéma une fois en une fonction de validation JavaScript, ce qui est assez rapide pour les chemins critiques — dans un service Node 20.11 que j’ai instrumenté, une vérification Ajv compilée sur un corps de requête typique se situait dans la dizaine de microsecondes.

Le pretty-printing est le plus banal des trois. Il n’insère que des espaces — indentation et sauts de ligne — sans changer le sens. La plupart des éditeurs et outils en ligne de commande le font ; les outils de dev navigateur le font automatiquement dans le panneau réseau. C’est utile pour les humains et sans intérêt pour les machines.

Comparaison et données

AspectPretty-printingValidation syntaxiqueValidation JSON Schema
ObjectifRendre les données lisiblesS’assurer que le texte se parse comme JSONS’assurer que les données analysées correspondent à une forme attendue
DétecteRien — espaces seulementCrochets non appariés, mauvais guillemets, échappements invalides, virgules traînantesChamps manquants, mauvais types, valeurs hors plage, clés inconnues
Ne détecte pasProblèmes structurels, sémantiquesProblèmes structurels (forme attendue), règles métierRègles sémantiques au-delà du schéma, invariants inter-champs sans mots-clés personnalisés
Outillage typiqueJSON.stringify(obj, null, 2), jq, formateur IDEJSON.parse, jq -e, tout parserAjv 8.x, python-jsonschema, validateurs OpenAPI
Où l’exécuterOutils développeur, logsÀ chaque frontière de parsing (implicite)Aux requêtes/réponses API, chargement de config, frontières de messages

Les trois colonnes ne sont pas des alternatives ; ce sont des couches séquentielles. Ouvrir un package-lock.json de 12 Mo sur une seule ligne dans un éditeur brut est la façon dont vous finissez avec une chaîne que votre outil de diff refuse de comparer, et l’embellir en forme indentée ne valide rien — cela rend juste la forme lisible. Cette distinction importe parce que les deux couches suivantes, syntaxe et schéma, sont souvent confondues avec « je l’ai pretty-print et rien n’a explosé ». Pretty-print pour lire, parser pour attraper un texte mal formé, et valider avec un schéma pour attraper une mauvaise forme. Ne livrer que les deux premières est un trou courant.

Scénarios concrets

Scénario 1 — Déboguer une réponse d’API. Une passerelle de paiement tierce renvoie un corps JSON de 600 lignes et le navigateur le montre sur une seule ligne. Le pretty-print — soit avec les outils de dev du navigateur, un formateur local, ou curl ... | jq . — le transforme en quelque chose qu’un humain peut parcourir. Aucune validation n’a lieu ici ; l’objectif est la lisibilité pendant que vous chassez le champ qui a l’air faux, et la discipline importante est de ne pas appeler cette étape « validée ».

Scénario 2 — Charger un fichier de configuration. Un service lit config.json au démarrage. Un parser JSON strict attrape les erreurs de syntaxe comme une virgule traînante égarée et refuse de démarrer, ce qui est le bon comportement. Mais, comme l’incident d’ouverture l’a montré, un fichier valide avec retries: "three" au lieu de retries: 3 se parsera très bien et n’échouera que lorsque le code essaiera de comparer une chaîne à un nombre. Le motif qui a fonctionné pour moi est de mettre Ajv.compile(schema)(config) dans les toutes premières lignes du point d’entrée et d’appeler process.exit(1) en cas d’échec — un changement de cinq minutes qui a payé pour lui-même les deux fois suivantes où quelqu’un a édité le fichier à la main.

Scénario 3 — Vérifier un contrat OpenAPI. Une équipe livre un document OpenAPI 3.1 qui décrit les endpoints, les corps de requêtes et les formes de réponses sous components.schemas. Les tests de contrat prennent les charges utiles d’exemple de la spécification et les valident contre les schémas en utilisant un validateur JSON Schema. Quand une implémentation de serveur dérive — disons, commence à renvoyer un entier là où la spec promettait une chaîne — le test de contrat signale l’écart avant qu’un client ne casse en production. C’est le même moteur JSON Schema que vous utiliseriez pour un fichier de config isolé ; la différence est l’échelle de couverture.

Idées fausses courantes

« JSON.parse suffit à valider le JSON. » Il valide la syntaxe, pas la forme. Un parser retournera joyeusement un objet auquel il manque la moitié des champs dont votre code a besoin. Traitez JSON.parse comme une barrière contre le texte mal formé et superposez une vérification de schéma par-dessus quand les données traversent une frontière de confiance.

« JSON Schema est uniquement côté serveur. » Valider dans le navigateur avant d’envoyer une requête donne aux utilisateurs un retour instantané et réduit la charge sur le serveur. Beaucoup de bibliothèques de formulaires et Ajv lui-même tournent confortablement dans le navigateur. La validation côté serveur doit toujours tourner — ne faites jamais confiance au client — mais les vérifications côté client améliorent l’UX sans affaiblir le modèle de sécurité.

« JSON5 n’est que du JSON avec des commentaires. » JSON5 ajoute des commentaires, des clés sans guillemets, des virgules traînantes, des nombres hexadécimaux et plus. Cela le rend plus amical comme format de configuration édité par l’humain — le consommateur le plus connu est tsconfig.json, qui utilise en fait JSONC (un autre sur-ensemble non standard différent) — mais tout ce qui suit strictement la RFC 8259 ne l’acceptera pas. Utilisez JSON5/JSONC là où le consommateur documente le support ; émettez du JSON strict quand vous écrivez sur le réseau ou vers tout outil dont vous ne contrôlez pas le parser.

« YAML n’est que du JSON avec de l’indentation. » Chaque document JSON valide est un YAML valide, mais YAML ajoute des fonctionnalités — ancres et alias, types tagués, plusieurs documents dans un fichier, scalaires en bloc et plié, parsing sensible à l’indentation — qui introduisent des bugs que JSON ne peut pas. Le classique est le fameux « problème norvégien » : YAML 1.1 interprète NO comme le booléen false sauf si vous l’entourez de guillemets. Passer de JSON à YAML pour « le rendre lisible » échange une classe de problèmes contre une autre.

Liste de vérification

  1. Avez-vous juste besoin de lire les données ? Pretty-print. Ne prétendez pas que c’est « validé ».
  2. Traversent-elles une frontière de confiance (requête HTTP, file de messages, fichier de config) ? Parsez puis lancez une vérification JSON Schema, pas seulement un parse.
  3. Vous souciez-vous des champs inconnus ? Définissez additionalProperties: false dans le schéma et décidez de rejeter ou retirer les extras.
  4. Les erreurs sont-elles actionnables ? Configurez le validateur (par exemple Ajv avec allErrors: true) pour renvoyer chaque violation afin que les utilisateurs voient tous les problèmes d’un coup.
  5. Le schéma vit-il à côté du code qui utilise les données ? La dérive entre une spécification et une implémentation est plus facile à prévenir quand le schéma est une source de vérité pour les deux.
  6. Le format est-il assez stable pour JSON ? Si des humains doivent l’éditer et que vous contrôlez le parser, JSON5/JSONC ou TOML peuvent être plus indulgents. Si des machines l’échangent, restez avec JSON strict.

Outil associé

Le formateur JSON Patrache Studio tourne dans le navigateur, donc la charge utile que vous collez ne quitte jamais votre machine — utile quand vous inspectez une réponse de production contenant des données personnelles. Les charges utiles vivent rarement seules : si le JSON que vous formatez inclut un binaire intégré, les règles dans Base64 et encodage d’URL : but, pièges, usage correct expliquent pourquoi le blob grandit et quand un transport différent est approprié. Si la charge utile inclut des identifiants, UUID v1 vs v4 vs v7 : choisir une clé primaire de BD couvre pourquoi la version exacte que vous générez sur le serveur affecte la façon dont les systèmes en aval indexent, trient et mettent en cache ce JSON.

Références