Aller au contenu principal

Concevoir une API REST maintenable

Photo d'Emmanuel BALLERY, fondateur de x10
Emmanuel BALLERY
CTO freelance & Architecte logiciel
calendar_today 28/03/2026
schedule 15 min lecture
Un schéma représente l'architecture d'une API REST avec ses endpoints et ses ressources

Une API REST, c'est du code qui sera consommé par d'autres développeurs, d'autres équipes, d'autres systèmes. Contrairement à une interface graphique que l'on peut ajuster au fil de l'eau, une API engage. Chaque endpoint publié est une promesse. Et chaque modification non rétrocompatible est une promesse rompue.

Pourtant, la majorité des API naissent dans l'urgence. On expose quelques routes, on documente à minima, on itère. Jusqu'au jour où la dette de conception rend toute évolution coûteuse. Cet article pose les principes qui font durer une API REST, au-delà du premier sprint.

Une API, c'est un contrat

Quand vous publiez un endpoint, vous signez un contrat avec tous les consommateurs qui vont l'intégrer. Applications mobiles, partenaires, front-ends internes, scripts d'automatisation… Chacun s'appuie sur la structure de vos réponses, vos codes HTTP, vos conventions de nommage.

Le coût d'un breaking change est rarement mesuré à l'avance. Il ne s'agit pas seulement de modifier votre code. Il faut coordonner la mise à jour de chaque consommateur, gérer la période de transition, maintenir l'ancienne version le temps que tout le monde migre. Sur une API publique, c'est un projet en soi. Sur une API interne avec dix consommateurs, c'est déjà une source de friction considérable.

C'est pourquoi la conception initiale mérite un investissement sérieux. Non pas pour tout prévoir, mais pour poser des fondations suffisamment solides pour absorber les évolutions sans casser l'existant. Les décisions prises dans les premières semaines — nommage, structure des ressources, gestion des erreurs — vous accompagneront pendant des années.

Conventions de nommage

Les conventions de nommage sont le premier signal de qualité d'une API. Un consommateur qui découvre vos endpoints doit pouvoir deviner la structure sans lire la documentation.

Ressources au pluriel

Les URLs désignent des ressources, pas des actions. Utilisez le pluriel pour les collections : /users, /orders, /products. Un élément individuel est identifié par son ID : /users/42. C'est simple, prévisible et universel.

Kebab-case pour les URLs

Les URLs utilisent le kebab-case : /order-items plutôt que /orderItems ou /order_items. Les URLs sont case-insensitive par convention, et le kebab-case est le standard du web.

Hiérarchie logique

La structure des URLs reflète les relations entre ressources. Un utilisateur possède des commandes : /users/{id}/orders. Une commande contient des lignes : /orders/{id}/items. Limitez-vous à deux niveaux d'imbrication maximum. Au-delà, l'URL devient illisible et le routage pénible à maintenir.

Les verbes HTTP, pas dans l'URL

C'est le verbe HTTP qui exprime l'action, pas l'URL. POST /users crée un utilisateur. GET /users/42 le récupère. DELETE /users/42 le supprime. Bannissez les /createUser, /deleteOrder et autres /getProductList.

Versioning

Le versioning est le filet de sécurité qui permet de faire évoluer une API sans casser les consommateurs existants. Encore faut-il choisir la bonne stratégie.

URL path vs header

Deux approches dominent. Le versioning par URL path (/v1/users) est explicite, simple à comprendre et facile à router. Le versioning par header (Accept-Version: v2) garde des URLs propres mais complexifie le routage et le debugging.

En pratique, le versioning par URL path est le plus répandu et le plus pragmatique. Réservez le versioning par header aux cas où la pureté des URLs est une contrainte forte, typiquement les API publiques à très large audience.

Quand versionner

Ne versionnez pas à chaque modification. Un nouveau champ dans une réponse n'est pas un breaking change. La suppression d'un champ, le changement de type d'un champ, la modification d'un code de retour : ça, c'est un breaking change.

La règle : tout ce qui peut faire échouer un consommateur existant sans modification de son code justifie une nouvelle version. Tout le reste est une évolution backward-compatible.

Pagination et filtrage

Toute collection de plus de quelques dizaines d'éléments doit être paginée. Sans pagination, un GET /users sur une base de 100 000 utilisateurs met votre serveur à genoux et votre consommateur en timeout.

Cursor vs offset

La pagination par offset (?page=3&limit=20) est intuitive mais fragile. Si un élément est ajouté ou supprimé entre deux pages, des résultats sont dupliqués ou manquants. La pagination par cursor (?after=eyJpZCI6NDJ9&limit=20) résout ce problème en s'appuyant sur un marqueur stable.

Privilégiez le cursor pour les collections qui changent fréquemment. L'offset reste acceptable pour les collections stables ou les cas d'usage qui nécessitent un accès direct à une page donnée.

Filtrage et tri

Le filtrage passe par les query parameters : /orders?status=pending&created_after=2024-01-01. Le tri également : /orders?sort=created_at&order=desc. Documentez les filtres disponibles. Un filtre non documenté est un filtre qui n'existe pas pour vos consommateurs.

Le total count est un sujet sous-estimé. Compter le nombre total d'éléments peut être extrêmement coûteux sur de grandes tables. Rendez-le optionnel via un header ou un paramètre (?include_total=true) et mettez en cache le résultat quand c'est possible.

