HATEOAS, nouvelle approche des APIs, nouveaux cas d’usage

Les APIs sont au centre du Système d’Information et du business des entreprises. Et qui dit API dit très souvent REST. Après avoir énoncé un bref récapitulatif de l’architecture REST et de ses contraintes, nous nous attarderons plus spécifiquement sur l’une d’entre elles, HATEOAS. Au travers de cet article, nous verrons que HATEOAS propose de nombreux avantages et cas d’usages pertinents, et que son implémentation améliore grandement la communication entre le client et le serveur. Cependant HATEOAS est encore peu répandu au sein des APIs REST, et ce pour plusieurs raisons que nous verrons également.

HATEOAS dans le modèle de Richardson

REST appliqué au protocole HTTP, ça donne quoi ?

Nous allons nous intéresser dans la suite de cet article aux APIs qui reposent sur le principe de l’architecture REST, que nous appelons les APIs REST.

Afin de juger du niveau de conformité d’une API aux contraintes de l’architecture REST, il existe un modèle appelé modèle de Richardson. Ce modèle est composé de 4 niveaux qui introduisent progressivement les grands principes REST (ressources, verbes et codes HTTP, contrôles hypermédias).

Le niveau 0 : RPC

A ce niveau, HTTP est uniquement utilisé comme protocole d’échange entre le client et le serveur. L’API exposée ne comporte qu’un unique endpoint, par exemple :
http://api.nexworld.fr/v1/services
L’objectif de la requête est contenu dans le flux envoyé (dans les headers ou directement dans le corps du message). Le verbe POST est systématiquement utilisé et la réponse envoyée par le serveur est toujours accompagnée du code HTTP 200, en cas de succès comme en cas d’erreur. Ce niveau RPC s’apparente au protocole SOAP. Requête du client :

POST http://api.nexworld.fr/v1/services
{
    « action » : « getCustomer »,
    « id » : « 1111 »
}

Réponse du serveur en cas de succès :

HTTP/1.1 200 Success
{
    « id » : « 1111 »,
    « lastname » : « Dupond »,
   « contracts » : [
        {« id » : « 123 »},
        {« id » : « 124 »}
    ]
}

Réponse du serveur en cas d’erreur :

HTTP/1.1 200 Success
{
    « error_code » : « INT_ERROR »,
    « error_reason » : « Internal server error »
}

Le niveau 1 : Les ressources

Au niveau 1 du modèle de Richardson, la notion de ressource est introduite. Une ressource est une représentation d’un objet métier. Chaque ressource est atteignable via une URI spécifique. Tout comme au niveau 0, le verbe POST est systématiquement utilisé et le serveur envoie toujours un code HTTP 200. Requête du client :

POST http://api.nexworld.fr/v1/customers/1234/contracts
{
    « action » : « GET »
}

Réponse du serveur en cas de succès :

HTTP/1.1 200 Success
{
    « id » : « 1111 »,
    « lastname » : « Dupond »,
    « contracts » : [
        {« id » : « 123 »},
        {« id » : « 124 »}
    ]
}

Réponse du serveur en cas d’erreur :

HTTP/1.1 200 Success
{
    « error_code » : « INT_ERROR »,
    « error_reason » : « Internal server error »
}

Le niveau 2 : Les verbes et les codes HTTP

Le niveau 2 du modèle de Richardson introduit la notion de verbes et de codes HTTP.

Dans le protocole HTTP, il existe une dizaine de verbes (ou méthodes) qui représentent les actions à effectuer sur les ressources. Les plus connus et utilisés sont GET, POST, PUT, DELETE et PATCH.

En fonction du traitement de la requête, le serveur répondra avec un code HTTP différent. Il existe 5 grandes familles de code HTTP :

  • 1XX : information
  • 2XX : succès
  • 3XX : redirection
  • 4XX : erreur côté client
  • 5XX : erreur côté serveur

Requête du client :

GET http://api.nexworld.fr/v1/customers/1234/contracts

Réponse du serveur en cas de succès :

HTTP/1.1 200 Success
{
    « id » : « 1111 »,
    « lastname » : « Dupond »,
    « contracts » : [
        {« id » : « 123 »},
        {« id » : « 124 »}
    ]
}

Réponse du serveur en cas d’erreur :

HTTP/1.1 500 Internal Server Error
{
   « error_code » : « INT_ERROR »,
   « error_reason » : « Internal server error »
}

Le niveau 3 : HATEOAS

