Une API est un contrat. Traitez-la comme tel.
Votre API est la surface de contact entre votre système et le monde extérieur. Clients front, applications mobiles, partenaires, services internes — tous dépendent de vos endpoints.
Une API mal conçue coûte cher : documentation confuse, intégrations fragiles, breaking changes qui cassent les clients, support technique permanent. Une API bien conçue est un multiplicateur de valeur : adoption facile, évolution sereine, écosystème qui grandit.
Le design d’API n’est pas un exercice académique. C’est une discipline d’ingénierie qui impacte directement votre business.
API-First Design
Le principe
L’approche API-first place la conception de l’API avant l’implémentation. Au lieu de construire le backend puis d’exposer des endpoints qui reflètent votre modèle de données interne, vous concevez d’abord l’interface que vos consommateurs vont utiliser.
Pourquoi ça change tout
- Les consommateurs sont servis — l’API est conçue pour ceux qui l’utilisent, pas pour ceux qui l’implémentent
- Parallélisation du travail — front et back peuvent travailler en parallèle sur le contrat défini
- Feedback précoce — les problèmes de design sont détectés avant d’écrire une ligne de code
- Documentation native — le contrat d’API est la documentation
En pratique
- Rédigez la spécification OpenAPI (YAML/JSON) avec les stakeholders
- Reviewez le contrat avec les consommateurs (front, mobile, partenaires)
- Générez un mock server pour permettre aux clients de démarrer l’intégration
- Implémentez le backend conformément au contrat
- Validez la conformité avec des tests de contrat automatisés
REST : les fondamentaux bien appliqués
REST reste le standard dominant pour les APIs web. Mais la plupart des APIs “REST” ne respectent pas réellement les principes REST. Voici les pratiques qui font la différence.
Nommage des ressources
Les URLs représentent des ressources (noms), pas des actions (verbes).
Correct :
GET /orders— lister les commandesGET /orders/123— récupérer la commande 123POST /orders— créer une commandeGET /orders/123/items— lister les articles de la commande 123
Incorrect :
GET /getOrdersPOST /createOrderGET /getOrderItems?orderId=123
Utilisez le pluriel pour les collections (/orders, pas /order). Utilisez le kebab-case pour les noms composés (/order-items, pas /orderItems).
Verbes HTTP
Chaque verbe HTTP a une sémantique précise :
- GET — lecture, idempotent, cacheable
- POST — création, non idempotent
- PUT — remplacement complet d’une ressource, idempotent
- PATCH — modification partielle, idempotent
- DELETE — suppression, idempotent
Respectez ces sémantiques. Un GET ne doit jamais modifier l’état du serveur. Un PUT remplace la ressource entière, pas seulement un champ.
Codes de statut HTTP
Utilisez les codes HTTP standards pour communiquer le résultat :
- 200 OK — requête réussie (GET, PUT, PATCH)
- 201 Created — ressource créée (POST), avec header
Location - 204 No Content — succès sans corps de réponse (DELETE)
- 400 Bad Request — erreur de validation côté client
- 401 Unauthorized — authentification requise ou invalide
- 403 Forbidden — authentifié mais pas autorisé
- 404 Not Found — ressource inexistante
- 409 Conflict — conflit d’état (doublon, version obsolète)
- 422 Unprocessable Entity — données valides syntaxiquement mais sémantiquement incorrectes
- 429 Too Many Requests — rate limit dépassé
- 500 Internal Server Error — erreur serveur inattendue
Ne retournez pas un 200 avec un message d’erreur dans le body. Le code HTTP est le signal principal.
Pagination
Toute collection potentiellement large doit être paginée. Deux approches courantes :
Offset-based — GET /orders?page=3&limit=20. Simple, mais problématique sur les grandes collections (le SKIP SQL est lent) et instable si des éléments sont ajoutés/supprimés entre les pages.
Cursor-based — GET /orders?cursor=eyJpZCI6MTIzfQ&limit=20. Performant et stable. Le curseur encode la position du dernier élément retourné. Idéal pour les flux infinis (timeline, feed).
Incluez les métadonnées de pagination dans la réponse :
{
"data": [...],
"pagination": {
"total": 1247,
"limit": 20,
"nextCursor": "eyJpZCI6MTQzfQ"
}
}
Filtrage et tri
Fournissez des paramètres de query explicites :
- Filtrage —
GET /orders?status=pending&customerId=456 - Tri —
GET /orders?sort=-createdAt,+total(préfixe-pour descendant,+pour ascendant) - Recherche —
GET /orders?q=macbookpour une recherche textuelle simple - Champs sélectifs —
GET /orders?fields=id,status,totalpour réduire la taille de la réponse
Documentez chaque paramètre disponible. Un filtrage non documenté est un filtrage qui n’existe pas pour le consommateur.
Format des erreurs
Standardisez vos réponses d’erreur. Le format RFC 7807 (Problem Details) est une bonne base :
{
"type": "https://api.example.com/errors/validation",
"title": "Validation Error",
"status": 422,
"detail": "Le champ 'email' n'est pas un email valide",
"errors": [
{
"field": "email",
"message": "Format email invalide",
"code": "INVALID_FORMAT"
}
]
}
Des messages d’erreur clairs et actionnables réduisent le support technique de manière significative.
GraphQL : quand et pourquoi
Les forces de GraphQL
Flexibilité de requête — le client demande exactement les champs dont il a besoin. Pas de sur-fetching (données inutiles) ni de sous-fetching (données manquantes nécessitant des requêtes supplémentaires).
Un seul endpoint — une seule URL, un seul contrat. Le client compose ses requêtes comme il le souhaite.
Typage fort — le schéma GraphQL est auto-documenté et typé. Les outils comme GraphQL Playground offrent une exploration interactive.
Agrégation de données — une seule requête peut résoudre des données de sources multiples.
Quand privilégier GraphQL
- Clients multiples avec des besoins différents — mobile et web n’ont pas besoin des mêmes données
- Graphes de données complexes — relations imbriquées difficiles à servir efficacement en REST
- Évolution rapide du front — le front peut modifier ses requêtes sans changement backend
Quand REST reste préférable
- APIs publiques — REST est universellement compris, GraphQL nécessite un apprentissage
- Opérations simples (CRUD) — GraphQL ajoute de la complexité inutile
- Caching HTTP — REST exploite nativement le cache HTTP (CDN, navigateur), GraphQL nécessite des solutions spécifiques
- Uploads de fichiers — complexe en GraphQL, trivial en REST
GraphQL et REST ne sont pas mutuellement exclusifs. Beaucoup de systèmes utilisent REST pour les opérations simples et GraphQL pour les requêtes complexes.
Stratégies de versioning
Pourquoi versionner
Votre API va évoluer. Des champs seront ajoutés, supprimés, renommés. Sans stratégie de versioning, chaque changement casse potentiellement les clients existants.
URL versioning
GET /v1/orders vs GET /v2/orders
Avantages : explicite, facile à router, facile à documenter. Inconvénients : duplication de code entre versions, URLs qui changent.
C’est l’approche la plus courante et la plus simple. Utilisez-la par défaut.
Header versioning
GET /orders avec header Accept: application/vnd.api+json;version=2
Avantages : URLs stables, séparation propre entre routing et versioning. Inconvénients : moins visible, plus difficile à tester dans un navigateur.
Évolutive (additive changes)
La meilleure stratégie est d’éviter le versioning autant que possible en ne faisant que des changements additifs :
- Ajouter un champ : compatible
- Rendre un champ optionnel : compatible
- Ajouter un endpoint : compatible
- Supprimer un champ : breaking change
- Renommer un champ : breaking change
- Changer le type d’un champ : breaking change
Marquez les champs à supprimer comme deprecated pendant 6-12 mois avant de les retirer. Communiquez les timelines de dépréciation.
Authentification et sécurité
OAuth 2.0 et OpenID Connect
Pour les APIs exposées à des clients tiers, OAuth 2.0 est le standard. Le flux Authorization Code avec PKCE est recommandé pour les applications web et mobiles.
OpenID Connect (OIDC) ajoute une couche d’identité au-dessus d’OAuth. Utilisez-le quand vous avez besoin d’informations sur l’utilisateur connecté.
API Keys
Pour les intégrations serveur-à-serveur simples, les API keys suffisent. Mais elles ne doivent jamais transiter côté client (navigateur, app mobile) car elles sont facilement extractibles.
Bonnes pratiques pour les API keys :
- Rotation régulière (tous les 90 jours)
- Scoping par permission (lecture seule, écriture, admin)
- Rate limiting par clé
- Révocation instantanée possible
JWT : avantages et pièges
Les JSON Web Tokens sont omniprésents mais souvent mal utilisés :
- Durée de vie courte (15 minutes max) avec refresh token à plus longue durée
- Ne stockez rien de sensible dans le payload (il est encodé, pas chiffré)
- Vérifiez la signature côté serveur à chaque requête
- Utilisez un algorithme asymétrique (RS256) pour les systèmes distribués
Rate Limiting
Pourquoi c’est non négociable
Sans rate limiting, un client mal codé ou malveillant peut saturer votre API et impacter tous les autres utilisateurs.
Implémentation
Appliquez des limites par :
- IP — protection basique contre les abus
- API key/utilisateur — limites par consommateur identifié
- Endpoint — limites différentes selon la lourdeur de l’opération
Retournez les informations de rate limit dans les headers de réponse :
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1678886400
Le code 429 Too Many Requests signale le dépassement avec un header Retry-After.
Stratégies avancées
- Sliding window — plus précis que le fixed window pour les pics de trafic
- Token bucket — permet des bursts contrôlés tout en limitant le débit moyen
- Tiering — des limites différentes par niveau de souscription (free, pro, enterprise)
Documentation
OpenAPI (Swagger)
La spécification OpenAPI est le standard de documentation des APIs REST. Elle décrit les endpoints, les paramètres, les schémas de données et les exemples dans un format machine-readable.
Outils essentiels :
- Swagger UI ou Redoc pour générer une documentation interactive
- Swagger Editor pour rédiger et valider la spec
- Prism (Stoplight) pour mocker l’API depuis la spec
Documentation comme code
Versionnez votre documentation OpenAPI avec votre code. Chaque PR qui modifie un endpoint doit mettre à jour la spec correspondante. Automatisez la validation de conformité dans le pipeline CI.
Exemples concrets
Chaque endpoint doit inclure des exemples de requête et de réponse réalistes. Pas des données génériques (foo, bar, test123) mais des données vraisemblables qui illustrent le cas d’usage.
Les exemples sont la première chose que les développeurs regardent. Ils doivent être fonctionnels et copiables.
Testing d’API
Tests de contrat
Les contract tests vérifient que le producteur et le consommateur s’accordent sur le format des échanges. Pact est l’outil de référence : le consommateur définit ses attentes, le producteur vérifie qu’il les satisfait.
Tests d’intégration
Testez chaque endpoint avec des scénarios réalistes :
- Happy path (cas nominal)
- Validation des inputs (données invalides, champs manquants)
- Authentification et autorisation (401, 403)
- Cas limites (pagination vide, ressource inexistante)
- Concurrence (créations simultanées, conflits)
Tests de performance
Mesurez la latence P50, P95 et P99 de chaque endpoint critique. Définissez des SLOs de latence et alertez quand ils sont dépassés. Utilisez des outils comme k6 ou Artillery pour les tests de charge.
Backward Compatibility
La règle d’or
Ne cassez jamais un client existant. Chaque changement d’API doit être backward compatible par défaut. Les breaking changes sont exceptionnels et gérés via le versioning.
Deprecation policy
Publiez une politique de dépréciation claire :
- Le champ/endpoint est marqué
deprecateddans la spec et la documentation - Un avertissement est retourné dans les headers de réponse
- Les consommateurs sont notifiés (changelog, email, dashboard)
- Après la période de dépréciation (6-12 mois minimum), le champ/endpoint est retiré
Consumer-driven contracts
Utilisez des contract tests pour détecter les breaking changes avant le déploiement. Si un changement backend casse un test de contrat, le pipeline CI échoue et le développeur est alerté immédiatement.
Notre approche
Chez Les Artisans du Digital, le design d’API est une étape fondamentale de chaque projet. On commence par un atelier API-first avec les stakeholders (front, mobile, partenaires), on rédige la spec OpenAPI, on la review, puis on implémente.
Nos APIs sont documentées, testées, versionnées et monitorées. Parce qu’une API est un produit — et un produit se conçoit avec soin.
FAQ
REST ou GraphQL pour un nouveau projet ?
Pour la majorité des projets, REST est le meilleur point de départ : universellement compris, excellent support de caching, outils matures. Optez pour GraphQL si vous avez des clients multiples avec des besoins de données très différents (web riche vs mobile minimal), ou si votre domaine implique des requêtes sur des graphes de données complexes et imbriquées. Dans le doute, commencez par REST. Migrer un endpoint REST vers GraphQL est plus simple que l’inverse.
Comment gérer les breaking changes sur une API publique ?
Suivez une politique de dépréciation stricte. Annoncez le changement 6 à 12 mois à l’avance. Fournissez la nouvelle version en parallèle de l’ancienne. Monitorez l’utilisation de l’ancienne version pour identifier les clients qui n’ont pas migré et contactez-les directement. Ne retirez l’ancienne version que quand le trafic est proche de zéro. Les breaking changes sont un dernier recours, pas une pratique courante.
Faut-il documenter les APIs internes aussi rigoureusement que les APIs publiques ?
Oui, mais avec des outils adaptés. Les APIs internes deviennent les APIs publiques de demain. Une documentation légère mais présente (spec OpenAPI auto-générée, exemples dans le code, contract tests) est le minimum. Les outils comme tRPC pour le TypeScript fullstack ou gRPC avec protobuf génèrent la documentation automatiquement depuis le code. L’investissement est minimal et la valeur en onboarding et maintenance est significative.
Quel est le bon niveau de rate limiting pour une API ?
Il n’y a pas de valeur universelle. Analysez les patterns d’usage réels de vos consommateurs. Un endpoint de lecture légère (profil utilisateur) peut supporter 1000 requêtes par minute. Un endpoint d’écriture lourd (génération de rapport) sera limité à 10 par minute. Commencez avec des limites généreuses, monitorez les patterns, et ajustez. Fournissez toujours les headers de rate limit dans les réponses pour que les consommateurs puissent adapter leur comportement.