La première version d’une API JSON naît souvent d’un besoin immédiat: afficher une page, alimenter une application mobile ou connecter un partenaire. Quelques champs suffisent. La difficulté arrive plus tard, lorsque des clients anciens, des scripts, des tableaux de bord et des intégrations externes dépendent déjà de cette forme. Concevoir pour le changement consiste à traiter le JSON comme une interface publique, même lorsqu’il semble interne.

Ajouter est plus sûr que modifier

Un client robuste ignore les champs inconnus. Cette convention permet au serveur d’enrichir une réponse sans casser les consommateurs. Modifier un champ existant est beaucoup plus risqué. Si un nombre devient une chaîne, si une propriété disparaît ou si un enum change de sens, certains clients échouent et d’autres produisent de mauvaises décisions.

Les tests de contrat doivent conserver des exemples historiques. Ils prouvent que les réponses nouvelles restent compatibles avec les promesses anciennes.

Null et absence doivent avoir un sens

Un champ absent peut signifier que le serveur ne fournit pas cette information. Un champ présent à null peut signifier que l’information est connue mais vide. Si l’API ne précise pas la différence, chaque client invente sa propre règle.

Documentez les champs requis, optionnels et nullable. Pour une liste sans élément, un tableau vide est souvent plus clair que null. Pour des objets partiels, il vaut parfois mieux séparer endpoints de résumé et de détail.

Les identifiants importants devraient être des chaînes

JSON possède un type numérique unique. Certains environnements ne représentent pas tous les entiers longs sans perte de précision. Un identifiant de base de données ou un numéro externe n’est pas une quantité à calculer; c’est une étiquette stable.

Le transporter comme chaîne préserve les zéros initiaux, évite les arrondis et signale qu’il ne faut pas l’additionner. Cette décision semble simple, mais elle évite des bugs coûteux entre backend et JavaScript.

Les dates exigent une sémantique

Un champ created_at ne suffit pas. Est-ce un instant UTC, une date locale, une heure planifiée ou une durée? JSON ne le sait pas. L’API doit préciser format, fuseau, précision et règle d’arrondi.

Pour un instant, ISO 8601 avec offset explicite est généralement plus clair. Pour une date de calendrier, un champ date sans heure peut être plus juste. Mélanger ces concepts dans une chaîne vague crée des bugs de fuseau horaire.

Les erreurs font partie du contrat

Les réponses de succès sont souvent soignées, tandis que les erreurs restent du texte libre. C’est une erreur de design. Un format d’erreur durable contient un code stable, un message humain, des détails facultatifs et un identifiant de requête.

Le code stable permet au client de réagir sans parser une phrase. Le message peut être traduit ou amélioré sans casser l’automatisation.

Versionner demande une politique

Tous les changements ne nécessitent pas une nouvelle URL. Un champ ajouté, une extension optionnelle ou un media type peuvent suffire. Une rupture de type ou de signification doit en revanche être traitée comme une nouvelle version ou une migration explicite.

Les versions anciennes ont besoin de métriques, de date de retrait et de communication. Les supprimer sans savoir qui les utilise transforme une décision technique en incident client.

L’entrée doit être stricte de manière consciente

Accepter des formes multiples facilite parfois une migration. Mais corriger silencieusement les erreurs cache des intégrations cassées. Si un endpoint accepte ID numérique et ID chaîne, il doit normaliser explicitement et mesurer qui envoie quoi.

Une bonne règle est d’être strict sur ce que l’on reçoit et compatible dans ce que l’on émet. Cela pousse les producteurs à corriger tôt tout en permettant aux consommateurs de tolérer les extensions.

Les exemples sont exécutables socialement

Des exemples réalistes avec listes vides, null, erreurs, pagination et dates valent plus qu’une documentation abstraite. Ils servent de langage commun entre équipes et peuvent devenir fixtures de tests. Lorsqu’un exemple change, on doit savoir si le contrat a changé.

Les observabilités de version évitent les surprises

Avant de retirer un champ ou une version, il faut savoir qui l’utilise encore. Les logs de client, les métriques par version et les alertes sur anciens contrats transforment une décision de rupture en migration contrôlée. Sans ces données, une équipe peut croire qu’un ancien format est mort alors qu’un partenaire critique l’utilise toujours.

La compatibilité n’est pas seulement une propriété du code. C’est aussi une propriété mesurée dans le trafic réel.

Les noms de champs portent une responsabilité

Un nom vague comme status ou type peut survivre longtemps tout en accumulant des sens incompatibles. Documenter les valeurs possibles, leur lifecycle et leur propriétaire évite que chaque client interprète le même champ à sa manière. Quand un concept change, mieux vaut ajouter un champ plus précis que redéfinir silencieusement l’ancien.

Les conventions de casse, de langue et de nommage doivent elles aussi rester stables. Un contrat agréable à lire aujourd’hui doit surtout être prévisible demain.

Une API JSON qui survit au changement n’est pas celle qui reste figée. C’est celle qui évolue avec des règles connues: champs stables, types explicites, erreurs structurées, versioning mesuré et preuves automatiques de compatibilité.