Je suis tombé sur la conception Event Sourcing et j'aimerais l'utiliser dans une application où un client REST est nécessaire (RESTful pour être précis). Cependant, je ne parviens pas à les connecter ensemble car REST est assez similaire à CRUD et la recherche d'événements est basée sur les tâches. Je me demandais comment pouvez-vous concevoir la création de commandes basées sur des demandes au serveur REST. Considérez cet exemple:
Avec REST, vous pouvez mettre un nouvel état dans la ressource appelée Fichier. Dans une demande, vous pouvez envoyer un nouveau nom de fichier, vous pouvez changer le dossier parent et / ou changer le propriétaire du fichier et ainsi de suite.
Comment construire le serveur pour pouvoir utiliser le sourcing d'événements. Je pensais à ces possibilités:
Déterminer le serveur quels champs ont été modifiés et de créer des commandes appropriées (
RenameFileCommand
,MoveFileCommand
,ChangeOwnerCommand
, ...) et l' expédition de ces individuellement. Cependant, dans cette configuration, chacune des commandes peut échouer, laissant les autres hors de la transaction et donc hors du changement "atomique" de la ressource.Dispatch une seule commande (
UpdateFileCommand
) et dans le gestionnaire de commande, plus précisément dans l'ensemble, déterminer quels champs ont été modifiés et envoyer des événements individuels au lieu (FileRenamedEvent
,FileMovedEvent
,OwnerChangedEvent
, ...)Celui-ci je n'aime pas du tout: dans la demande au serveur, je spécifierais dans les en-têtes la commande à utiliser, car l'interface utilisateur est toujours basée sur les tâches (mais la communication se fait via REST). Cependant, il échouera dans toute autre utilisation de la communication REST (par exemple dans des applications externes) car ils ne sont pas tenus de modifier uniquement le seul champ dans une demande. J'apporte également un assez grand couplage dans l'interface utilisateur, REST et ES.
Laquelle préférez-vous ou existe-t-il une meilleure façon de gérer cela?
Note latérale: application écrite en Java et Axon Framework pour le sourcing d'événements.
Réponses:
Je pense que vous pouvez avoir un processus utilisateur à la discordance d'implémentation ici.
Premièrement: un utilisateur voudra-t-il honnêtement effectuer plusieurs modifications simultanément sur un fichier? Un changement de nom (qui peut ou non inclure un changement de chemin?), Un changement de propriétaire et peut-être un changement de contenu de fichier (par souci d'argument) semblent être des actions distinctes.
Prenons le cas où la réponse est "oui" - vos utilisateurs veulent vraiment faire ces changements simultanément.
Dans ce cas, je vous recommande fortement contre toute mise en œuvre qui envoie plusieurs événements -
RenameFileCommand
,MoveFileCommand
,ChangeOwnerCommand
- pour représenter cette seule intention de l' utilisateur.Pourquoi? Parce que les événements peuvent échouer. C'est peut-être extrêmement rare, mais votre utilisateur a soumis une opération qui semblait atomique - si un seul des événements en aval échoue, l'état de votre application n'est plus valide.
Vous invitez également les dangers de la course sur une ressource qui est clairement partagée entre chacun des gestionnaires d'événements. Vous devrez écrire "ChangeOwnerCommand" de telle manière que le nom de fichier et le chemin d'accès au fichier n'aient pas d'importance, car ils pourraient être obsolètes au moment de la réception de la commande.
Lors de la mise en œuvre d'un système reposant non piloté par des événements avec déplacement et renommage de fichiers, je préfère garantir la cohérence en utilisant quelque chose comme un système eTag - assurez-vous que la version de la ressource en cours de modification est la version que l'utilisateur a récupérée en dernier, et échoue si elle a été modifié depuis. Mais si vous envoyez plusieurs commandes pour cette opération à utilisateur unique, vous devrez incrémenter la version de votre ressource après chaque commande - vous n'avez donc aucun moyen de savoir que la ressource que l'utilisateur modifie est vraiment la même version que la ressource qu'il a lue en dernier. .
Ce que je veux dire par là, c'est que si quelqu'un d'autre effectue une autre opération sur le fichier presque en même temps. Les 6 commandes peuvent s'empiler dans n'importe quel ordre. Si nous n'avions que 2 commandes atomiques, la commande précédente pourrait réussir et la commande suivante pourrait échouer "la ressource a été modifiée depuis sa dernière récupération". Mais il n'y a aucune protection contre cela lorsque les commandes ne sont pas atomiques, donc la cohérence du système est violée.
Fait intéressant, il existe un mouvement vers quelque chose comme une architecture basée sur les événements dans REST, appelée "Rest without PUT", recommandée dans le radar de la technologie Thoughtworks, janvier 2015 . Il y a un blog considérablement plus long sur Rest without PUT ici .
Essentiellement, l'idée est que POST, PUT, DELETE et GET conviennent parfaitement aux petites applications, mais lorsque vous devez commencer à supposer que put, post et delete peuvent être interprétés à l'autre extrémité, vous introduisez le couplage. (par exemple "quand JE SUPPRIME la ressource associée à mon compte bancaire, le compte doit être fermé") Et la solution proposée est de traiter REST de manière plus sourcée par l'événement. ie permet de POSTER l'intention de l'utilisateur en tant que ressource d'événement unique.
L'autre cas est plus simple. Si vos utilisateurs ne veulent pas effectuer toutes ces opérations simultanément, ne les laissez pas. POSTER un événement pour chaque intention d'utilisateur. Vous pouvez maintenant utiliser le contrôle de version etag sur vos ressources.
Quant aux autres applications qui utilisent une API très différente de vos ressources. Ça sent le trouble. Pouvez-vous construire une façade de l'ancienne API au-dessus de votre API RESTful et les pointer vers la façade? c'est-à-dire exposer un service qui effectue plusieurs mises à jour d'un fichier en séquence via le serveur REST?
Si vous ne créez pas l'interface RESTful au-dessus de l'ancienne solution, ni ne construisez une façade de l'ancienne interface au-dessus de la solution REST, et essayez de maintenir les deux API pointant vers une ressource de données partagée, vous rencontrerez des maux de tête majeurs.
la source
Tout à l'heure, je suis tombé sur l'article suivant, qui encourage à spécifier les noms de commande dans la demande au serveur dans l'en-tête Content-Type (tout en suivant 5 niveaux de type de support).
Dans l'article, ils mentionnent que le style RPC est mauvais pour REST et suggèrent d'étendre Content-Type pour spécifier le nom de la commande:
L'article est ici: http://www.infoq.com/articles/rest-api-on-cqrs
Vous pouvez en savoir plus sur 5 niveaux de type de média ici: http://byterot.blogspot.co.uk/2012/12/5-levels-of-media-type-rest-csds.html
Bien qu'ils exposent les événements de domaine à l'API REST, ce que je considérerais comme une mauvaise pratique, j'aime la solution car elle ne crée pas un nouveau "protocole" uniquement pour CQRS, que ce soit en envoyant des noms de commande dans le corps ou en extra et reste fidèle aux principes RESTful.
la source