Avec le niveau 3 du modèle de Richardson, nous allons commencer à parler de HATEOAS (Hypertext As The Engine Of Application State). Que se cache-t-il derrière ce nom barbare ? Le principe HATEOAS introduit tout simplement des transitions possibles entre les différents états d’une même ressource, ainsi qu’entre les ressources elles-mêmes.

Ainsi, les requêtes sont les mêmes qu’au niveau précédent, mais les réponses sont enrichies avec des liens hypermédias qui fournissent ces fameuses transitions.

Voici un exemple.

Requête du client :

GET http://api.nexworld.fr/v1/customers/1234/contracts

Réponse du serveur en cas de succès :

HTTP/1.1 200 Success

{
   « id » : « 1111 »,
   « lastname » : « Dupond »,
   « links » : [
      
{
           
« rel » : »contract »,
           
« method » : « GET »,
           
« href » : “/contracts/123″
       
},
       
{
           
« rel » : »contract »,
           
« method » : « GET »,
           
« href » : “/contracts/124″
        
}
    
]
}

Dans cette réponse, le client récupère des liens hypermédias qui lui permet d’accéder aux contrats du customer.

Réponse du serveur en cas d’erreur :

HTTP/1.1 500 Internal Server Error
{
   « error_code »: « INT_ERROR »,
   « error_reason » : « Internal server error »
}

HATEOAS, un niveau trop peu atteint

HATEOAS est le niveau de maturité le plus important du modèle de Richardson. D’après ce modèle, une API est mature sur les principes REST si elle répond à toutes ces conditions :

  • Utilisation des ressources
  • Utilisation des codes HTTP
  • Utilisation des verbes HTTP
  • HATEOAS

Aujourd’hui, si beaucoup d’APIs respectent les 3 premiers niveaux du modèle de Richardson, une faible proportion ont atteint le dernier niveau HATEOAS. Il est intéressant de s’interroger pourquoi.

Nous allons voir dans la suite de cet article les cas d’usages où l’utilisation de HATEOAS est pertinente, ainsi que les avantages et les inconvénients à utiliser une telle implémentation dans les APIs REST.

Cas d’usages

Voici quelques exemples de cas d’usages de HATEOAS.

La pagination

Dans le cas d’une API permettant de remonter une liste d’objets, comme une liste de clients, l’utilisation d’une pagination peut s’avérer utile voir recommandée. En effet, il est possible que la liste remontée par le serveur comporte un très grand nombre d’éléments. Afin d’éviter par exemple une surcharge réseau, la pagination permet de réduire le nombre d’éléments remontés par l’API. Voici un exemple de réponse d’API mettant en place la pagination via HATEOAS.

