Publié par
Il y a 8 années · 8 minutes · Back

REST : Richardson Maturity Model

Le modèle de maturité de Richardson (Richardson Maturity Model) est un modèle qui décompose l’approche REST en trois étapes qui introduisent progressivement les principaux éléments de REST (Ressources ; Verbes et Codes retours HTTP ; Contrôles hypermédia) pour passer d’un modèle RPC sur HTTP à un modèle RESTFul.

Ce modèle a été développé par Léonard Richardson. Léonard Richardson est, entre autres, co-auteur du livre « Restful Web Service » publié chez O’Reilly.
Martin Fowler a récemment publié un papier à propos du Modèle de Maturité de Richardson intitulé « Richardson Maturity Model: steps toward the glory of REST ». Dans ce papier, Martin Fowler déroule et commente le Richardson Maturity Model au travers d’un cas d’utilisation simple (réserver un rendez-vous chez le médecin).

Ce billet présente le Richardson Maturity Model en s’appuyant en grande partie sur le papier de Martin Fowler. Au programme :

Le niveau 0 : Le RPC sur HTTP en POX

A ce niveau, qui constitue le point de départ du modèle, on ne peut pas vraiment parler de REST : on se contente d’utiliser HTTP comme système de transport pour interagir à distance avec un « service ».
Toutes les requêtes sont envoyées vers le même endpoint (la même URI) : /appointmentService. Elles sont complètement décrites dans le flux XML envoyé. Dans l’exemple proposé par Martin Fowler, la réservation se fait de la façon suivante :

Une première requête est envoyée pour obtenir les créneaux disponibles à une date donnée :

POST /appointmentService HTTP/1.1
[various other headers]

Le serveur retourne une liste de créneaux :
HTTP/1.1 200 OK
[various headers]

  
    
  
  
    
  

Une deuxième requête est envoyée (sur le même endpoint) pour réserver un des créneaux de la liste :

POST /appointmentService HTTP/1.1
[various other headers]

  
  

Si la demande aboutit, le serveur retourne un rendez-vous :

HTTP/1.1 200 OK
[various headers]

  
  

Si la demande échoue, le serveur retourne un message d’erreur :

HTTP/1.1 200 OK
[various headers]

  
  
  Slot not available

Vous noterez l’incongruité d’une réponse 200 OK en cas d’erreur (nous y reviendrons).

Cette approche revient à mettre en place un simple système RPC (Remote Procédure Call). Elle met en œuvre les mêmes mécanismes que SOAP ou XML-RPC, mais en s’affranchissant des enveloppes inhérentes à ces mécanismes. Les messages échangés sont du POX (Plain Old XML).

Le niveau 1 : l’utilisation de ressources différenciées

Dans le Richardson Maturity Model, le premier pas vers l’utilisation de REST consiste à introduire la notion de ressource. Ce qui est somme toute assez logique, puisque REST est un modèle d’architecture basé sur la manipulation de ressources (tout est ressource).
Ainsi, là où au niveau 0, toutes les requêtes étaient faites vers un unique endpoint (une unique URI), au niveau 1, les requêtes sont envoyées à des ressources individuelles : dans l’exemple de Martin Fowler, des médecins et des créneaux.

La première requête (pour demander les créneaux disponibles) se fait vers l’URI d’une ressource de type médecin :

POST /doctors/mjones HTTP/1.1
[various other headers]

La requête étant faite sur un médecin (une ressource) particulier, le flux XML ne spécifie plus cette information.

La réponse du serveur est en substance la même, mais elle fournit maintenant pour chaque créneau un identifiant de ressource : chaque créneau est maintenant une ressource qui peut être requêtée individuellement :

HTTP/1.1 200 OK
[various headers]

  
  

La requête de réservation d’un créneau se fait maintenant sur la ressource idoine :

POST /slots/1234 HTTP/1.1
[various other headers]

  

La réponse renvoyée par le serveur est la même qu’au niveau 0.

Au niveau 1, l’introduction des ressources nous permet de gérer la complexité de notre système (de notre API de réservation) par l’approche « divide & conquer » : nous avons éclaté un service en plusieurs ressources.

