
Lorsque l'on parle de REST, il est intéressant de lire la thèse de Roy Thomas Fielding. L'article original qui décrit le web RESTful, « Architectural Styles and the Design of Network-based Software Architectures » de Roy T. Fielding (2000), présente le style architectural Representational State Transfer (REST) comme un cadre pour la conception de systèmes en réseau évolutifs, performants et faciles à maintenir, en particulier les services web.
Cet article vise à analyser les styles architecturaux des systèmes en réseau, en identifiant leurs forces et leurs faiblesses. Il définit REST comme un style architectural spécifique optimisé pour le web moderne, axé sur l'évolutivité, la simplicité et l'adaptabilité.
Fielding démontre comment les principes REST contribuent au succès du web, en préconisant leur adoption dans la conception de systèmes distribués avec des interfaces universelles et sans état et des interactions claires basées sur les ressources.
Dans sa thèse, il ne prescrit pas l'utilisation spécifique des verbes HTTP (tels que GET, POST, PUT, DELETE) et ne se concentre pas sur les API de type CRUD, comme c'est souvent le cas aujourd'hui avec la mise en œuvre de REST.
La thèse décrit clairement REST comme un style architectural qui fournit des principes et des contraintes pour la création d'applications en réseau, en utilisant le web comme exemple fondamental.
Roy Fielding a explicitement critiqué la simplification excessive de REST dans les API de type CRUD, soulignant que de nombreuses API dites « RESTful » ne parviennent pas à mettre en œuvre les contraintes clés de REST, en particulier l'utilisation de l'hypermédia pour piloter les transitions d'état des applications. Dans son article de blog de 2008, « Les API REST doivent être pilotées par l'hypertexte », Fielding déclare :
« Si le moteur de l'état de l'application (et donc l'API) n'est pas piloté par l'hypertexte, alors il ne peut pas être RESTful et ne peut pas être une API REST. Point final. »
Voici quelques idées fausses courantes concernant ce que les gens considèrent comme REST :
- REST est CRUD (c'est souvent le cas, mais pas toujours)
- Une ressource est une entité (souvent une entité persistante).
- Une API RESTful ne doit pas utiliser de verbes.
Mais il s'agit en réalité de décisions de conception prises pour l'API en question, choisies par leurs créateurs et qui n'ont rien à voir avec REST.
Que signifie « piloté par l'hypertexte » ?
L'expression « non piloté par l'hypertexte » dans la critique de Roy Fielding fait référence à l'absence de l'hypermédia comme moteur de l'état de l'application (HATEOAS) dans de nombreuses API qui se prétendent RESTful. HATEOAS est un principe fondamental de REST, qui exige que le client découvre dynamiquement les actions et les interactions grâce à des liens hypermédia intégrés dans les réponses du serveur, plutôt que de s'appuyer sur des connaissances hors bande (par exemple, la documentation de l'API).
Code : | Sélectionner tout |
1 2 3 4 5 6 7 | { "orderId": 123, "_links": { "self": { "href": "/orders/123" }, "cancel": { "href": "/orders/123/cancel", "method": "POST" } } } |
Le problème central qu'il aborde est le couplage client-serveur. Il existe probablement d'innombrables projets dans lesquels une petite modification de la structure URI d'un serveur a nécessité un déploiement coordonné (et souvent pénible) de plusieurs applications clientes. Une approche basée sur HATEOAS résout directement ce problème en découplant le client de l'espace de noms du serveur. Cela permet d'améliorer la qualité de l'évolutivité.
La simple mise en œuvre de HATEOAS vous rapprochera davantage des principes RESTful que de débattre de la question de savoir si les verbes sont autorisés dans votre API.
Qu'est-ce qu'une « ressource » ?
Les gens débattent souvent de ce qu'est une ressource dans REST. J'ai vu plus ou moins souvent des gens exprimer l'opinion qu'une ressource est une structure de données provenant du serveur, malheureusement souvent même équivalente à une entité persistante.
Voyons ce que Fielding en dit :
L'abstraction clé de l'information dans REST est une ressource. Toute information pouvant être nommée peut être une ressource : un document ou une image, un service temporel (par exemple « la météo d'aujourd'hui à Los Angeles »), une collection d'autres ressources, un objet non virtuel (par exemple une personne), etc. En d'autres termes, tout concept pouvant être la cible d'une référence hypertexte d'un auteur doit correspondre à la définition d'une ressource. Une ressource est un mappage conceptuel vers un ensemble d'entités, et non l'entité qui correspond au mappage à un moment donné.
La sémantique est un sous-produit de l'acte d'attribuer des identifiants de ressources et de remplir ces ressources avec des représentations. À aucun moment, le serveur ou le logiciel client n'ont besoin de connaître ou de comprendre la signification d'un URI : ils agissent simplement comme un canal par lequel le créateur d'une ressource (une autorité de nommage humaine) peut associer des représentations à la sémantique identifiée par l'URI. En d'autres termes, il n'y a pas de ressources sur le serveur, mais seulement des mécanismes qui fournissent des réponses via une interface abstraite définie par les ressources. Cela peut sembler étrange, mais c'est l'essence même de ce qui permet au Web de fonctionner à travers tant d'implémentations différentes.
La sémantique est un sous-produit de l'acte d'attribuer des identifiants de ressources et de remplir ces ressources avec des représentations. À aucun moment, le serveur ou le logiciel client n'ont besoin de connaître ou de comprendre la signification d'un URI : ils agissent simplement comme un canal par lequel le créateur d'une ressource (une autorité de nommage humaine) peut associer des représentations à la sémantique identifiée par l'URI. En d'autres termes, il n'y a pas de ressources sur le serveur, mais seulement des mécanismes qui fournissent des réponses via une interface abstraite définie par les ressources. Cela peut sembler étrange, mais c'est l'essence même de ce qui permet au Web de fonctionner à travers tant d'implémentations différentes.
Cette spécification ne limite pas la portée de ce qui peut être considéré comme une ressource ; le terme « ressource » est plutôt utilisé dans un sens général pour désigner tout ce qui peut être identifié par un URI. Parmi les exemples courants, on peut citer un document électronique, une image, une source d'informations ayant un objectif cohérent (par exemple, « les prévisions météo du jour pour Los Angeles »), un service (par exemple, une passerelle HTTP vers SMS) et un ensemble d'autres ressources. Une ressource n'est pas nécessairement accessible via Internet ; par exemple, les êtres humains, les entreprises et les livres reliés dans une bibliothèque peuvent également être des ressources. De même, des concepts abstraits peuvent être des ressources, tels que les opérateurs et les opérandes d'une équation mathématique, les types de relation (par exemple, « parent » ou « employé ») ou les valeurs numériques (par exemple, zéro, un et l'infini).
- ftp://ftp.is.co.za/rfc/rfc1808.txt
- http://www.ietf.org/rfc/rfc2396.txt
- ldap://[2001:db8::7]/c=GB?objectClass?one
- mailto:John.Doe@example.com
- news:comp.infosystems.www.servers.unix
- tel:+1-816-555-1212
- telnet://192.0.2.16:80/
- urn:oasis:names:specification:docbook:dtd
ml:4.1.2
Conclusion sur les ressources
Une ressource peut être pratiquement tout ce qui peut être adressé par un URI. Il peut s'agir d'un objet physique, d'un concept, d'un document, d'un service ou même d'une chose virtuelle ou abstraite, à condition qu'elle puisse être identifiée et représentée de manière unique.
Ce que Fielding considère comme une API RESTful
En 2008, Fielding a exprimé sa frustration : Source
Je suis frustré par le nombre de personnes qui qualifient toute interface basée sur HTTP d'API REST.
Concepteurs d'API, veuillez noter les règles suivantes avant de qualifier votre création d'API REST :
- Une API REST ne doit pas dépendre d'un protocole de communication unique, même si son mappage réussi à un protocole donné peut dépendre de la disponibilité des métadonnées, du choix des méthodes, etc. En général, tout élément de protocole qui utilise un URI pour l'identification doit permettre l'utilisation de n'importe quel schéma URI à des fins d'identification. [Un échec à cet égard implique que l'identification n'est pas séparée de l'interaction.]
- Une API REST ne doit pas contenir de modifications des protocoles de communication, à l'exception du remplissage ou de la correction des détails des bits sous-spécifiés des protocoles standard, tels que la méthode PATCH ou le champ d'en-tête Link de HTTP. Les solutions de contournement pour les implémentations défectueuses (telles que les navigateurs assez stupides pour croire que HTML définit l'ensemble des méthodes HTTP) doivent être définies séparément, ou au moins dans des annexes, en espérant que la solution de contournement finira par devenir obsolète. [Tout manquement à cette règle implique que les interfaces de ressources sont spécifiques à un objet et non génériques.]
- Une API REST doit consacrer la quasi-totalité de ses efforts descriptifs à la définition des types de médias utilisés pour représenter les ressources et piloter l'état de l'application, ou à la définition de noms de relations étendus et/ou de balises hypertextes pour les types de médias standard existants. Tout effort consacré à la description des méthodes à utiliser sur les URI d'intérêt doit être entièrement défini dans le cadre des règles de traitement d'un type de média (et, dans la plupart des cas, déjà défini par les types de médias existants). [Tout manquement à cette règle implique que l'interaction est pilotée par des informations hors bande plutôt que par l'hypertexte.]
- Une API REST ne doit pas définir de noms ou de hiérarchies de ressources fixes (couplage évident entre le client et le serveur). Les serveurs doivent avoir la liberté de contrôler leur propre espace de noms. Au lieu de cela, permettez aux serveurs d'indiquer aux clients comment construire des URI appropriés, comme cela se fait dans les formulaires HTML et les modèles d'URI, en définissant ces instructions dans les types de médias et les relations de lien. [Un échec à cet égard implique que les clients supposent une structure de ressources en raison d'informations hors bande, telles qu'une norme spécifique à un domaine, qui est l'équivalent orienté données du couplage fonctionnel du RPC].
- Une API REST ne doit jamais comporter de ressources « typées » qui sont significatives pour le client. Les auteurs de spécifications peuvent utiliser des types de ressources pour décrire l'implémentation du serveur derrière l'interface, mais ces types doivent être sans importance et invisibles pour le client. Les seuls types qui sont significatifs pour un client sont le type de média de la représentation actuelle et les noms de relations standardisés. [idem]
- Une API REST doit être accessible sans connaissance préalable autre que l'URI initiale (signet) et un ensemble de types de médias standardisés adaptés au public visé (c'est-à-dire compréhensibles par tout client susceptible d'utiliser l'API). À partir de là, toutes les transitions d'état de l'application doivent être déterminées par le choix du client parmi les options fournies par le serveur qui sont présentes dans les représentations reçues ou implicites dans la manipulation de ces représentations par l'utilisateur. Les transitions peuvent être déterminées (ou limitées) par la connaissance qu'a le client des types de médias et des mécanismes de communication des ressources, qui peuvent tous deux être améliorés à la volée (par exemple, code à la demande). [Un échec à ce niveau implique que ce sont des informations hors bande qui déterminent l'interaction plutôt que l'hypertexte.]
Mais qu'est-ce que tout cela signifie exactement ? Pour être honnête, sans y consacrer du temps et de la réflexion, je ne l'ai pas compris non plus la première fois que je l'ai lu.
Interprétation des règles
Voici ma compréhension de ces règles, n'hésitez pas à ne pas être d'accord et discutons-en ! Je suis curieux de connaître d'autres points de vue ou opinions à leur sujet.
1. Ne dépendez pas d'un seul protocole
Une API REST utilise des identifiants de ressources uniformes (URI) pour nommer les éléments. Une URL (http://...) n'est qu'un type spécifique d'URI qui inclut également un emplacement. Le principe clé ici est que l'identité fondamentale d'une ressource doit être séparée de son mécanisme d'accès.
Un URI (Uniform Resource Identifier) est un concept large qui désigne toute chaîne de caractères utilisée pour identifier une ressource, tandis qu'une URL (Uniform Resource Locator) est un type spécifique d'URI qui non seulement identifie une ressource, mais fournit également un moyen de la localiser en décrivant son mécanisme d'accès principal (tel que son emplacement réseau).
Votre API doit fonctionner avec n'importe quel URI et ne pas dépendre de mécanismes spécifiques à HTTP.
2. Ne modifiez pas le protocole
Respectez les normes existantes (comme HTTP). Si un élément de la norme est vague, clarifiez-le. N'inventez pas de nouveaux comportements et ne modifiez pas ceux qui existent déjà.
Ne piratez pas et ne redéfinissez pas le fonctionnement de HTTP. Corrigez les lacunes, mais ne modifiez pas les règles.
Si HTTP ne définit pas entièrement le fonctionnement de PATCH, vous pouvez le clarifier. Mais ne redéfinissez pas GET pour également supprimer des données simplement parce que c'est pratique.
3. Concentrez-vous sur les types de médias, pas sur les URI
Votre API doit définir comment comprendre et utiliser les données qu'elle renvoie, à travers les types de médias (tels que JSON, HTML) et les liens, et non se concentrer sur la structure des URI ou les actions à appeler.
Consacrez votre énergie à la conception du format des données et des liens qu'elles contiennent, et non à la documentation des URL à utiliser.
Au lieu de documenter que vous devez envoyer une requête POST à /users/123/activate, votre API doit renvoyer une représentation de l'utilisateur dans un format compatible avec l'hypermédia (comme application/hal+json ou un type personnalisé comme application/vnd.myapp.user+json).
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 | { "name": "John Doe", "status": "inactive", "_links": { "self": { "href": "/users/123" }, "activate": { "href": "/users/123/activate", "method": "POST" } } } |
Le code client ne connaît pas le chemin /users/123/activate. Il sait seulement que le type de média définit une relation de lien « activate » et utilise le href et la méthode fournis dans la réponse pour effectuer l'action.
4. Ne codifiez pas en dur les structures d'URI
Cette règle est la conséquence directe de la règle n° 3. Les clients ne doivent pas supposer ou coder en dur des chemins tels que /users/123/posts. Ils doivent plutôt découvrir les URI via les liens fournis par le serveur. Les clients doivent apprendre les URI de manière dynamique.
Un client ne doit pas supposer que les publications d'un utilisateur se trouvent à l'adresse /users/123/posts. Il doit lire un lien comme celui-ci à partir de la ressource :
5. Évitez les « types » de ressources
La classification interne d'une ressource par le serveur (par exemple, utilisateur ou administrateur) doit être totalement indépendante et invisible pour le client.
Le client ne doit pas se soucier du type d'entité qu'une ressource représente en interne (comme utilisateur, administrateur, modérateur). Il doit uniquement se soucier du type de média (comme application/json) et des liens/actions qu'il voit.
N'exposez pas les types d'objets ou les rôles internes. Envoyez simplement une réponse bien structurée avec des liens utiles. Ne demandez pas au client de savoir qu'une ressource est de type Admin. Donnez-lui simplement une réponse application/json cohérente avec des liens et des données pertinents.
Par « noms de relations standardisés », il fait référence aux relations de liens enregistrées par l'IANA.
6. Commencez par un signet et suivez les liens
Le client ne devrait avoir besoin que d'un seul point de départ (par exemple, une URL de base, un signet) et d'une connaissance des types de médias standard. Tout le reste (quoi faire, où aller) devrait provenir des réponses du serveur.
Les clients doivent suivre les liens comme s'ils naviguaient sur un site web, en commençant par la page d'accueil et en cliquant sur les liens, sans coder en dur les chemins d'accès.
Commencez par https://api.example.com/ et suivez les liens dans chaque réponse :
Code : | Sélectionner tout |
1 2 3 4 5 6 | { "_links": { "user": { "href": "/users/123" }, "orders": { "href": "/users/123/orders" } } } |
Dans la pratique, très peu d'API respectent ces principes. La section suivante examine pourquoi.
Pourquoi la plupart des API ne sont-elles pas véritablement RESTful ?
L'adoption généralisée d'un style plus simple, similaire au RPC, sur HTTP peut probablement être attribuée à des compromis pratiques en matière d'outils et d'expérience des développeurs : l'écosystème autour de spécifications telles que OpenAPI s'est développé rapidement, offrant des avantages immédiats qui se sont avérés irrésistibles pour les équipes de développement. Ces outils offraient des fonctionnalités puissantes telles que la génération automatique de code client/serveur, une documentation interactive et la validation des requêtes prête à l'emploi. Pour une équipe soumise à la pression de livrer, le contrat clair et statique fourni par une définition OpenAPI était et est probablement encore souvent considéré comme « suffisant », rendant les avantages architecturaux à long terme de HATEOAS, tels que l'évolutivité, abstraits et moins urgents.
De plus, la charge cognitive initiale liée à la création d'un client véritablement hypermédia était perçue comme un obstacle important. Il semblait plus facile pour un développeur de lire la documentation et de coder en dur un modèle d'URI tel que /users/{id}/orders que d'écrire un client capable d'analyser dynamiquement une section _links et de découvrir l'URI « orders » lors de l'exécution.
Dans de nombreux scénarios courants, tels que le développement d'une application frontale à page unique par la même équipe que le backend, le client et le serveur sont déjà étroitement couplés. Dans ce contexte, le principal problème que HATEOAS résout, à savoir le découplage du client de la structure URI du serveur, ne se présente pas comme un point sensible immédiat, ce qui fait de l'approche plus simple, basée sur la documentation, la voie la moins résistante.
Conclusion
Les règles de Fielding soulignent qu'une API véritablement RESTful doit adopter l'hypermédia (HATEOAS) comme mécanisme central d'interaction, et ne pas se contenter d'utiliser HTTP comme moyen de transport. REST est indépendant du protocole dans son essence ; HTTP est simplement un moyen pratique de l'utiliser. Les clients doivent découvrir et naviguer dans les ressources de manière dynamique grâce à des liens et des relations standardisées intégrés dans les représentations, sans dépendre de structures d'URI, de types ou de documentation externe codés en dur.
Cela rend les systèmes REST faiblement couplés, évolutifs et alignés sur le fonctionnement du web lui-même : à travers la représentation, la découverte et les transitions. REST ne consiste pas à exposer votre modèle d'objet interne via HTTP, mais à construire des systèmes distribués qui se comportent comme le web.
Par conséquent, soyez simplement pragmatique. Personnellement, j'aime éviter le terme « RESTful » pour les raisons exposées dans l'article et préfère parler d'API basées sur « HTTP ». Construisez ce qui est logique pour votre projet et les consommateurs de votre API. Ignorez les dogmatiques qui prêchent ce que devraient être ou ne pas être les API RESTful. Une API doit avant tout être facile à apprendre et difficile à utiliser à mauvais escient. Si elle répond à ces critères, peu importe qu'elle soit RESTful ou non. Suivez la loi de Postel si cela est logique dans votre cas : « Soyez conservateur dans ce que vous faites, soyez libéral dans ce que vous acceptez des autres. ».
Qui sont les utilisateurs de votre API ? Sera-t-elle facile à apprendre et à utiliser ? Son utilisation sera-t-elle intuitive ? Quelles sont les contraintes possibles ? Comment la versionnez-vous ? Quelles sont vos stratégies de dépréciation et de mise hors service ? Comment les modifications apportées à l'API sont-elles communiquées efficacement aux utilisateurs ? Ces éléments sont bien plus importants que le format réel de votre identifiant de ressource.
En utilisant HATEOAS et en référençant des définitions de schéma (telles que XSD ou JSON Schema) à partir de vos représentations de ressources, vous pouvez permettre aux clients de comprendre la structure des données et de naviguer dans l'API de manière dynamique. Cela peut prendre en charge des clients génériques ou auto-adaptatifs. Si cela correspond à vos objectifs (par exemple, découplage des clients, évolutivité, interaction dynamique), alors c'est un choix de conception valable et puissant. Si vous créez une API publique pour des développeurs externes que vous ne contrôlez pas, investissez dans HATEOAS. Si vous créez un backend pour un seul frontend contrôlé par votre propre équipe, une API de type RPC plus simple peut être un choix plus pratique.
Source : "Most RESTful APIs aren't really RESTful"
Et vous ?


Voir aussi :



Vous avez lu gratuitement 3 088 articles depuis plus d'un an.
Soutenez le club developpez.com en souscrivant un abonnement pour que nous puissions continuer à vous proposer des publications.
Soutenez le club developpez.com en souscrivant un abonnement pour que nous puissions continuer à vous proposer des publications.