Article

HATEOAS : une API qui indique les actions disponibles

Une réponse hypermédia contient des données, des liens et des actions. Le client suit ces indications, tout en partageant un vocabulaire clair avec le serveur.

Une commande attend son paiement. Au lieu de demander au client de construire lui-même l'adresse de paiement, l'API peut lui fournir l'action disponible, sa destination et les champs attendus. Après paiement, elle propose d'autres actions. Ce principe, appelé HATEOAS, permet au client de suivre les possibilités offertes par le serveur à chaque étape.
Une représentation REST contient le type de média et le statut, les données, les liens (transitions) et les formulaires (affordances) ; le client suit une affordance pour passer à l'état suivant, au lieu de connaître l'URL à l'avance.
Une réponse porte ses données et ses actions possibles. Le client suit ce qui lui est proposé, sans deviner l'étape suivante.

Suivre les liens et les actions proposés dans la réponse

HATEOAS développe Hypermedia As The Engine Of Application State. Le nom décrit une façon de faire avancer un parcours à partir des liens et des actions présents dans les réponses. Le client sait lire le format ; le serveur indique les possibilités disponibles.

Une action décrite dans un message est parfois appelée une affordance. Elle peut préciser une méthode HTTP, une adresse et les paramètres à fournir. Dans une page web, un formulaire remplit ce rôle.

Le client découvre la destination d'une action au lieu de la fabriquer à partir d'un chemin enregistré dans son code. Il choisit encore l'action selon son objectif : suivre un lien ne lui apprend pas automatiquement s'il faut payer, annuler ou attendre.

Le bénéfice attendu est de réduire le nombre d'adresses et de transitions codées à l'avance dans le client. Le serveur peut faire évoluer certaines destinations tant qu'il conserve le contrat que le client comprend.

Une réponse hypermédia, en un exemple

Voici une commande en attente de paiement. Elle porte ses données, un lien vers le client et deux actions, chacune avec sa méthode, sa cible et ses champs :

{
  "reference": "C-42",
  "statut": "en attente de paiement",
  "_liens":   { "client": { "href": "/clients/7" } },
  "_actions": {
    "payer":   { "method": "POST",   "href": "/commandes/C-42/paiement",
                 "champs": ["moyen", "montant"] },
    "annuler": { "method": "DELETE", "href": "/commandes/C-42" }
  }
}

Dans cet exemple de format, les noms _liens et _actions sont des conventions à documenter. Le client utilise l'adresse reçue pour soumettre le paiement. Une fois la commande payée, la réponse peut remplacer cette action par le suivi d'expédition.

Les actions affichées ne remplacent pas les contrôles du serveur. L'état ou les droits peuvent changer entre leur lecture et leur utilisation ; le serveur doit encore vérifier la demande et signaler un conflit si nécessaire.

L'interface uniforme fournit un contrat commun

Fielding place l'hypermédia parmi les quatre composantes de l'interface uniforme du style REST. Elles permettent de partager des règles de communication entre clients et serveurs. Cette généralité peut coûter en efficacité par rapport à une interface conçue pour un seul échange.

Sous-contrainteCe qu'elle exigePoint de vigilance
Identifier les ressourcesune URI stable par concept, pas par actionVérifier que le contrat est documenté et stable
Manipuler par les représentationsle client échange des messages, jamais la chose elle-mêmeVérifier que le contrat est documenté et stable
Messages auto-descriptifsméthode, type de média et statut portent le senspartiellement : application/json ne porte aucune sémantique, et l'auto-description s'arrête souvent à la méthode et au statut
Hypermédia comme moteurla réponse porte les transitions possiblesLes transitions doivent être présentes et comprises par le client

Identifier les ressources. Une ressource est un concept — une commande, un article, un compte — désigné de façon stable par une URI. Nommez des choses, pas des actions, et agissez dessus ensuite.

Manipuler par les représentations. Le client ne touche jamais la ressource : il échange des représentations, des messages qui la photographient à un instant et dans un format donnés. Une même ressource peut être servie en HTML à un navigateur et en JSON à un programme, au choix du client par l'en-tête Accept.

