★ L'architecture orientée ressource pour faire des services web RESTful

Le plus gros défaut de REST, c'est sûrement de se limiter à la comparaison des 4 verbes HTTP (GET, POST, PUT et DELETE) aux 4 actions possibles sur des données issues de bases de données (Retrieve, Create, Update et Delete soit CRUD mais j'ai laissé dans l'ordre de la comparaison). Et le pire, c'est que je suis tombé dans ce « piège » dans mon précédent billet sur REST (même si c'était une traduction), il est temps de parler plus en détail des possibilités offertes par une telle architecture.

Préambule

Pour être tout à fait honnête, ce billet est grandement inspiré du chapitre 4 du livre RESTful WebServices, document que vous pourrez librement télécharger sur l'article présentant une interview des auteurs. Ce livre est comparé à celui du Gang Of Four en terme d'impact donc il faut absolument que je me le procure car ce chapitre m'a clairement mis l'eau à la bouche ! Il y a même un chapitre qui parle de REST dans Django :-).

Christian a fait une excellente note d'introduction à l'enjeu de cet ouvrage si vous souhaitez avoir une version plus « haut niveau ».

La terminologie architecture orientée ressource est presque une pure création des auteurs, il s'agit de préciser certains points de l'architecture REST afin d'en avoir la même interprétation pour tous. Ce sont surtout des règles ou bonnes pratiques de REST appliquées au domaine des services web (qui peuvent être transgressées si l'on en comprend bien les tenants et les aboutissants). Ces règles me semblent essentielles pour ne pas dériver vers du STREST 2.0, ce qui est bien trop souvent le cas...

Enfin l'utilisation du terme architecture orientée ressource permet justement de se différencier du terme REST qui est utilisé aujourd'hui un peu à tort et à travers. L'architecture REST étant très vague, les différentes interprétations sont à l'origine de véritables guerres entre extrêmistes que les auteurs ne cautionnent pas. Voici donc les 4 concepts et les 4 propriétés décrivant une architecture orientée ressource :

Concepts

Les ressources

Une ressource est quelque chose d'assez important pour être référencé comme étant une chose en elle-même.

En énonçant cela, on a à la fois tout dit et rien dit ! Donc plongeons un peu plus dans le détail avec un extrait du W3C, si vous souhaitez :

créer un lien hypertexte vers elle, faire ou réfuter des affirmations à son sujet, rechercher ou mettre en mémoire cache une représentation la concernant, l'inclure en partie ou dans son ensemble en la référençant dans une autre représentation, l'annoter ou encore effectuer d'autres opérations

alors vous devez créer une ressource. Une ressource peut donc être un objet physique ou un concept abstrait.

Leurs noms (URI)

Mais pour qu'une ressource soit connue, il faut qu'elle soit accessible et pour ça on a créé les URI qui sont à la fois le nom et l'adresse d'une ressource, sans URI pas de ressource.

C'est ce qui fait la force du Web (HTTP), et ce qui lui a permis d'écraser une bonne partie des autres protocoles. Aujourd'hui tout passe par ce protocole au détriment des autres, on télécharge via un navigateur et non un client FTP par exemple.

L'un des points importants de l'architecture orientée ressource est qu'une URI doit être descriptive. On doit savoir ce qui se cache derrière une URI rien qu'en la lisant, par exemple en allant sur http://www.biologeek.com/liens/ vous savez que vous allez accéder à une page listant des liens. On peut même aller jusqu'à prédire et donc construire des URI, ce à quoi je me suis attaché dans ma refonte, pour pouvoir par exemple construire http://www.biologeek.com/python,django,rest/ si je souhaite avoir tous les billets formant l'intersection de ces thèmes.

Enfin un mot sur la relation URI/ressource : une ressource doit au moins avoir une URI mais rien n'empêche une ressource d'avoir plusieurs URI. C'est néanmoins déconseillé pour deux raisons :

  • la dilution de l'information (bon il y a aussi le problème du duplicate content de google...) ;
  • la possible incompréhension du « visiteur » (est-ce vraiment la même ressource ?).

Leurs représentations

Le découpage en ressources est conceptuel, une ressource n'est pas une donnée. Il faut donc représenter cette ressource sous format informatique pour qu'elle soit consultable, cette représentation peut avoir différents formats (html ou json par exemple).

