Article

L'interface uniforme : l'hypermédia comme moteur

Le cœur de REST : l'interface uniforme et HATEOAS, l'hypermédia comme moteur de l'état. Le client suit liens et formulaires au lieu de coder les URL en dur.

Votre navigateur n'a jamais été mis à jour parce qu'un site a déplacé un bouton. Votre application mobile, elle, casse dès que l'API renomme une URL. Les deux parlent HTTP ; un seul respecte la contrainte qui fait toute la différence.
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 représentation ne porte pas que des données : elle porte ses propres transitions. Le client suit ce qu'on lui offre ; il ne devine pas l'étape suivante.

Au volet précédent, six contraintes définissaient le style REST. L'une d'elles en est la clé de voûte : l'interface uniforme. C'est elle qui permet à un même client de parler à des serveurs qu'il n'a jamais vus — et c'est elle, presque toujours, qu'on laisse de côté. Elle se décompose en quatre sous-contraintes ; les trois premières sont admises sans peine, la quatrième est la grande oubliée.

Identifier, représenter, se décrire

Identifier les ressources. Une ressource est un concept — une commande, un article, un compte — désigné de façon stable par une URI. Pas une fonction ni une action : un nom de chose. On modélise des noms, on agit dessus ensuite.

Manipuler par les représentations. Le client ne touche jamais la ressource directement ; il échange des représentations, c'est-à-dire des messages. Une même ressource peut en avoir plusieurs : du HTML pour un navigateur, du JSON pour un programme, choisis par le client via l'en-tête Accept. La ressource est le concept ; la représentation en est une photographie, à un instant et dans un format donnés.

Des messages auto-descriptifs. Chaque message porte de quoi être compris seul : la méthode dit l'intention (lire, créer, remplacer), le type de média — le Content-Type que vous voyez dans toute réponse HTTP — dit comment lire le corps, le code de statut dit ce qui s'est passé : 200, 404, 409 ne sont pas des décorations mais une sémantique partagée. La méthode énonce aussi des garanties communes : GET est sûre (sans effet de bord) donc cacheable, PUT et DELETE sont idempotentes — rejouables sans dommage : envoyer deux fois le même DELETE ne casse rien, la seconde fois la ressource est déjà supprimée. Ces propriétés ne sont pas propres à votre API : un intermédiaire — cache, proxy — sait qu'il peut mettre en cache un GET ou réessayer un PUT, sans rien connaître du métier.

HATEOAS : l'hypermédia comme moteur

Vient la quatrième, celle dont le sigle effraie pour rien : HATEOAS, pour Hypermedia As The Engine Of Application State — l'hypermédia comme moteur de l'état de l'application. L'idée est exactement celle d'une page web : la réponse du serveur ne contient pas que des données, elle contient les transitions possibles, sous forme de liens à suivre et de formulaires à soumettre. Le client ne calcule pas l'étape suivante, ni l'URL à appeler : il la découvre dans ce que le serveur vient de lui envoyer, et la suit. Une telle action, offerte et décrite par le message, porte un nom : une affordance.

« Moteur de l'état de l'application » est à prendre au pied de la lettre. Là où vous en êtes dans un parcours — panier, validation, paiement — n'est pas une logique gravée dans le client : c'est l'enchaînement des liens et des formulaires que le serveur propose, étape après étape, qui fait avancer l'état. Un exemple concret : la représentation d'une commande en attente porte ses données, mais aussi un lien vers le client, un formulaire « payer » (méthode et cible comprises), un formulaire « annuler ». Le client n'a pas à savoir bâtir l'URL de paiement : il soumet le formulaire qu'on lui tend. Une fois la commande payée, la représentation suivante ne proposera plus « payer », mais « suivre l'expédition ». L'éventail des actions est dicté par l'état, côté serveur ; le client n'est que l'exécutant.

Schématiquement, la représentation porte ses données et ses transitions — chaque action avec sa méthode, sa cible et ses champs attendus :

{
  "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" }
  }
}

Et l'hypermédia n'est pas réservé au HTML. Des types de média pensés pour le JSON — comme HAL, JSON:API ou Siren — normalisent la façon d'y porter liens et actions. Le contrat partagé, c'est le type de média, pas l'URL : deux programmes qui parlent le même type se comprennent sans documentation préalable, exactement comme deux navigateurs s'accordent sur le HTML. Le couplage ne s'évapore pas pour autant — il se déplace. Le client doit encore partager le sens des relations (le vocabulaire des rel : que veut dire « payer », « suivant », « client ») et des champs de formulaire. C'est un contrat, mais porté par le type de média et son vocabulaire, pas gravé dans des URL. Et écrire un client qui suit réellement les affordances, au lieu de re-coder les chemins en douce, demande plus de soin : c'est pourquoi, en pratique, tant d'« API REST » hypermédia retombent dans le codage en dur.

Le navigateur, preuve par l'exemple

Cette contrainte n'a rien d'abstrait : vous l'utilisez chaque jour. Le navigateur est le client générique par excellence. Il ne connaît à l'avance aucune des adresses des milliards de sites qu'il visite ; il affiche ce que le serveur envoie et suit les liens et formulaires qu'on y a placés. Qu'un site refonde toutes ses URL du jour au lendemain, et aucun navigateur n'a besoin d'être corrigé — parce qu'aucun n'avait codé ces URL en dur. C'est l'évolutivité par l'hypermédia, à l'échelle du Web.

Comparez avec une application mobile branchée sur une « API REST » ordinaire : elle a, gravé dans son code au moment de sa compilation, le gabarit /api/v1/commandes/{id}. Que le serveur réorganise ses chemins, et l'application se brise — il faut la republier, puis attendre que chaque utilisateur la mette à jour. Le couplage que l'hypermédia avait dissous est revenu, du côté du client.

Auto-descriptif et hypermédia se complètent : le premier fait qu'un message dit ce qu'il est, le second qu'il dit ce qu'on peut faire ensuite. Ensemble, ils suffisent à piloter un client qui ne sait rien de l'application à l'avance — exactement ce que décrit Fielding dans sa définition de REST.

Si cette contrainte est si puissante, pourquoi presque aucune « API REST » ne l'implémente-t-elle ? Parce qu'on l'a jugée coûteuse, et qu'on s'en est passé — à un prix qu'on mesurera au volet suivant.

Laisser un commentaire

Vous devez être connecté pour pouvoir laisser un commentaire.