Le niveau 2 : L’utilisation des verbes et des codes retours HTTP

La deuxième étape de l’approche prônée par le Richardson Maturity Model est d’introduire l’utilisation des verbes et des codes retours HTTP. Dans REST, les ressources sont manipulées au travers d’un jeu de verbes simples. Le plus souvent les verbes HTTP pour la simple et bonne raison que la majeure partie des implémentations REST se fait sur HTTP.

L’idée est de tirer parti du protocole sur lequel nous nous appuyons. Ainsi, au niveau 2, Martin Fowler déroule son exemple de la façon suivante :

La première requête (pour demander les créneaux disponibles) se fait en utilisant une requête GET (et non plus POST) :

GET /doctors/mjones/slots?date=20100104&status=open HTTP/1.1
Host: royalhope.nhs.uk

La réponse à cette requête est la même qu’au niveau 1.

Pour rappel, HTTP définit GET comme une opération « sécurisée » qui n’induit aucun changement d’état côté serveur. Cette particularité présente deux avantages :

  • Les requêtes GET peuvent être invoquées autant de fois qu’on le souhaite dans n’importe quel ordre : la réponse à une requête sera toujours la même (sauf bien sûr si l’état de la ressource a été modifié par ailleurs).
  • Les résultats des requêtes GET peuvent être mis en cache par les différents équipements intervenant dans la chaîne de routage de la requête (dans un système comme celui de l’exemple déroulé par Martin Folwer, il conviendra évidement de régler correctement le « cache timeout »).

La requête de réservation d’un créneau est la même qu’au niveau 1 (en POST).

Les réponses retournées par le serveur sont les mêmes qu’au niveau 1 à l’exception du code retour utilisé :

  • Si la demande aboutie, le serveur retourne un code 201 Created : ce code réponse indique clairement qu’une nouvelle ressource a été créée. L’URI de cette ressource est contenue dans la réponse : Location : slots/1234/appointment (la ressource elle-même, dans sa représentation XML, est également retournée afin d’éviter une requête supplémentaire au client). L’indication fournie par le code retour est plus riche qu’avec un simple 200 OK.
HTTP/1.1 201 Created
Location: slots/1234/appointment
[various headers]

  
  

  • Si la demande échoue, le serveur retourne un code 409 Conflict : ce code réponse indique clairement que la requête n’a pas aboutit en raison d’un conflit (le créneau est déjà réservé). L’utilisation d’un code en 4XX a ici beaucoup plus de sens que celle du 200 OK qui devient fallacieuse quand on retourne une erreur.
HTTP/1.1 409 Conflict
[various headers]

  

Au niveau 2, l’utilisation des verbes et codes retours standards de HTTP nous permet de tirer pleinement parti du protocole sur lequel nous nous appuyons (« By following the rules of HTTP we’re able to take advantage of that capability. »).
Cette approche nous permet également d’éliminer les variantes dans la façon de traiter les choses et ainsi, de gérer des cas similaires de façon semblable dans l’ensemble de notre API.

A propos de l’utilisation des standards HTTP, Martin Fowler soulève un point très intéressant. Comme il l’explique, les partisans de REST poussent à l’utilisation de l’ensemble des verbes HTTP (ce qui permet de disposer d’une sémantique CRUD). Or, un argument souvent avancé est que le modèle REST a fait ses preuves à très grande échelle : internet est construit sur une architecture REST. En effet, cet argument est inattaquable quand il s’agit d’utiliser POST et GET, mais il devient beaucoup plus discutable quand on parle de l’utilisation des verbes PUT et DELETE.

Le niveau 3 : L’utilisation des contrôles hypermédia

Le troisième et dernier niveau du Richardson Maturity Model introduit la notion de HATEOAS (Hypertext As The Engine Of Application State). Derrière cet acronyme barbare se cache un principe simple : les transitions possibles vers les états suivants sont fournies par des liens hypermédia.

