Contrat d'API
PostShip apprend la forme d'une réponse JSON sur trois passages, puis alerte dès qu'elle dérive.
Mis à jour le 11 septembre 2026
Sur cette page
- Ce que PostShip vérifie
- Ce que le schéma retient
- Cassant ou informatif
- Régler
- Ce qui déclenche une alerte
- Limites et plans
- Dépannage
- Pourquoi une propriété optionnelle est signalée « n'est plus toujours présent » ?
- Pourquoi le passage est en erreur plutôt qu'en échec ?
- L'API répond du JSON mais avec Content-Type: text/html
Une API qui répond 200 peut casser vos clients : price devient une chaîne, items disparaît, une date n'en est plus une. Rien ne le signale, jusqu'à ce que l'application mobile plante ou que l'intégration d'un partenaire s'arrête. Le contrat d'API demande une URL qui rend du JSON, apprend sa forme, puis compare chaque passage à ce qu'il a appris. Vous ne rédigez aucun schéma.
Ce que PostShip vérifie
À chaque passage, PostShip fait un GET avec Accept: application/json (12 secondes, 5 redirections, en-tête privé possible) et procède dans l'ordre :
- Le statut. Il doit être exactement le statut attendu (200 par défaut). Sinon, échec franc, avant même de lire le corps : le contrat commence par « répondre ».
- Le JSON. Le corps doit être du JSON valide et tenir en 512 Ko — au-delà, ce n'est pas un contrat, c'est un export, et le passage est en erreur.
- L'apprentissage. Les 3 premiers passages nourrissent le schéma sans jamais juger. Un seul échantillon ne dit pas ce qui est optionnel ni ce qui est une énumération ; deux, à peine plus.
- La comparaison. À partir du quatrième passage, la réponse est comparée au schéma appris. Chaque écart est une dérive, cassante ou informative.
Ce que le schéma retient
Pour chaque valeur : son type (null, booléen, nombre — entier ou non —, chaîne, tableau, objet), les types alternatifs vus au même endroit (string | null), et pour les chaînes un format reconnu (date, datetime, url, email, uuid) ou les valeurs distinctes vues tant qu'elles sont peu nombreuses (8 au plus, de 64 caractères au plus) — c'est ainsi qu'un status devient une énumération paid | pending. Une propriété présente dans tous les échantillons est requise ; présente dans certains, optionnelle. Au-delà de 12 niveaux d'imbrication ou de 200 clés dans un objet, le conteneur est tronqué : c'est un dictionnaire indexé, pas une structure.
Cassant ou informatif
| Dérive | Gravité | Phrase |
|---|---|---|
type_change | Cassante | $.price : number → string |
prop_disparue | Cassante | $.items a disparu |
requis_absent | Cassante | $.items[].sku n'est plus toujours présent |
format_perdu | Cassante | $.created_at n'est plus une date-heure |
prop_nouvelle | Informative | $.currency : nouvelle propriété |
enum_nouvelle | Informative | $.status : nouvelle valeur "refunded" |
tableau_vide | Informative | $.items est vide |
Cassant : un client typé ne s'en relève pas. Informatif : rien ne casse, mais le contrat bouge. Les dérives informatives sont apprises en silence — la propriété nouvelle fait désormais partie du contrat et ne sera plus signalée. Le schéma continue donc de grandir avec l'API, et « cassant » garde le sens que vous attendez : quelque chose que votre code n'aurait pas prévu.
Régler
Projet → URLs → « Ajouter une URL » → sorte « Contrat d'API (JSON) ». Dans les Options avancées : le statut attendu et, pour une API privée, un en-tête (Authorization, X-Api-Key, X-Monitoring-Key ou X-Health-Token) envoyé à l'hôte d'origine seulement.
Sur le détail de l'URL, le panneau « Contrat d'API » montre : pendant l'apprentissage, « Apprentissage en cours : 2 passages sur 3. Rien n'est jugé avant. » ; ensuite, le schéma appris en clair (six niveaux affichés au plus), les dérives cassantes en rouge, les informatives en gris avec la mention « appris », et le nombre de passages d'apprentissage.
Le bouton « Réapprendre le contrat » efface le schéma. Après un changement d'API volontaire, c'est ce qu'on veut : trois passages plus tard, le nouveau contrat est la référence, sans avoir à le décrire.
Ce qui déclenche une alerte
| Code | Phrase |
|---|---|
statut:200:503 | L'API répond 503 au lieu de 200. |
json_invalide | La réponse n'est plus du JSON valide. |
contrat:type_change:$.price | Contrat d'API : $.price a changé de type. |
contrat:prop_disparue:$.items | Contrat d'API : $.items a disparu. |
contrat:requis_absent:$.items[].sku | Contrat d'API : $.items[].sku n'est plus toujours présent. |
contrat:format_perdu:$.created_at | Contrat d'API : $.created_at n'a plus le format attendu. |
L'alerte cite les deux premières dérives cassantes et compte les autres : « 3 changements cassants : $.price : number → string, $.items a disparu et 1 autre(s) ». Un code par dérive, stable d'un passage à l'autre : la même dérive n'alerte pas à chaque cycle, une dérive supplémentaire réalerte. Les dérives informatives n'alertent jamais. Un contrat en échec coûte 10 points au Ship Score.
Limites et plans
Disponible sur tous les plans ; une cible compte pour une URL du quota (Free 3, Pro 15, Team 50). Le rythme est celui du cycle — 30 minutes sur Free, 5 minutes sur Pro et Team — plus chaque déploiement, et l'apprentissage demande donc de 15 minutes à une heure et demie avant le premier verdict.
Dépannage
Pourquoi une propriété optionnelle est signalée « n'est plus toujours présent » ?
Parce qu'elle était présente dans les trois échantillons d'apprentissage : PostShip l'a apprise requise. Cliquez sur « Réapprendre le contrat » à un moment où la réponse la contient parfois, ou acceptez le verdict comme le signal qu'un client typé aurait eu.
Pourquoi le passage est en erreur plutôt qu'en échec ?
Une erreur veut dire que PostShip n'a pas pu juger : délai dépassé, réponse de plus de 512 Ko, boucle de redirection. Un échec est un verdict sur le contrat. Les deux ouvrent un incident, mais seule l'erreur dit « La réponse dépasse 512 Ko : trop grosse pour un contrat. ».
L'API répond du JSON mais avec Content-Type: text/html
Le type annoncé n'est pas vérifié : seul le corps compte. Si JSON.parse réussit, le contrat s'apprend.