Ce qui est recommandé en termes d'architecture orientée ressource est de faire figurer les informations de représentation au sein de l'URI. Alors bien sûr ça va faire bondir ceux qui connaissent les headers permettant justement de préciser ce type d'information sous forme de méta-données mais les auteurs avancent deux arguments qui me semblent pertinents :

  • sur le plan humain, lorsqu'on donne une URI à quelqu'un, on souhaite qu'il ait la même représentation de la ressource que nous ;
  • sur le plan machine, les robots (comme le validateur du W3C ou les crawlers) ne vont pas pouvoir tester/répertorier l'ensemble de vos représentations.

Les liens entre elles

Les représentations ne contiennent bien souvent pas seulement des données mais aussi des liens vers d'autres ressources. L'axiome issu de la thèse de Roy Fielding :

l'hypermédia comme moteur de l'état de l’application

Résume bien le fait que nous naviguons sur internet grâce aux liens entre les ressources. Que votre page d'accueil soit un moteur de recherche ou celle de votre FAI préféré, ce n'est qu'un point d'entrée pour aller consulter des ressources. Sans ces outils d'agrégation que de temps gagné pour arrêter de geeker perdu à chercher les ressources nécessaires...

Propriétés

À adresse

Une application à adresses doit pouvoir présenter les aspects intéressants de son jeu de données sous la forme de ressources.

Comme les ressources sont identifiées par leurs URI, ça consiste généralement à fournir une liste d'URI possibles. Celles-ci pouvant être infinies comme par exemple dans le cas de Google : http://www.google.fr/search?q=* où * peut être remplacé par n'importe quel mot-clé, par exemple http://www.google.fr/search?q=rest . Grâce à cette propriété, on peut indiquer une adresse à quelqu'un sans lui dire : va sur google.fr et tape « rest » dans le formulaire.

C'est le gros problème des applications web 2.0 actuelles qui utilisent AJAX, elles ne sont pas toujours à adresses. En fait ces services sont souvent déjà des clients de services web RESTful. Par exemple dans le cas de GMail, http://mail.google.com/mail/ est le client et http://mail.google.com/mail/?ui=html est le service web qui vous permet de donner une adresse de recherche dans les mails par exemple (ce qui serait impossible avec la version client/AJAX). La perte des adresses dans de telles applications est problématique et il devrait toujours être possible d'avoir le lien direct vers les ressources présentées (puisqu'il n'est pas possible de changer l'adresse du navigateur en JavaScript, excepté les ancres).

Sans état

Chaque requête HTTP doit s'exécuter sans avoir connaissance des requêtes précédentes ou suivantes. C'est l'une des propriétés clés de l'architecture orientée ressource qui permet par exemple de ne pas casser le bouton « Reculer d'une page » du navigateur. Chaque nouvelle page affichée contient toutes les informations nécessaires pour afficher la ressource appropriée ou effectuer les traitements nécessaires, les requêtes ne doivent pas avoir d'ordre pré-défini et sont déconnectées les unes des autres.

De cette façon, le serveur n'a jamais besoin de connaître l'état du client, il ne sait même pas où il est, il sait juste qu'une requête arrivant avec tels paramètres doit restituer telles données. C'est un réel avantage lorsque vous fournissez un tel service car vous pouvez mettre des requêtes en cache de manière performante ou jouer avec du load-balancing sans avoir à vous soucier de ce qu'il se passe sur les autres serveurs.

Les cookies et les sessions sont les deux possibilités habituelles pour casser une telle architecture. Leur utilisation donne au serveur la possibilité de connaître l'état de ses différents clients ce qui va par exemple modifier la représentation d'une ressource selon le client qui va l'afficher. C'est une grave violation de l'architecture orientée ressource.

Mais de quel état parle-t-on ? Celui de l'application ou celui de la ressource ?

Il faut avant tout distinguer l'état de l'application, qui est dépendante du client, et l'état de la ressource, qui est dépendante du serveur. Un service web ne doit prendre en compte l'état de votre application qu'au moment de la requête et vous devez donc envoyer toutes les informations nécessaires à ce moment là. L'état d'une ressource est le même pour toutes les requêtes.

Prenons un exemple assez insidieux, celui des clés d'API. Si votre clé ne vous permet d'effectuer qu'un nombre limité de requêtes (comme c'est le cas pour celle de Google), alors c'est un état du client. Vous allez pouvoir effectuer les 1000 premières requêtes mais la 1001ème ne sera pas possible, c'est donc différent selon le client.

