Détectez la dérive de schéma d'API avant vos tests
Un test qui vérifie le code de statut et quelques champs continue de réussir lorsque l'API ajoute un champ, en supprime un que vous n'affirmez pas ou transforme un nombre en chaîne de caractères. Nexus Studio enregistre la structure de chaque réponse d'API, les noms de champs et les types sans jamais stocker les valeurs, la compare avec l'exécution précédente et signale API_DRIFTED lorsqu'elle change. Avec NEXUS_API_DRIFT_STRICT=true, cette même modification fait échouer la suite.
Par l'équipe Nexus Studio, Verdict System LLC. 27 octobre 2026.
Qu'est-ce que la dérive de schéma d'API ?
La dérive de schéma correspond au changement de structure d'une réponse entre deux exécutions : un champ ajouté, un champ supprimé ou un champ dont le type a changé. Une API a le droit d'évoluer. Le problème survient lorsque ses consommateurs s'en aperçoivent en production, car aucun élément de la suite de tests n'a signalé ce changement.
Pourquoi un test de contrat réussi ne la détecte-t-il pas ?
Parce qu'il n'affirme que ce à quoi son auteur a pensé. Une règle telle que validate(res, { status: 200, hasFields: ['id'] }) continue de réussir lorsque price passe d'un nombre à une chaîne de caractères, puisque price n'est pas inclus dans la règle. C'est le client qui effectue la somme des prix qui s'arrête de fonctionner.
Puis-je voir cela se produire sur un exemple exécutable ?
Enregistrez ceci sous le nom server.mjs. Il répond à un point de terminaison, et la variable SHAPE détermine ce que renvoie le point de terminaison : un prix sous forme de nombre, ou un prix sous forme de chaîne de caractères avec un nouveau champ currency.
import http from 'node:http';
// SHAPE=v1 answers {id, price: 9.99}; SHAPE=v2 answers {id, price: "9.99", currency: "USD"}.
const v2 = process.env.SHAPE === 'v2';
http.createServer((req, res) => {
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(v2 ? { id: 7, price: '9.99', currency: 'USD' } : { id: 7, price: 9.99 }));
}).listen(4010, '127.0.0.1');
Enregistrez ce test d'API sous le nom APIT900_drift_demo.api.js dans le dossier api-tests/rest de votre espace de travail. Il valide le statut et un champ, comme le font de nombreuses suites réelles.
// type: rest
import { runApiSuite } from '../../utils/base-api-fixture.js';
await runApiSuite([{
id: 'APIT900-1',
name: 'GET /product/7 returns 200 with an id',
fn: async ({ request, validate }) => {
const res = await request({ method: 'GET', url: '/product/7' });
validate(res, { status: 200, hasFields: ['id'] });
},
}]);
Démarrez le serveur dans une fenêtre PowerShell et exécutez le test dans une autre. La première exécution n'a aucun élément de comparaison : elle enregistre donc la structure et réussit.
$env:SHAPE = "v1"; node server.mjs
$env:API_BASE_URL = "http://127.0.0.1:4010"; nexus api APIT900 --no-app
Arrêtez le serveur, redémarrez-le avec $env:SHAPE = "v2" et exécutez le même test. Il réussit toujours, mais l'exécution n'est plus API_SECURE. Voici la sortie, raccourcie aux lignes importantes :
schema drift: +1 field, 1 type change
+ currency
~ price: number → string
API_DRIFTED 7ms
1/1 passed
1 endpoint changed shape since the last run, set NEXUS_API_DRIFT_STRICT=true to fail the suite on it
Une dérive peut-elle faire échouer le build ?
Oui, sur demande. Par défaut, API_DRIFTED est considéré comme un succès et renvoie le code de sortie 0, car l'évolution de l'API constitue une information et non un défaut. Elle est affichée sur sa propre ligne et consignée avec la différence dans les preuves de l'exécution, de sorte qu'elle n'est jamais interprétée comme une réussite parfaite. Définissez NEXUS_API_DRIFT_STRICT=true et cette même modification renverra le code de sortie 1. Pour le constater, exécutez le test une fois sur v1 et une fois sur v2 avec cette variable définie.
La référence correspond toujours à l'exécution précédente. Après une exécution ayant dérivé, la nouvelle structure devient la référence, de sorte que l'exécution suivante sur la même réponse ne signale aucune dérive.
Quelles sont les limites ?
- La première exécution d'un test enregistre uniquement une structure. Il n'y a encore aucun élément par rapport auquel dériver.
- La structure concerne les noms et les types, pas la sémantique. Si
pricereste un nombre mais passe des dollars aux centimes, rien ne change. - La comparaison s'effectue avec l'exécution précédente, et non avec un contrat convenu au préalable. Elle vous indique que quelque chose a changé, pas si ce changement était autorisé.
- Chaque cas de test conserve une seule structure, issue du corps de sa dernière requête. Une liste est décrite par son premier élément, un objet par un maximum de 200 clés, et l'imbrication s'arrête à six niveaux.
Où puis-je le constater ?
Le guide des verdicts détaille les verdicts de test, et la page Preuves répertorie les fichiers qu'une exécution laisse sur votre disque. L'essai de 30 jours exécute le même moteur sur vos propres tests d'API.