Gestion d'erreurs standardisée

La gestion d'erreurs est ce qui sépare une API agréable d'une API pénible. Quand quelque chose échoue, le consommateur a besoin de trois informations : quoi (quel type d'erreur), (quel champ, quelle ressource) et comment (que faire pour corriger).

RFC 7807 Problem Details

La RFC 7807 (devenue RFC 9457) définit un format standard pour les erreurs HTTP. Un objet JSON avec les champs type, title, status, detail et instance. C'est le format adopté par API Platform et de nombreux frameworks. L'adopter, c'est offrir à vos consommateurs une structure prévisible pour parser et afficher les erreurs.

Codes HTTP cohérents

Utilisez les codes HTTP pour ce qu'ils signifient. 400 pour une requête malformée. 401 pour un problème d'authentification. 403 pour un problème d'autorisation. 404 pour une ressource inexistante. 409 pour un conflit. 422 pour une validation métier échouée. 429 pour un rate limit dépassé. 500 pour une erreur serveur.

Et surtout : jamais de réponse 200 avec un body d'erreur. C'est le piège le plus courant et le plus destructeur. Un consommateur qui filtre sur le code HTTP ne verra jamais l'erreur. Un monitoring basé sur les codes de retour sera aveugle. C'est une bombe à retardement.

Documentation comme produit

Une API sans documentation n'est pas une API. C'est une boîte noire que personne n'ose toucher. La documentation doit être traitée comme un produit à part entière, avec le même soin que le code.

OpenAPI et génération automatique

Le standard OpenAPI (ex-Swagger) permet de décrire votre API dans un format machine-readable. À partir de cette spécification, des outils génèrent la documentation interactive, les clients SDK, les mocks et les tests.

En PHP, API Platform génère la spécification OpenAPI automatiquement à partir de vos entités et ressources. C'est un gain de temps considérable et une garantie que la documentation reste synchronisée avec le code.

Exemples et sandbox

Une documentation sans exemples est une documentation incomplète. Chaque endpoint doit montrer un exemple de requête et de réponse, avec des données réalistes. Mieux encore : proposez un environnement sandbox où les consommateurs peuvent tester les appels sans impacter les données de production.

Sécurité

La sécurité d'une API ne se limite pas à l'authentification. C'est un ensemble de couches qui protègent vos données et vos systèmes contre les usages malveillants.

Authentification et autorisation

OAuth2 est le standard pour les API qui exposent des données utilisateur. Les API keys suffisent pour les intégrations machine-to-machine simples. Dans tous les cas, ne réinventez pas la roue. Utilisez des bibliothèques éprouvées et des tokens à durée de vie limitée.

Rate limiting

Le rate limiting protège votre API contre les abus, qu'ils soient intentionnels (attaque DDoS) ou accidentels (boucle infinie chez un consommateur). Retournez un 429 avec un header Retry-After pour indiquer quand le consommateur peut réessayer.

CORS et validation des entrées

Configurez le CORS strictement. N'autorisez que les origines légitimes. Validez toutes les entrées, y compris les query parameters et les headers. Une API qui fait confiance aux données entrantes est une API vulnérable.

Le HTTPS est non négociable. Toute API servie en HTTP est un vecteur d'interception. Redirigez systématiquement le trafic HTTP vers HTTPS et activez HSTS.

Performance

Une API lente est une API abandonnée. La performance se travaille à plusieurs niveaux, du cache HTTP jusqu'à la structure des réponses.

Cache HTTP

Les headers ETag et Last-Modified permettent aux consommateurs de valider leur cache sans retélécharger les données. Quand un GET retourne un 304 Not Modified, c'est du temps de transfert et du calcul serveur économisés. Sur une API à fort trafic, l'impact est significatif.

Compression et champs sparse

Activez la compression gzip sur toutes les réponses JSON. Proposez des champs sparse (/users?fields=name,email) pour que les consommateurs ne récupèrent que les données dont ils ont besoin. Moins de données transférées, moins de sérialisation, moins de charge réseau.

Le piège du N+1

Les endpoints qui retournent des ressources avec des relations imbriquées sont un terrain fertile pour le problème N+1. Un GET /orders?include=items,customer qui exécute une requête par commande pour charger les items va exploser en temps de réponse dès que la collection grossit.

La solution : eager loading côté serveur, avec des jointures optimisées. Et surtout, mesurez. Un endpoint qui répond en 50 ms sur 10 résultats peut répondre en 5 secondes sur 100 si les includes ne sont pas optimisés.

Concevoir pour durer

Une API REST maintenable n'est pas une API sur-conçue. C'est une API dont les conventions sont claires, les erreurs exploitables, la documentation à jour et la sécurité non négociable. Ces principes ne demandent pas plus de temps de développement. Ils demandent plus de réflexion en amont, pour éviter des mois de correction en aval.

Chez x10, nous concevons des API REST pensées pour durer, avec API Platform, une documentation générée automatiquement et des conventions qui tiennent la charge. Besoin d'un accompagnement sur votre développement sur mesure ou votre architecture applicative ? Parlons-en.

Photo d'Emmanuel BALLERY, fondateur de x10

À propos de l'auteur

Emmanuel BALLERY est le fondateur de x10. Expert en architecture logicielle et passionné par la qualité du code (Software Craftsmanship), il aide les entreprises à transformer leur dette technique en actifs durables.

Voir plus arrow_forward