Connecté

Cette propriété est directement issue du concept des liens évoqué ci-dessus. Les ressources doivent s'inter-lier dans leurs représentations respectives. Si l'on prend le service S3 d'Amazon par exemple, les ressources sont accessible via un service RESTful mais elles ne sont pas connectées.

J'ai par exemple l'habitude de dire qu'un billet de blog sans liens est une impasse, je trouve que cette image illustre parfaitement cette propriété.

À interface uniforme

Et cette interface provient des verbes HTTP, je ne vais pas reprendre en détail ce que j'ai déjà expliqué dans le précédent billet sur REST mais plutôt revenir sur des points de détails qui ont leur importance. Si l'on considère les 4 verbes les plus intéressants, bref rappel tout de même :

  • GET permet de récupérer une représentation d'une ressource ;
  • POST de créer une ressource ;
  • PUT de mettre une ressource à jour ;
  • DELETE de supprimer la ressource.

Avec une remarque concernant la création d'une ressource, il est aussi possible d'utiliser PUT si l'on connaît l'URI finale de la ressource. Généralement POST est utilisé car l'on peut difficilement connaître l'id sous lequel la ressource va être enregistrée par le serveur par exemple et cet id se retrouve souvent dans l'URI de la ressource.

Autre remarque concernant cette fois POST, il est possible d'ajouter des données à une ressource via ce verbe. Un bon exemple est celui d'une ressource de type log, comment faire pour ajouter une entrée à la fin de /log/ ? La sémantique de POST permet d'ajouter une nouvelle ligne comme si cela était une nouvelle ressource de type particulier (qui ne possède pas forcément d'URI...).

Enfin les auteurs distinguent le POST(a) d'ajout qui est celui correspondant à l'architecture REST et le POST(o) surchargé (overloaded) qui est celui utilisé par les navigateurs et qui ne permet pas de différencier les différents verbes possibles (POST, PUT ou DELETE). Je trouve que c'est une bonne nomenclature et j'aurais l'occasion de la réutiliser ici.

Il existe aussi les verbes HEAD et OPTIONS qui peuvent vous être utiles :

  • HEAD : permet de récupérer uniquement les méta-données ;
  • OPTIONS : permet de connaître les verbes autorisés pour une URI donnée.

Enfin concernant l'interface uniforme, deux propriétés à ne pas oublier :

  • la sûreté : lorsque les verbes GET ou HEAD sont employés, c'est pour lire des données et il ne doit donc y avoir aucun changement d'état au niveau du serveur. C'est la raison principale pour laquelle les boutons d'un formulaire sont si moches reconnaissables, l'utilisateur doit être averti lorsqu'il risque de modifier des données sur le serveur. Un bon exemple des problèmes que cela peut engendrer est le client Web Accelerator que Google avait lancé en 2005 et qui devait précharger les pages suivantes possibles (accessibles en GET) pour les afficher plus rapidement. Si tous les sites avaient respecté cette propriété, il n'y aurait pas eu des milliers de comptes/mails/etc effacés... résultat, cet outil a été un flop ;
  • l'idempotence : traduit en REST, il s'agit de pouvoir répéter une requête plusieurs fois sans que cela ait de conséquences. Imaginons un billet de blog, je peux faire autant de GET que je veux dessus sans que ça pose problème, pareil pour PUT puisque nous avons vu que toutes les informations doivent être envoyées à chaque requête selon la propriété sans état plus haut. Dans le cas de DELETE, je vais aussi pouvoir répéter plusieurs fois la même opération aussi, la première supprimera effectivement la ressource, les suivantes pourront m'informer que cela a déjà été fait mais je pourrais les faire. Le véritable problème de l'idempotence intervient lors des POST. Plusieurs mécanismes de confirmation existent mais ça sera sûrement pour un prochain billet :-).

Conclusion

J'espère que ce billet vous aura permis de comprendre un peu mieux les règles qui régissent une architecture REST et par extension une architecture orientée ressource. Il ne s'agit pas de la nouvelle architecture 2.0 hype du moment mais bien du Web passé, actuel et futur donc en le comprenant vous pourrez construire des sites et des applications web mieux pensées et cohérentes. Vous gagnerez en interopérabilité mais aussi en temps de développement puisque votre API sera la même pour votre propre client et pour les utilisateurs qui souhaitent développer des applications tierces. Une fois les concepts et les propriétés assimilés, il n'y a vraiment que des avantages à utiliser une telle architecture.