{
    « total_items » : 166,
    « total_pages » : 83,
    « page » : 27,
    « page_size » : 2,
    « customers » : [
          {
                « id » : « 1234 »,
                « lastname » : « DUPOND »,
                « firstname » : « JEAN »
           },
          {
                « id » : « 5678 »,
                « lastname » : « DURAND »,
                « firstname » : « ANTOINE »
          }
       ],
      « links » : [
             {
                   « rel » : « first »,
                  « href » : « http://api.nexworld.fr/v1/customers?page_size={page_size}&page=1 »,
             {
                  « rel »: « next »,
                  « href »: « http://api.nexworld.fr/v1/customers?page_size={page_size}&page={page+1} »,

             {
                  « rel »: « prev »,
                  « href »: « http://api.nexworld.fr/v1/customers?page_size={page_size}&page={page-1} »,
             {
                  « rel »: « last »,
                  « href »: « http://api.nexworld.fr/v1/customers?page_size={page_size}&page={total_pages} »,
              }
        ]
}

Les liens hypermédias renvoyés dans la liste « links » permettent d’accéder au premier élément, au dernier élément, à la page suivante et la page précédente. Ces liens sont facilement utilisables par le consommateur de l’API pour naviguer dans la liste de clients.

La résolution des erreurs

En cas de requête en erreur, le serveur peut envoyer grâce à HATEOAS des informations complémentaires sur l’origine de l’erreur afin de la corriger. Imaginons une API permettant de gérer des utilisateurs. Une requête est envoyée afin de mettre à jour l’adresse de l’utilisateur 1234 :

PATCH http://api.nexworld.fr/v1/users/1234
{
          « address » : {
                   …
          }
}

Il se trouve que cet utilisateur n’est pas « activé ». Or d’un point de vue métier, il n’est pas possible de mettre à jour un utilisateur qui n’est pas encore « activé ». Le serveur, qui porte cette logique métier, va donc avertir le client de l’origine de l’erreur, et lui proposer via un lien hypermédia d’ « activer » l’utilisateur avant de mettre à jour son adresse :

{
       « error_name » : « INVALID_OPERATION »,
       « error_message » : « update to an inactive account is not         supported »,
              « links » : [
                     {
                            « href » : « http://api.nexworld.fr/v1/users/1234/activate »,
                            « rel » : « activate user »,
                            « method » : « POST »
                     }
              ]
}

Ainsi, le consommateur de l’API connaît la raison de l’erreur, et peut la corriger facilement en suivant les directives données dans les liens hypermédias.

Logique métier portée par le serveur

Dans certains contextes métiers compliqués, l’utilisation de HATEOAS permet d’éviter au consommateur de prendre en charge la logique et les processus métiers. Cela assure un couplage large entre le client et le serveur, ce qui est l’une des contraintes majeures de l’architecture REST. Prenons l’exemple d’une commande qui peut être annulée uniquement si elle est dans l’état « en cours » et non si elle est dans l’état « terminée ». Voici la requête pour récupérer les informations de la commande 1234 :

GET http://api.nexworld.fr/v1/orders/1234

Voici la réponse de l’API dans le cas où la commande 1234 est « en cours » :

HTTP/1.1 200 OK
{
            . . .
            « status » : « PENDING »,
            « links »: [
                    {
                            « rel » : « self »,
                            « href »: « http://api.nexworld.fr/v1/orders/1234 »,
                            « method » : « GET »
                    },
                    {
                            « rel » : « cancel »,
                            « href » :  » http://api.nexworld.fr/v1/orders/1234/cancel »,
                            « method » : « POST »
                    }
        ]
}

La commande 1234 est « en cours ». Conformément au processus métier, l’utilisateur peut donc la consulter ou l’annuler s’il le souhaite. Ces deux actions sont fournies par les liens hypermédias.

Voici la réponse de l’API dans le cas où la commande 1234 est « terminée » :

HTTP/1.1 200 OK
 {
            . . .
            « status » : « COMPLETED »,
            « links »: [
                    {
                            « rel » : « self »,
                            « href »: « http://api.nexworld.fr/v1/orders/1234 »,
                            « method » : « GET »
                    }
        ]
}

La commande 1234 est « terminée ». Conformément au processus métier, l’utilisateur ne peut plus l’annuler, mais il peut toujours la consulter. Le lien permettant l’annulation de la commande n’est donc plus envoyé par le serveur dans la réponse de l’API.


Traitement asynchrone

Certains traitements peuvent être traités de façon asynchrone, notamment afin d’éviter au client un temps d’attente trop long. Prenons l’exemple de l’envoi d’un mail traité de façon asynchrone :

POST http://api.nexworld.fr/v1/resources/1234/send_mail
{
    . . .
}

La réponse de l’API est la suivante :

HTTP/1.1 202 Accepted
{
    « links » : [
        {
                « href » : « http://api.nexworld.fr/v1SS/resources/1234/mail_status »,
                « rel » : « get the mail status »,
                « method » : « GET »
        }
    ]
}

Le traitement (ici l’envoi du mail) est asynchrone, mais le consommateur peut suivre le statut du traitement en appelant le lien renvoyé par l’API.


Avantages

L’utilisation du HATEOAS comporte de nombreux avantages.

Découplage client-serveur

En cas de refactorisation des URI de l’API côté serveur, les clients ne sont pas impactés, sous réserve bien entendu qu’ils utilisent les liens hypermédias fournis dans les réponses. Le client n’a plus à connaître l’ensemble des URI de l’API et les coder en « dur », mais peut les gérer de façon dynamique en utilisant les liens hypermédias. Cela permet de découpler le client du serveur.

Diminution des erreurs côté client

Le fait pour le client d’obtenir les URI de façon dynamique via des liens hypermédias permet de réduire drastiquement les erreurs de construction d’URI. En effet, beaucoup d’erreurs côté client sont dues à une mauvaise construction des URI (éléments manquants, dans le mauvaise ordre, etc…).

Logique métier portée par le serveur

Comme nous l’avons vu précédemment dans le cas d’usage de la commande qui ne peut être annulée que dans certains cas métiers, l’utilisation de HATEOAS permet au client de ne pas porter la logique métier, et laisse le serveur s’en charger.

Auto-documentation

HATEOAS permet également à l’API qui l’implémente de s’auto-documenter. Le consommateur peut découvrir les différentes possibilités de l’API en suivant les liens hypermédias. De plus, en cas de nouvelles fonctionnalités, le serveur met à jour les liens hypermédias. Toutefois, HATEOAS ne saurait en aucun cas remplacer une documentation claire et exhaustive de l’API.


Inconvénients

Toutefois, il existe également des inconvénients à l’utilisation de HATEOAS.

Un développement plus compliqué côté serveur et côté client

Intégrer des liens hypermédias dans la réponse d’une API rend son développement plus difficile. En effet, cela va dépasser la simple sérialisation/désérialisation des objets manipulés. Il va falloir prévoir toutes les transitions possibles (ou du moins le plus possible d’entre elles) entre les différents états des ressources, et avoir la capacité de les remonter au client en fonction du contexte métier.
De même, le client doit pouvoir interpréter les liens hypermédias envoyés par le serveur, en plus de la donnée utile.

Inadapté pour certaines méthodes

Nous avons vu précédemment plusieurs cas d’usages du HATEOAS. Dans ces exemples, un lien hypermédia est accompagné de trois informations :

  • Une URI (exemple : /v1/customers?page_size={page_size}&page={page+1})
  • Le verbe HTTP associé (exemple : GET)
  • Le nom de l’action (exemple : page suivante)

Il n’y a pas d’information concernant le body de la requête. En effet, renvoyer un body entraînerait un alourdissement conséquent de la réponse, tout en la rendant moins lisible.
HATEOAS est donc très adapté pour les transitions dont les requêtes ne possèdent pas de body, comme les GET par exemple. Mais avec ce type de liens hypermédias, le serveur ne peut pas remonter au client l’ensemble des transitions possibles, comme la création d’un objet par exemple, qui nécessite un body en entrée.

 

Conclusion

HATEOAS est le niveau le plus mature du modèle de Richardson. Il est indéniable que HATEOAS améliore le découplage entre le client et le serveur, et répond à de nombreux cas d’usages, comme nous l’avons vu précédemment. Il améliore également la documentation des APIs et facilite l’utilisation de l’API par le client. Pourtant malgré tous ces avantages certains, HATEOAS reste très peu répandu parmi les APIs REST.

Pourquoi un tel paradoxe ?
Premièrement, son utilisation n’est pas forcément adaptée à toutes les situations et la généraliser sans se poser de questions n’est pas forcément une bonne idée. Lors du design et de l’implémentation d’une API REST, il est nécessaire de se poser la question de la pertinence de l’utilisation de HATEOAS. Malgré ses avantages, HATEOAS doit répondre à un besoin métier, et ne pas être implémenté à tout prix.

Deuxièmement, HATEOAS augmente grandement la complexité de développement du client et du serveur. C’est ce coût supplémentaire qui reste le principal frein à sa généralisation au sein des APIs REST. Ainsi, même les géants du web comme Facebook, Google ou Amazon n’utilisent que très peu HATEOAS dans leurs APIs REST.

Nous sommes face à un cercle vicieux. Aujourd’hui, peu de clients sont capables de tirer pleinement profit d’une API REST HATEOAS. Cela implique que les développeurs d’APIs ne prennent pas nécessairement la peine d’implémenter HATEOAS, car cela a un coût (complication des développements) et ne sera sans doute pas utilisé. Mais si les clients ne sont pas adaptés au HATEOAS, c’est aussi car très peu d’APIs proposent cette fonctionnalité. Avec HATEOAS, nous sommes un peu face au serpent qui se mord la queue…

Quentin DUSSERRE

Quentin DUSSERRE

Consultant Nexworld

DÉCOUVREZ COMMENT NOTRE CABINET ACCOMPAGNERA LA TRANSFORMATION DE VOTRE ENTREPRISE

Les consultants Nexworld mettent leur expertise aux services des entreprises qui veulent accélérer leur transformation numérique. Nexworld propose des séminaires adaptés aux besoins et au SI existant de votre entreprise.

Machine Learning : comment industrialiser vos modèles ?

La Data Science, domaine prometteur qui continue de séduire de plus en plus d’entreprises, peine à être intégré dans des processus d’industrialisation. La combinaison entre donnée, algorithme, mathématiques, infrastructure technique, devOps, API, entre autres, fait...

Le site Nexworld.fr fait sa mue

Si vous lisez ces lignes, c’est que vous avez sous les yeux la nouvelle version du site de Nexworld. En cette fin d’année 2019, Nexworld a pris le parti d’adopter une approche plus créative pour ne pas dire plus COMICS de la communication corporate. Ce site est...

RPA – Quelles sont les principales offres du marché ?

Pourquoi des acteurs d’origines souvent très diverses (ceux qui ne sont pas pure players) proposent-ils aujourd’hui des offres autour de la RPA ?

Les pure players d’envergure mondiale : Comme souvent, il y a les acteurs spécialisés qu’on qualifie souvent de « pure players » lorsqu’on veut parler anglais