Il y a 13 ans -
Temps de lecture 8 minutes
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 (Plain Old XML).
- Le niveau 1 : L’utilisation de ressources différentiées.
- Le niveau 2 : L’utilisation des verbes et des codes retours HTTP.
- Le niveau 3 : L’utilisation des contrôles hypermédia.
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 simple200 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 en4XX
a ici beaucoup plus de sens que celle du200 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]uri = "slots/1234"/> uri = "slots/5678"/>
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.
Commentaire
5 réponses pour " REST : Richardson Maturity Model "
Published by Jocelyn , Il y a 13 ans
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 ?
Published by Christophe Heubès , Il y a 13 ans
Jocelyn,
Le propos n’est pas ici de remettre en cause l’utilisation des opérations
PUT
etDELETE
. 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 deDELETE
qui sont très peu utilisés (donc pas à très grande échelle comme le sontGET
etPOST
).Published by Dominique De Vito , Il y a 13 ans
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.
Published by Bruno GACEL , Il y a 6 ans
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.
Published by Axel Rousseau , Il y a 5 ans
Les valeurs en XML des requêtes ou des réponses ne s’affichent pas sur la page (car interprété comme des balises)
(excellent article au demeurant ;-) …)