La plupart des bugs d'API ne viennent pas d'une erreur de code, mais d'un désaccord de contrat. Le frontend attend userId, le backend renvoie user_id, et l'écart n'est détecté qu'en QA. Le développement d'API spec-first évite ce problème en faisant de la spécification OpenAPI le premier artefact du projet, avant le code serveur.
Dans ce guide, vous allez rédiger une petite spécification OpenAPI, puis l'utiliser pour générer des mocks, préparer des tests de contrat et produire une documentation API avant même que le backend soit implémenté. Cette approche est aussi appelée design-first, contract-first ou développement piloté par les spécifications. Le principe reste le même : définir l'interface, la valider, puis construire.
Qu'est-ce que le développement d'API spec-first ?
Le développement d'API spec-first consiste à écrire un contrat lisible par machine, généralement un fichier OpenAPI, avant d'implémenter les endpoints. Ce contrat décrit :
- les chemins ;
- les méthodes HTTP ;
- les paramètres ;
- les corps de requête ;
- les schémas de réponse ;
- les codes de statut ;
- les erreurs attendues.
La spécification n'est donc pas une documentation écrite après coup. Elle devient la source de vérité du projet.
Concrètement :
- le frontend consomme un serveur mock généré depuis la spec ;
- l'équipe QA prépare des tests à partir des schémas ;
- le backend implémente les endpoints pour respecter le contrat ;
- la documentation est générée depuis le même fichier.
Dans une approche code-first, vous écrivez les handlers, puis vous documentez l'API ensuite. La documentation finit souvent par diverger du code. Dans une approche spec-first, vous inversez l'ordre : le contrat est écrit, relu et validé avant l'implémentation.
Cycle de vie spec-first vs code-first
Les deux approches peuvent produire les mêmes endpoints. La différence principale est le moment où les problèmes apparaissent.
Avec une approche spec-first, les équipes peuvent travailler en parallèle dès que le contrat est validé. Le frontend n'attend pas le backend, la QA n'attend pas une version stable, et la documentation ne dépend pas d'une rédaction manuelle en fin de sprint.
Exemple pratique : créer une spec OpenAPI pour /users
Construisons une API simple avec deux opérations :
-
GET /userspour lister les utilisateurs ; -
POST /userspour créer un utilisateur.
1. Déclarer les métadonnées OpenAPI
Commencez par l'en-tête du document :
openapi: 3.0.3
info:
title: Users API
version: 1.0.0
servers:
- url: https://api.example.com/v1
Cette partie indique :
- la version OpenAPI utilisée ;
- le nom de l'API ;
- la version du contrat ;
- l'URL de base du serveur.
2. Définir le schéma User
Placez les modèles réutilisables dans components/schemas.
components:
schemas:
User:
type: object
required:
- id
- email
- createdAt
properties:
id:
type: string
format: uuid
email:
type: string
format: email
name:
type: string
createdAt:
type: string
format: date-time
Ce schéma impose que chaque utilisateur possède :
- un
idau format UUID ; - un
emailvalide ; - une date
createdAt; - un champ optionnel
name.
L'avantage de components/schemas est la réutilisation. Vous définissez User une seule fois, puis vous le référencez dans plusieurs endpoints avec $ref.
3. Définir GET /users
Ajoutez ensuite l'opération de lecture.
paths:
/users:
get:
summary: List users
operationId: listUsers
parameters:
- name: limit
in: query
schema:
type: integer
default: 20
maximum: 100
responses:
"200":
description: A list of users
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/User"
Ce contrat indique que :
-
limitest un paramètre de query string ; - sa valeur par défaut est
20; - sa valeur maximale est
100; - la réponse
200renvoie un tableau d'objetsUser.
Un client peut donc appeler :
GET /users?limit=10
Et attendre une réponse de ce type :
[
{
"id": "3f8f3c5e-4d3e-4b22-9d3a-7c9e77f7d8f1",
"email": "alice@example.com",
"name": "Alice",
"createdAt": "2026-06-01T10:00:00Z"
}
]
4. Définir POST /users
Ajoutez maintenant l'opération de création.
paths:
/users:
post:
summary: Create a user
operationId: createUser
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- email
properties:
email:
type: string
format: email
name:
type: string
responses:
"201":
description: User created
content:
application/json:
schema:
$ref: "#/components/schemas/User"
"400":
description: Invalid request body
Le corps de requête attendu est minimal :
{
"email": "alice@example.com",
"name": "Alice"
}
Le champ email est obligatoire. Si le client l'omet, l'API doit pouvoir répondre avec 400.
5. Assembler la spécification complète
Voici le fichier complet :
openapi: 3.0.3
info:
title: Users API
version: 1.0.0
servers:
- url: https://api.example.com/v1
paths:
/users:
get:
summary: List users
operationId: listUsers
parameters:
- name: limit
in: query
schema:
type: integer
default: 20
maximum: 100
responses:
"200":
description: A list of users
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/User"
post:
summary: Create a user
operationId: createUser
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- email
properties:
email:
type: string
format: email
name:
type: string
responses:
"201":
description: User created
content:
application/json:
schema:
$ref: "#/components/schemas/User"
"400":
description: Invalid request body
components:
schemas:
User:
type: object
required:
- id
- email
- createdAt
properties:
id:
type: string
format: uuid
email:
type: string
format: email
name:
type: string
createdAt:
type: string
format: date-time
À ce stade, aucun code serveur n'existe encore. Pourtant, vous avez déjà défini :
- les endpoints disponibles ;
- les entrées acceptées ;
- les réponses attendues ;
- les champs obligatoires ;
- les formats de données ;
- les erreurs de validation.
C'est ce contrat qui va piloter la suite.
Générer des mocks, des tests et de la documentation
L'intérêt du spec-first est de produire plusieurs artefacts à partir d'un seul fichier.
1. Générer un serveur mock
Un serveur mock lit la spécification OpenAPI et retourne des réponses conformes aux schémas.
Pour GET /users, le mock peut renvoyer un tableau d'utilisateurs respectant User. Les formats comme uuid, email et date-time aident les outils à générer des données réalistes.
Résultat : le frontend peut commencer à intégrer l'API immédiatement.
Exemple d'appel côté client :
const response = await fetch("https://mock.example.com/users?limit=10");
const users = await response.json();
console.log(users);
Le backend réel n'est pas encore disponible, mais l'interface est déjà testable.
2. Écrire des tests de contrat
La spécification sert aussi d'oracle de test. Les tests ne vérifient pas seulement que l'API répond. Ils vérifient qu'elle respecte le contrat.
Pour POST /users, les assertions principales sont :
- une requête valide retourne
201; - la réponse respecte le schéma
User; - une requête sans
emailretourne400.
Exemple de logique de test :
import assert from "node:assert";
const response = await fetch("https://api.example.com/v1/users", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
email: "alice@example.com",
name: "Alice"
})
});
assert.strictEqual(response.status, 201);
const body = await response.json();
assert.ok(body.id);
assert.ok(body.email);
assert.ok(body.createdAt);
Dans un pipeline CI, ces tests permettent de détecter rapidement une divergence entre la spec et l'implémentation.
3. Générer la documentation API
La documentation de référence peut être générée directement depuis le fichier OpenAPI.
Cela évite de maintenir séparément :
- le code ;
- les tests ;
- les mocks ;
- la documentation.
Chaque endpoint, paramètre, schéma et code de statut vient de la même source.
C'est aussi ce qui rend l'approche compatible avec un flux de travail API natif Git : la spécification est un fichier texte, versionné, relu et validé dans les pull requests.
Un reviewer peut voir dans un diff qu'un champ obligatoire a été supprimé ou qu'un paramètre a été renommé avant que le changement atteigne la production.
Le faire dans Apidog
Apidog prend en charge ce workflow via le mode Spec-First. Au lieu de traiter OpenAPI comme une simple exportation, Apidog utilise la spécification comme base du projet.
Le workflow est le suivant :
- créez ou importez votre fichier OpenAPI ;
- éditez directement le YAML ;
- laissez Apidog générer les mocks ;
- partagez la documentation générée ;
- exécutez les opérations comme cas de test ;
- synchronisez la spec avec Git.
Pour l'exemple /users, vous pouvez coller la spécification dans l'éditeur. Apidog analyse les opérations GET /users et POST /users, puis met en place un serveur mock correspondant. Le frontend peut alors commencer à appeler ces endpoints sans attendre le backend.
Lorsque l'implémentation réelle est prête, vous pouvez exécuter les cas issus de la spécification contre le serveur backend et vérifier que les réponses correspondent aux schémas déclarés.
La synchronisation Git bidirectionnelle permet de garder le contrat au même endroit logique : le dépôt. Si vous modifiez le YAML dans votre éditeur et poussez le changement, Apidog le récupère. Si vous modifiez la spec dans Apidog, le changement peut apparaître comme un commit à relire.
Pour une comparaison plus détaillée, consultez spec-first vs design-first dans Apidog.
Checklist spec-first avant implémentation
Avant de démarrer le développement backend, vérifiez les points suivants :
- [ ] La spécification est valide selon le schéma OpenAPI.
- [ ] Chaque endpoint possède au moins une réponse de succès.
- [ ] Chaque endpoint déclare au moins une réponse d'erreur.
- [ ] Les schémas partagés sont placés dans
components/schemas. - [ ] Les schémas réutilisés sont référencés avec
$ref. - [ ] Les champs obligatoires sont marqués avec
required. - [ ] Les formats utiles sont définis :
uuid,email,date-time, etc. - [ ] Les paramètres de query, path et header sont explicitement décrits.
- [ ] La spec est versionnée dans Git.
- [ ] Les changements de contrat passent par une pull request.
- [ ] Un serveur mock est généré depuis la spec.
- [ ] Le frontend peut consommer le mock.
- [ ] Les tests de contrat comparent les réponses réelles à la spec.
- [ ] La documentation publiée est générée depuis le même fichier.
Si cette checklist est validée, les équipes peuvent avancer en parallèle sur un contrat commun au lieu de travailler à partir d'hypothèses différentes.
FAQ
Le développement d'API spec-first est-il la même chose que le design-first ?
Oui, dans la plupart des cas. Les termes design-first, contract-first et spec-first décrivent le même principe : définir l'interface avant l'implémentation.
Le terme spec-first insiste sur l'artefact concret utilisé au départ : un fichier de spécification OpenAPI.
Dois-je écrire le YAML à la main ?
Non. Vous pouvez utiliser un éditeur visuel ou écrire le YAML directement. L'important est que le contrat soit défini et accepté avant le code.
Beaucoup d'équipes combinent les deux : conception visuelle pour aller vite, puis relecture du YAML dans Git pour valider les détails.
Comment éviter que la spécification et le code divergent ?
Faites de la spécification la source de vérité.
En pratique :
- gardez le fichier OpenAPI dans Git ;
- relisez chaque changement dans une pull request ;
- générez les mocks et la documentation depuis ce fichier ;
- exécutez des tests de contrat en CI ;
- faites échouer le pipeline si une réponse ne respecte plus le schéma.
Avec ce workflow, une divergence devient visible dès le développement, pas en QA ou en production.
Le développement d'API spec-first est un changement simple : écrire le contrat avant le code. Mais ce changement réduit fortement les erreurs d'intégration. Commencez par une spécification OpenAPI minimale, générez vos mocks, validez vos tests de contrat, puis implémentez le backend pour satisfaire le contrat.
Si vous voulez tester le cycle complet, ouvrez le mode Spec-First dans Apidog et connectez-le à votre dépôt Git.


Top comments (0)