Vous en conviendrez tous, entendre quelqu’un parler et employer à tord un terme, soit-il technique ou non, gêne. Cela est d’autant plus vrai lorsque ce terme est un buzzword.
Aujourd’hui, étudions un mot à la mode : REST.
Qui n’a pas lu un article sur comment créer un service REST avec le framework machin chose ? Bien que souvent intéressants techniquement, ces articles parlent dans la plupart des cas de la mise en oeuvre de services web utilisant autant que faire se peut les possibilités d’interaction proposées par HTTP et reposant sur un format de présentation plébiscité pour ce type d’API : JSON. Lorsqu’on est là, on est encore loin du compte pour revendiquer l’étiquette “REST”.
Un service qui se conformerait au style d’architecture REST (ou service aussi dit RESTful) doit en fait tout simplement suivre la définition du style. Et cela devient d’un seul coup un peu plus compliqué que de simplement sérialiser un POJO en JSON et le servir sur un plateau à quiconque appelle le serveur avec une méthode GET sur l’adresse de la ressource visée.
Avant d’aller plus en avant, faisons un petit “zoom out”. Le terme REST – pour Representational State Transfer – nous vient de Roy Fielding, diplômé de l’UCI [1], membre du “Board of Directors” de la fondation Apache. Il a présenté ce style d’architecture dans une thèse en 2000 sur les systèmes distribués. Il s’agit d’un style, parmi d’autres, adapté à ce type d’architectures, inspiré par ailleurs de certains (“REST is a hybrid style derived from several of the network-based architectural styles”). Et ce style trouve en HTTP un protocole applicatif particulièrement adapté, mais pourrait aussi se décliner avec d’autres.
Mais concrètement, qu’est-ce que c’est que ce style d’architecture réellement ? Comment se définit-il ?
Pour les amateurs de lecture, la thèse de Roy T. Fielding, disponible en ligne [2], apporte toutes les réponses détaillées.
Pour ceux qui souhaitent une synthèse, nous allons en extraire les principes fondamentaux.
On peut résumer le style d‘architecture REST à un ensemble de contraintes à satisfaire, au nombre de 6 pour les principales (les termes originaux en anglais sont de préférence à retenir en lieu et place de mes traductions, ils sont donc repris ci-dessous entre crochets). Voici donc les contraintes :
- [Client Server] Architecture client serveur
La séparation des responsabilités entre le client et le serveur offre un découplage favorable à l’évolution du système dans son ensemble. Ce type d’architecture n’est pas propre au style REST, ce dernier s’en inspire tout simplement. - [Stateless] Sans état (coté serveur)
Chaque requête doit porter suffisamment d’information pour être comprise par le serveur sans que celui-ci n’ait besoin de retrouver le fruit des interactions précédentes avec ce client en particulier. Cela permet d’assurer une meilleure capacité à monter en charge, mais aussi d’améliorer la robustesse (la perte d’une session est toujours un problème, et sa réplication encore plus…) - [Cache] Utilisation du cache
On parle d’architecture distribuée et donc d’échanges réseau. La contrainte du cache est naturellement là pour optimiser les performances. Cette contrainte induit que les réponses du service indiquent au client si elles peuvent être mises en cache ou non, lui laissant la possibilité de ne pas requêter à nouveau si la ressource est présumée encore “ fraîche” - [Uniform Interface] Interface uniforme
Cette contrainte augmente encore le découplage entre le client et les ressources en rendant générique la façon d’interagir avec les ressources. Le style REST spécifie sous forme de nouvelles contraintes ce qu’est une interface uniforme. Ces contraintes d’interface sont :1. Une identification des ressources. Cela permet de faire référence à des ressources de façon non équivoque et de créer des liens pérennes entre ressources. - L’utilisation de Représentations pour interagir avec les Ressources. Une ressource peut avoir une ou plusieurs représentations, que le client manipulera et dont il se servira pour communiquer avec le service, lequel agira sur la ressource en conséquence.
- Messages auto descriptifs. Une réponse à une requête portera par exemple une information sur le type de représentation retourné, permettant au client de savoir comment la traiter.
- Gestion des transitions par liens hypermédia. Les possibilités d’interactions avec une ressource au travers ses représentations sont décrites dans les messages par des liens hypermédia, permettant au client de “découvrir” ce qui lui est permis de faire.
- [Layered System] Architecture multi-couches
On parle ici des couches d’une architecture complète. Considérant le cas d’un service REST reposant sur HTTP, ces couches sont par exemple un reverse proxy, un service d’authentification, … Le client ne doit pas avoir besoin de connaître, ni quelle est la première couche avec laquelle il communique, ni combien de couches le séparent des ressources manipulées. D’ailleurs la configuration des couches doit pouvoir évoluer sans impact sur le client. Ici, l’interface unifiée est un des éléments permettant cette souplesse. - [Code-on-demand] Code à la demande Optionnel
Offre la possibilité de fournir au client par le biais, de scripts fournis par le serveur qu’il pourra exécuter, l’accès à des fonctionnalités sans besoin au préalable qu’il les ait implémentées. Cette contrainte est notée comme optionnelle. Elle doit rester optionnelle aussi dans le sens ne pas bloquer l’utilisation du service si le client ne permet pas l’exécution du code en question (“non obtrusive”). Elle peut avoir du sens par exemple dans un environnement maîtrisé (typiquement en entreprise).
Ces contraintes apportent un certain nombre d’avantages à une architecture qui les suivrait, mais aussi des inconvénients, par ailleurs clairement énoncés dans la thèse. Il s’agit, comme à chaque fois, de compromis.
Vous comprenez donc qu’un service ne peut pas être qualifié de REST simplement parce qu’il retourne des objets sérialisés au format JSON… C’est d’ailleurs l’avis du créateur de ce style, qui insiste sur le respect des contraintes, et qui a écrit il y a quelques années : “I am getting frustrated by the number of people calling any HTTP-based interface a REST API. […] if the engine of application state […] is not being driven by hypertext, then it cannot be RESTful and cannot be a REST API. Period.”.
Cependant, il est juste de dire que certains services s’inspirent des principes du style d’architecture REST, et se conforment à une ou plusieurs contraintes, sans forcément d’ailleurs que leurs concepteurs ne les connaissent toutes. Pour mesurer ce niveau de conformité, on peut s’appuyer sur une échelle, appelée le “modèle de maturité”, imaginée par Leonard Richardson (QCon 2008, Act 3: The Maturity Heuristic [3]) et présentée à la conférence QCon en 2008. Le modèle présente une échelle sur 4 niveaux (0 à 3) sur laquelle un service peut se positionner quant à son respect des contraintes. Vous constaterez qu’au mieux, les services que vous rencontrez dans les tutoriaux atteignent 2… Et s’ils atteignent 3, ajoutez-les à vos favoris et inspirez-vous en !
Enfin, REST fait encore pas mal débattre les experts et le concept proposé par Roy Fielding n’a pas fini de susciter questions, et fort heureusement réponses. J’espère qu’à la lecture de cet article vous aurez une vision plus complète de ce style d’architecture que j’ai essayé de résumer ici, et qui fait parler beaucoup de lui sans pour autant être bien connu. Peut-être aurez-vous aussi l’envie d’en découvrir plus et d’essayer de construire vos services en respectant un maximum de contraintes du style REST afin de rendre votre “API Web” progressivement “RESTful”.
De prochains articles sur le sujet essaieront de compléter votre arsenal de connaissances sur ce sujet.
[1] : http://www.uci.edu/
[2] : http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
[3] : http://www.crummy.com/writing/speaking/2008-QCon/act3.html
Crédit Photo : http://www.flickr.com/photos/adactio/