Des messages auto-descriptifs. Chaque message se comprend seul. La méthode dit l'intention : lire, créer, remplacer. Le type de média (l'en-tête Content-Type) dit comment lire le corps. Le statut dit ce qui s'est passé : 200, 404 ou 409 ont un sens partagé.

La méthode donne aussi des garanties, et elles disent moins que ce qui leur est prêté. GET est sûre : le client ne demande aucun changement d'état et n'en répond pas. Ce que le serveur fait par ailleurs, journaliser ou facturer un affichage, ne lui est pas imputable. C'est une propriété distincte de la cacheabilité, que HTTP accorde à GET, HEAD et POST, et que les caches n'exploitent en pratique que pour les deux premières.

PUT et DELETE sont idempotentes : l'effet voulu de N requêtes identiques est celui d'une seule. Un client peut donc relancer sa requête quand la connexion tombe avant qu'il ait pu lire la réponse — l'effet sera le même, même si la réponse diffère, le second DELETE trouvant la ressource déjà supprimée. Ce que le serveur fait à côté, journaliser ou garder un historique, n'entre pas dans la garantie.

Ces garanties sont celles de HTTP, pas du métier. Un cache sait qu'il peut stocker la réponse à un GET ; un client dont la connexion est tombée sait qu'il peut relancer son PUT. Un proxy, lui, n'a le droit de rejouer automatiquement que l'idempotent.

Choisir un format qui décrit les contrôles nécessaires

Des types de média pensés pour le JSON normalisent la façon d'y placer ces contrôles. Mais pas au même degré, et la nuance a son importance. HAL s'en tient délibérément aux liens : « omettre les formulaires était une décision de conception intentionnelle », dit son annexe. JSON:API non plus n'en définit pas. Il faut Siren pour obtenir une action complète, avec sa méthode et ses champs.

Le type de média définit comment lire les données et les contrôles. Le client doit également comprendre le vocabulaire métier utilisé : ce que veut dire une relation « payer », quels montants sont exprimés et quelles erreurs sont possibles. Un format partagé ne donne pas à lui seul toute cette connaissance.

Le couplage ne disparaît pas pour autant : il se déplace. Ce qui reste à partager n'est plus la liste des URL mais le vocabulaire : le sens des relations, portées par l'attribut rel d'un lien (que veut dire « payer », « suivant », « client » ?), et celui des champs de formulaire. HAL le reconnaît d'ailleurs en demandant qu'une relation personnalisée soit une URI qui, ouverte dans un navigateur, serve sa propre documentation.

Écrire un client qui suit vraiment les affordances demande aussi plus de soin. C'est pourquoi tant d'« API REST » hypermédia retombent, en pratique, dans les URL écrites en dur.

Ce que le navigateur nous apprend sur ce contrat

Le navigateur illustre la séparation entre un mécanisme générique et les choix de l'utilisateur. Il sait afficher le HTML et suivre les formulaires ; la personne comprend le contenu et décide quoi faire. Cette compréhension humaine ne peut pas être supposée automatiquement chez tout client logiciel.

Une application mobile branchée sur une « API REST » ordinaire a, elle, le gabarit /api/v1/commandes/{id} gravé dans son code. Que le serveur réorganise ses chemins, et l'application casse : il faut la republier, puis attendre que chaque utilisateur la mette à jour.

Les messages auto-descriptifs indiquent comment interpréter l'échange ; l'hypermédia fournit les transitions proposées. Fielding souligne leur rôle dans les API REST, dans la continuité du modèle décrit dans sa thèse. Le client reste lié aux formats et aux relations qu'il sait utiliser.

Je privilégierais cette approche lorsque plusieurs clients doivent suivre des parcours qui évoluent. Elle demande de concevoir les réponses et les clients ensemble. Ajouter quelques liens à une API dont les consommateurs continuent à construire toutes les adresses ne procure pas le même bénéfice.

Sources

Explorer

Sur le même sujet

Choisis dans l’index d’après les étiquettes de cet article — les plus proches d’abord, hors de sa série. Rien n’est écrit à la main : un article publié demain avec les mêmes étiquettes y prendra place.

Laisser un commentaire

Elle n'est jamais affichée ni publiée. Elle sert à regrouper vos commentaires et, si vous vous inscrivez un jour avec elle, à vous les rendre.

Votre commentaire sera relu avant d'être publié.