— 29/06/2007

Articles peut-être en rapport

Commentaires

Gilles le 30/06/2007 :

Alors là, chapeau ! Rien à dire. Excellent article. C'est de l'excellent. Très très intéressant, très très bien décrit. C'est du David quoi :) Vraiment merci et bravo. Bon week-end à toi !

Eric Daspet le 30/06/2007 :

> une URI doit être descriptive

Ca n'est pas une contrainte ou même une recommandation de l'architecture orientée ressource. Du point de vue du navigateur, du serveur, et de la ressource, l'URL est un composant opaque. Cette URL n'est pas "comprise", elle n'a pas à être descriptive.

Si l'URL doit être descriptive, c'est uniquement un effet de bord de son positionnement actuel dans les interfaces des navigateurs. On a mis l'URL comme un composant central, accessible et éditable par l'utilisateur. De fait, du coup, l'URL s'échange sous format texte et mérite à être descriptive.

Dans l'idéal l'humain n'a pas à lire l'URL, il n'a pas à la manipuler. Tout ce qu'il a à faire c'est la stocker (par exemple dans ses favoris), l'échanger et la rappeler. Vu notre monde, le stockage est ou va devenir tout électronique (favoris du navigateur, clé usb, téléphone portable). On devrait pouvoir donc à terme se passer de l'URL descriptive : le dispositif électronique nous présentera le titre de la page, la description texte qu'on y a accolé, le site source ... l'URL n'a plus aucun intérêt du point de vue humain. Même chose pour l'échange. On va y arriver très vite avec les QR Code des téléphones portables.

Bref, l'URL descriptive est encore nécessaire dans nos pays (ça doit être moins vrai là où le QR Code est développé) mais ça n'est pas lié à l'architecture RESTE, à HTTP ou au Web. C'est juste une problématique d'interface utilisateur qui mérite d'évoluer (et qui le fera à moyen terme).

David, biologeek le 30/06/2007 :

@Gilles : Merci ! Bon we à toi aussi :-).

@Eric Daspet : je suis d'accord avec le fait que les URL n'ont pas été faites pour les humains mais force est de constater que c'est rentré dans les mœurs et (presque) tout le monde comprend à peu près ce que ça signifie, principalement grâce au nom donné.

Du coup, je ne pense pas qu'elles disparaissent de si tôt des interfaces utilisateurs car on n'a pas encore trouvé mieux... remarque on pourrait presque faire un parallèle entre la ligne de commande et les adresses web et celles-ci on presque disparues donc je m'avance un peu.

Je pense que l'indexation a pris le dessus sur le stockage. Aujourd'hui pour retrouver un favori je cherche pas souvent dans les centaines que j'ai, je le retrouve avec des mots-clés sur un moteur de recherche. C'est d'ailleurs ce qui donne tant (trop !) de puissance aux moteurs de recherche, ils nous guident un peu là où ils ont envie...

syntax_error le 01/07/2007 :

La description des principes est claire, mais j'avoue que j'ai pas compris à quoi ca correspond concrètement en termes de développement. A part éviter les cookies et les sessions, et avoir des urls claires ca manque d'exemples concrets, de modèles ou de comparaisons.

D'après ce que j'en retire l'idée est que chaque requête doit pouvoir s'exécuter indépendament de tout contexte. Cela semble plus un principe qu'une méthode.

Stéphane Bortzmeyer le 01/07/2007 :

> j'avoue que j'ai pas compris à quoi ca correspond concrètement en
> termes de développement

J'espère que le petit exemple qui est ici :

www.bortzmeyer.org/progra...

aidera. Il est tout petit mais fait partie d'un vrai logiciel de gestion de registre (CODEV-NIC).

> A part éviter les cookies et les sessions, et avoir des urls claires

C'est déjà pas mal si on fait tout ça !

David, biologeek le 01/07/2007 :

@syntax_error : patience les exemples arrivent ;-).

@Stéphane Bortzmeyer : merci pour le lien.

Olivier le 16/07/2007 :

Bonjour

Merci pour cet article qui m'a permis de clarifier certaines choses. Je suis un lecteur assidu de ce blog et cette fois-ci, je me lance à rédiger un commentaire ...