Les requêtes sont les mêmes qu’au niveau 2, mais les réponses sont ici enrichies avec, pour chaque ressource, un élément link fournissant l’URI permettant de la manipuler.
Ainsi, dans l’exemple de Martin Fowler, la réponse à la requête de demande de créneaux libres est :

HTTP/1.1 200 OK
[various headers]

  
     
  
  
     
  

Et la réponse à la requête de réservation d’un créneau est :

HTTP/1.1 201 Created
Location: slots/1234/appointment
[various headers]

  
  
  
  
  
  
  
  

Le premier avantage de l’utilisation des contrôles hypermédia est que les développeurs côté serveur peuvent refactorer les URI d’accès à l’API sans impacter les clients (pour autant que les clients utilisent les URI fournies par les éléments link).

D’autre part, l’utilisation des contrôles hypermédia permet d’auto-documenter l’API REST. Même si cette approche ne suffit pas à documenter complètement l’API, elle fournit un premier niveau d’information :

  • Elle aide les utilisateurs de l’API REST (les développeurs de clients) à explorer ses capacités : chaque réponse indique ce qu’il est possible de faire après en indiquant les ressources manipulables (on notera que les éléments link ne fournissent pas d’indication sur les verbes utilisables).
  • Elle permet aux développeurs de l’API de communiquer sur les nouvelles fonctionnalités en ajoutant de nouveaux éléments link dans les réponses.

Perspectives

Le Richardson Maturity Model propose un fil conducteur permettant d’appréhender pas à pas les concepts sous-jacents à une approche RESTFul :

  • Niveau 1 : Gérer la complexité de notre système via l’approche « divide & conquer » en introduisant la notion de ressource.
  • Niveau 2 : Eliminer les variantes dans la façon de traiter les choses et de gérer des cas similaires de façon semblable en introduisant un jeu de verbes standards pour manipuler les ressources.
  • Niveau 3 : Auto-documenter le protocole et fournir un premier niveau de découvrabilité au travers de la notion de HATEOAS.

Le Richardson Maturity Model fournit aussi un biais intéressant pour évaluer la « RESTitude » d’une architecture.

3 thoughts on “REST : Richardson Maturity Model”

  1. Publié par Jocelyn, Il y a 8 années

    Merci pour cet excellent résumé.
    Je me pose toutefois une question. Je ne comprends pas la phrase suivante: « En effet, cet argument est inattaquable quand il s’agit d’utiliser POST et GET, mais il devient beaucoup plus discutable quand on parle de l’utilisation des verbes PUT et DELETE. »
    Quels arguments appuient cette déclaration ? Le simple fait que ces opérations sont très peu utilisées n’en est pas un à mon avis. Alors quoi d’autre ?

  2. Publié par Christophe Heubès, Il y a 8 années

    Jocelyn,

    Le propos n’est pas ici de remettre en cause l’utilisation des opérations PUT et DELETE. En effet, même si certains discutent de leur caractère obligatoire dans l’achèvement d’un système RESTFul (GET and POST are RESTful enough), leur mise en œuvre apporte de nombreux avantages dont ceux liés à l’utilisation du standard HTTP.

    La remarque porte sur un argument très souvent avancé par les promoteurs / défenseurs de REST : « REST a fait ses preuves à très grande échelle puisqu’Internet est construit sur une architecture REST. ». Cet argument choc, est plus difficilement discutable dans le cadre de l’utilisation de PUT et de DELETE qui sont très peu utilisés (donc pas à très grande échelle comme le sont GET et POST).

  3. Publié par Dominique De Vito, Il y a 7 années

    imho, une des causes possibles d’un problème lié à l’utilisation des opérations PUT et DELETE réside dans l’utilisation des pare-feux qui peuvent être (fréquemment ?) configurés pour ne pas laisser ces opérations PUT et DELETE… inconnues au bataillon pour le plus grand nombre.

  4. Publié par Bruno GACEL, Il y a 10 mois

    De plus, il y a une ambiguité pour PUT, puisque cette opération réalise une mise à jour si la données est présente et une création si elle n’existe pas. C’est un écart par rapport à la normalisation restfull.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *