Arrêter une machine virtuelle via une interface REST
Il s'agit en fait d'un exemple quelque peu célèbre, présenté par Tim Bray en 2009 .
Roy Fielding, discutant du problème, a partagé cette observation :
Personnellement, je préfère les systèmes qui traitent l'état surveillé (comme l'état de l'alimentation) comme non modifiable.
En bref, vous disposez d'une ressource d'informations qui renvoie une représentation actuelle de l'état surveillé; cette représentation peut inclure un lien hypermédia vers un formulaire qui demande une modification de cet état, et le formulaire a un autre lien vers une ressource pour gérer (chaque) demande de modification.
Seth Ladd avait les idées clés du problème
Nous avons transformé Running d'un simple état de personne à un vrai nom qui peut être créé, mis à jour et commenté.
Reprenant cela pour redémarrer les machines. Je dirais que vous POSTERIEZ à / vdc / 434 / cluster / 4894 / server / 4343 / reboots Une fois que vous avez publié, vous avez un URI qui représente ce redémarrage, et vous pouvez l'obtenir pour les mises à jour de statut. Grâce à la magie de l'hyperlien, la représentation du redémarrage est liée au serveur qui est redémarré.
Je pense que frapper l'espace URI est bon marché, et les URI sont encore moins chers. Créez une collection d'activités, modélisées sous forme de noms, et affichez, publiez et supprimez!
La programmation RESTful est la bureaucratie de Vogon à l'échelle du Web. Comment faites-vous quoi que ce soit RESTful? Inventez-lui de nouveaux documents et numérisez-les.
Dans un langage un peu plus sophistiqué, vous définissez le protocole d'application de domaine pour «arrêter une machine virtuelle» et identifiez les ressources dont vous avez besoin pour exposer / implémenter ce protocole.
Regarder vos propres exemples
PATCH /api/virtualmachines/42
Content-Type:application/json
{ "state": "shutting down" }
C'est bon; vous ne traitez pas vraiment la demande elle-même comme une ressource d'informations distincte, mais vous pouvez toujours la gérer.
Vous avez manqué un peu dans votre représentation du changement.
Avec PATCH, cependant, l'entité incluse contient un ensemble d'instructions décrivant comment une ressource résidant actuellement sur le serveur d'origine doit être modifiée pour produire une nouvelle version.
Par exemple, les instructions de formatage du type de support JSON Patch comme si vous modifiiez directement un document JSON
[
{ "op": "replace", "path": "state", "value": "shutting down" }
]
Dans votre alternative, l'idée est proche, mais pas évidemment correcte. PUT
est un remplacement complet de l'état de la ressource à l'URL cible , donc vous ne choisiriez probablement pas une orthographe qui ressemble à une collection comme cible d'une représentation d'une seule entité.
POST /api/virtualmachines/42/actions
Est cohérent avec la fiction selon laquelle nous ajoutons une action à une file d'attente
PUT /api/virtualmachines/42/latestAction
Est conforme à la fiction selon laquelle nous effectuons une mise à jour de l'élément de queue dans la file d'attente; c'est un peu bizarre de le faire de cette façon. Le principe de la moindre surprise recommande de donner à chaque PUT son propre identifiant unique, plutôt que de les mettre tous au même endroit et de modifier plusieurs ressources en même temps.
Notez que, dans la mesure où nous discutons de l'orthographe de l'URI - REST s'en fiche; /cc719e3a-c772-48ee-b0e6-09b4e7abbf8b
est un URI parfaitement cromulent en ce qui concerne REST. La lisibilité, comme pour les noms de variables, est une préoccupation distincte. L'utilisation d'orthographes conformes à la RFC 3986 rendra les gens beaucoup plus heureux.
CQRS
Que se passe-t-il si nous avons un domaine CQRS avec de nombreuses "actions" (commandes aka) qui pourraient potentiellement conduire à des mises à jour de plusieurs agrégats ou ne peuvent pas être mappées aux opérations CRUD sur des ressources et sous-ressources concrètes?
Greg Young sur CQRS
CQRS est un modèle très simple qui offre de nombreuses possibilités d'architecture qui autrement n'existeraient pas. Le CQRS n'est pas une cohérence éventuelle, ce n'est pas un événement, ce n'est pas de la messagerie, il n'a pas de modèles séparés pour la lecture et l'écriture, ni il n'utilise la recherche d'événements.
Lorsque la plupart des gens parlent de CQRS, ils parlent vraiment d'appliquer le modèle CQRS à l'objet qui représente la limite de service de l'application.
Étant donné que vous parlez de CQRS dans le contexte de HTTP / REST, il semble raisonnable de supposer que vous travaillez dans ce dernier contexte, alors allons-y.
Étonnamment, celui-ci est encore plus facile que votre exemple précédent. La raison en est simple: les commandes sont des messages .
Jim Webber décrit HTTP comme le protocole d'application d'un bureau des années 50; le travail se fait en prenant des messages et en les mettant dans des boîtes de réception. La même idée tient - nous obtenons une copie vierge d'un formulaire, le remplissons avec les détails que nous connaissons, le livrons. Ta da
Devrions-nous essayer de modéliser autant de commandes que le béton crée ou met à jour sur des ressources concrètes, dans la mesure du possible (en suivant la première approche de l'exemple I) et utiliser des «points de terminaison d'action» pour le reste?
Oui, dans la mesure où les «ressources concrètes» sont des messages, plutôt que des entités dans le modèle de domaine.
Idée clé: votre API REST est toujours une interface ; vous devriez pouvoir changer le modèle sous-jacent sans que les clients n'aient besoin de changer les messages. Lorsque vous publiez un nouveau modèle, vous publiez une nouvelle version de vos points de terminaison Web qui savent comment prendre votre protocole de domaine et l'appliquer au nouveau modèle.
Un modèle CQRS est-il mieux adapté à une API de type RPC?
Pas vraiment - en particulier, les caches Web sont un excellent exemple d'un «modèle de lecture finalement cohérent». Rendre chacune de vos vues adressable indépendamment, chacune avec ses propres règles de mise en cache, vous donne un tas de mise à l'échelle gratuitement. Il y a relativement peu d'intérêt pour une approche exclusivement RPC des lectures.
Pour les écritures, c'est une question plus délicate: envoyer toutes les commandes à un seul gestionnaire à un seul point de terminaison, ou à une seule famille de points de terminaison, est certainement plus facile . REST est vraiment plus sur la façon dont vous trouvez communiquer où le point de terminaison est au client.
Le traitement d'un message comme sa propre ressource unique présente l'avantage que vous pouvez utiliser PUT, alertant les composants intermédiaires du fait que la gestion du message est idempotente, afin qu'ils puissent participer dans certains cas de gestion des erreurs, c'est une bonne chose d'avoir . (Remarque: du point de vue des clients, si les ressources ont des URI différents, alors ce sont des ressources différentes; le fait qu'ils peuvent tous avoir le même code de gestionnaire de requêtes sur le serveur d'origine est un détail d'implémentation caché par l'uniforme interface).
Fielding (2008)
Je dois également noter que ce qui précède n'est pas encore pleinement RESTful, du moins comment j'utilise le terme. Tout ce que j'ai fait est décrit les interfaces de service, qui ne sont pas plus que n'importe quel RPC. Afin de le rendre RESTful, j'aurais besoin d'ajouter un hypertexte pour introduire et définir le service, décrire comment effectuer le mappage à l'aide de formulaires et / ou de modèles de lien, et fournir du code pour combiner les visualisations de manière utile.