Je suis entièrement convaincu du bien fondé et des avantages de cette architecture, mais n'y-a-t-il pas qq soucis concernant la réalisation concrète de "grosses applications", je pense en particulier aux performances (reconstituer l'état complet d'un gros système à chaque requête) ... ou encore à la longueur des URLS ...
Pour le REST ;-) , je suis convaincu qu'il n'y aura bientôt plus de "grosses applications" mais simplement une miriade de petites discutant entre elles ... mais en attendant ...

Merci pour la mine d'info pertinente qu'est ce blog et vivement cette refonte :-)

David, biologeek le 16/07/2007 :

@Olivier : il ne faut surtout pas être si timide ;-).

> n'y-a-t-il pas qq soucis concernant la réalisation concrète de "grosses applications", je pense en particulier aux performances (reconstituer l'état complet d'un gros système à chaque requête) ...

Au niveau des performances, cela ne change rien si ce n'est qu'une application utilisant cette architecture peut reposer sur le cache HTTP qui a fait ses preuves jusqu'à présent (donc il n'y a pas forcément processing à chaque requête). Il est vrai que les exemples d'applications complexes RESTful sont rares pour l'instant mais mon petit doigt me dit que cela ne va pas durer.

> ou encore à la longueur des URLS ...

Une URL peut être très longue www.boutell.com/newfaq/mi... mais si l'on considère des imbrications de ressources vraiment importantes (mais alors là on en arriverait à une complexité énorme) ça pourrait en effet poser problème. Pour l'instant je suis jamais arrivé à plus de 6 ressources imbriquées et c'était pour des workflows bien complexes.

REST n'est donc pas forcément limité aux petites applications même si tous les exemples restent basiques. C'est juste pour expliquer le principe mais on peut faire des choses beaucoup plus attrayantes avec ;-).

Sebmox le 17/07/2007 :

Pour info, le livre mentionné au début par David sort en septembre en version française...
www.oreilly.fr/catalogue/...

Sinon très très bon article !!

Graffiti le 18/07/2007 :

L'url sert (encore un anagrame de rest) aussi pour le référencement... :) on a tendance à l'oublier

Stéphane Bortzmeyer le 25/07/2007 :

Puisque certains ont été assez indulgents pour apprécier mon premier court article (moins bon que celui de David mais avec plus de code), voici un second :

www.bortzmeyer.org/rest-s...

Nicolas Hoizey le 28/11/2007 :

Excellent article, qui me confirme que nous sommes de plus en plus nombreux à utiliser cette architecture, bravo !!!

Juste une précision, sans doute non nécessaire pour la plupart des lecteurs, mais bon :

Tu dis « il n'est pas possible de changer l'adresse du navigateur en JavaScript, excepté les ancres ».

Il faudrait sans doute modifier ça en « il n'est pas possible de changer l'adresse du navigateur en JavaScript sans provoquer le rechargement de la page, excepté pour les ancres ».

David, biologeek le 28/11/2007 :

@Nicolas Hoizey : En effet, bonne précision mais JavaScript est souvent utilisé pour palier justement au rechargement de la page actuellement.

Nicolas Hoizey le 28/11/2007 :

Je suis d'accord, je soulignais juste une imprécision pouvant conduire un lecteur à croire une erreur... ;-)

étudiant blogueur le 25/11/2008 :

je pense qu'il y a erreur dans ce qui suit :
html ou json par exemple
vous voulez dire peut être :
html ou js (javascript) par exemple

David, biologeek le 25/11/2008 :

Non, je parlais bien du format de représentation de données JSON :
http://fr.wikipedia.org/wiki/JavaScript_Object_Notation

Il est lié à la base à JavaScript mais ce n'est pas une erreur de ma part :-)

étudiant blogueur le 26/11/2008 :

Ok c'est noté cher blogueur. Même si je suis développeur je n'y avais jamais entendu parlé.
PS: wikipedia a déjà accumulé $3 000 000 :-0
Merci :)

nfroidure le 02/10/2010 :

Bonjour,

Petit commentaire en réaction à la partie "Sans état".

Pour un service web qui serait, pour sa majeure partie, accessible de manière privée, les sessions ou cookies me paraissent inévitables.

Il y a peut-être la possibilité de distinguer une ressource privée en signifiant dans l'URI qu'elle est privée. Sur twitter ça donnerai ça :
http://twitter.com/private/nfroidure/settings/account
au lieu de :
http://twitter.com/settings/account

Quelles sont les pratiques en la matière pour gérée les droits d'accès sur une application RESTful ?

Merci