Il y a quelques années, j’ai parlé d’architectures ROCA dans un article sur le Touilleur Express, inspiré par Sadek Drobi de Prismic.io (et aussi co-créateur de Play2 au passage). Plus global que de parler simplement d’API REST, cette notion permet de décrire un ensemble de caractéristiques intéressantes pour construire une application web. Cela reste très actuel en 2017 et encore parfois peu connu de beaucoup de développeurs.
Aujourd’hui je souhaite faire un focus sur les API REST de niveau 3 (modèle de Richardson), qui exposent les ressources ainsi qu’un ensemble d’hyper-liens entre les ressources. Peut-être que vous avez déjà entendu parler d’HATEOAS (Hypermedia As The Engine of Application State). Vous pouvez aller voir l’API du CFP de Devoxx France, qui est une forme d’implémentation très basique (et certainement perfectible) de cette approche.
En octobre 2008, dans l’un des commentaires sur son blog, Roy Fiedling (REST) répond avec ceci :
I think most people just make the mistake that it should be simple to design simple things. In reality, the effort required to design something is inversely proportional to the simplicity of the result. As architectural styles go, REST is very simple (source).
J’ai revu récemment le principe d’HATEOAS et plusieurs exemples d’implémentations. L’idée de base, lorsque vous codez une API REST, est de permettre l’interconnexion via le réseau entre 2 systèmes. C’est la base de la thèse de R.Fielding en 2000 « Architectural Styles and the Design of Network-based Software Architectures« . De là, les gens ont surtout retenu le chapitre 5, qui parle de REST. Mais la lecture complète du document fait bien la distinction entre la représentation des ressources, et la définition des actions/méthodes possibles entre ressources.
HATEOAS, contrairement à une architecture SOA, permet de découpler plus fortement (mais pas totalement) les relations clients-serveurs. C’est un principe qui permet de définir la logique de contrôle sur les ressources, dans la représentation même de ces ressources. Imaginez une ressource « place de concert » qui expose un lien « transférer sa place » ou « annuler » pour permettre des actions, et déclencher la création ou la modification de ressources. Cela serait pratique si ces actions étaient exposées en même temps que la représentation de votre place de concert non ? Un peu comme des hyper-liens dans une page web.
Pour que cela fonctionne, une API REST type HATEOAS expose des liens d’action (si c’est le bon terme) afin de permettre de naviguer de ressource en ressource. S’il existait une entité facture, alors celle-ci aurait un lien vers « client facturé » pour permettre de charger plus d’informations sur le client facturé. Et chaque client pourrait avoir un lien vers une liste de factures, etc. Jusqu’ici il s’agit de permettre de parcourir un graphe d’objet.
Imaginons que nous ayons aussi un lien « annuler facture » qui modifiera la facture, entrainera la création d’un avoir, etc. Il faudra donc pouvoir distinguer les liens entre les ressources, des liens d’actuateurs qui modifient cette ressource. C’est là que cela commence à être intéressant.
Il faut que le client de cette API soit maintenant capable de « comprendre » la sémantique de votre API.
Sur le papier, cela semble génial, on attend plus que tout le monde implémente son API REST de cette façon, c’est la fête, je vais me faire tatouer HATEOAS, etc.
Mais où est le framework JS qui fait cela ? Ah y’en a pas. Bon.
Cela permet en principe d’écrire une API « auto-découvrable » où un client, doué d’une capacité à « lire » les liens hypertextes, serait capable de parcourir le graphe des ressources d’une API. En théorie.
Premier point qui selon moi, manque de normalisation ou de définition, c’est que le client de votre API doit alors être sacrément bien implémenté pour parcourir ce graphe.
Deuxième point, si on va un peu plus loin, c’est que les ressources d’une API n’auraient plus d’URI unique. J’ai même entendu un développeur dire : « on va obfusquer les URLs pour que les clients ne puissent pas utiliser directement les ressources ».
Troisième point, cela présuppose que le client comprend l’ontologie (la grammaire) et qu’il dispose d’un moyen pour « analyser » et connaître à priori les verbes d’action.
Or je prends mes lunettes et je relis ceci, de Roy Fielding :
“A REST API should be entered with no prior knowledge beyond the initial URI… From that point on, all application state transitions must be driven by client selection of server-provided choice… “
Dans la vraie vie sur de vrais projets, HATEOAS peut entraîner une sur-complexité pour le client de votre service. Il manque l’équivalent d’un bon vieux WSDL, qui pour le coup, permettait de documenter le contrat client-serveur, et même parfois de générer du code côté client automatiquement (wsdl2java, mon cher, c’est de toi dont je parle). C’était verbeux, cela plantait parfois (surtout avec Oracle Application Server en fait) mais cela marchait pas trop mal au final.
GraphQL ? je sais pas, je ne connais pas.
HATEOAS, tu te débrouilles. Tu charges la ressource initiale et tu vas découvrir ensuite le graphe des relations entre les agrégats de ton domaine. Humm… moi je voulais juste écrire un client REST en 2 jours et pas dépenser tout mon budget pour faire un parseur de ton API.
Le côté positif : l’ontologie est exposée avec les ressources. Le côté discutable c’est que les utilisateurs de cette API vont devoir mettre en place des clients plus poussés, à même de s’adapter sans dépendance à votre serveur.
Bref HATEOAS et l’idée d’API découvrable ne doit pas faire oublier que cela va demander plus de travail, pour le client de cette API Web. Il faut penser aussi aux développeurs de votre API. Swagger permet de documenter et de structurer l’API. JSON-D (pas utilisé personnellement) semble pouvoir donner un coup de main pour exposer mieux la sémantique.
Dernier projet à regarder, si vous vous êtes déjà engagé sur ce chemin, c’est Hydra (http://www.hydra-cg.com/). Il s’agit d’une spécification en draft, proposée début 2017 par Markus Lanthaler de Google. Attention elle n’a rien d’officiel et je vous recommande de bien lire le disclaimer de la spécification. Ce n’est PAS une spec du W3C. Cela étant dit, c’est un travail intéressant assorti d’un ensemble d’outils, qui permet de décrire une API HATEOAS avec un vocabulaire normalisé. L’idée d’Hydra est de permettre d’informer des différentes transitions possibles dans la ressource (en général représentée en JSON). C’est encore un peu neuf, même s’il existe des kits clients en Java.
Voir aussi JSON-LD (Json for Linked Data) qui permet de donner une correspondance entre vos champs JSON et des champs plus normalisés.
Pour conclure
Posez-vous la question : qui va devoir utiliser mon API ? Est-ce que vraiment, c’est nécessaire ? Cela ne va-t-il pas entraîner un coût de développement plus important pour mes utilisateurs ? Comment vais-je documenter mon API ? M’assurer que cette documentation est à jour ?
Commentaires récents