Je me demande comment vous implémenteriez le cas d'utilisation suivant dans REST. Est-il même possible de se passer de compromettre le modèle conceptuel?
Lisez ou mettez à jour plusieurs ressources dans le cadre d'une seule transaction. Par exemple, transférez 100 $ du compte bancaire de Bob vers le compte de John.
Pour autant que je sache, la seule façon de mettre cela en œuvre est de tricher. Vous pouvez POSTER sur la ressource associée à John ou Bob et effectuer toute l'opération en une seule transaction. En ce qui me concerne, cela rompt l'architecture REST car vous effectuez essentiellement un tunnel d'appel RPC via POST au lieu de vraiment fonctionner sur des ressources individuelles.
Il y a quelques cas importants auxquels cette question ne répond pas, ce que je trouve dommage, car elle est bien classée sur Google pour les termes de recherche :-)
Plus précisément, une bonne solution serait: Si vous POSTEZ deux fois (parce que certains cache ont eu un hoquet dans l'intermédiaire), vous ne devriez pas transférer le montant deux fois.
Pour y parvenir, vous créez une transaction en tant qu'objet. Cela peut contenir toutes les données que vous connaissez déjà et mettre la transaction en attente.
Une fois que vous avez cette transaction, vous pouvez la valider, quelque chose comme:
Notez que plusieurs put n'ont pas d'importance à ce stade; même un GET sur le txn renverrait l'état actuel. Plus précisément, le deuxième PUT détecterait que le premier était déjà dans l'état approprié, et le retournerait simplement - ou, si vous essayez de le mettre dans l'état "rolledback" après qu'il soit déjà dans l'état "commit", vous obtiendrez un erreur, et la transaction validée réelle en arrière.
Tant que vous parlez à une seule base de données ou à une base de données avec un moniteur de transactions intégré, ce mécanisme fonctionnera très bien. Vous pouvez également introduire des délais d'expiration pour les transactions, que vous pouvez même exprimer à l'aide des en-têtes Expires si vous le souhaitez.
la source
En termes REST, les ressources sont des noms sur lesquels on peut agir avec les verbes CRUD (créer / lire / mettre à jour / supprimer). Puisqu'il n'y a pas de verbe "transfert d'argent", nous devons définir une ressource "transaction" sur laquelle agir avec CRUD. Voici un exemple en HTTP + POX. La première étape consiste à CRÉER (méthode HTTP POST) une nouvelle transaction vide :
Cela renvoie un identifiant de transaction, par exemple "1234" et l'URL correspondante "/ transaction / 1234". Notez que le déclenchement de ce POST plusieurs fois ne créera pas la même transaction avec plusieurs ID et évite également l'introduction d'un état "en attente". De plus, POST ne peut pas toujours être idempotent (une exigence REST), il est donc généralement recommandé de minimiser les données dans les POST.
Vous pouvez laisser la génération d'un ID de transaction au client. Dans ce cas, vous utiliseriez POST / transaction / 1234 pour créer la transaction "1234" et le serveur renverrait une erreur si elle existait déjà. Dans la réponse d'erreur, le serveur peut renvoyer un ID actuellement inutilisé avec une URL appropriée. Ce n'est pas une bonne idée d'interroger le serveur pour un nouvel ID avec une méthode GET, car GET ne devrait jamais modifier l'état du serveur et la création / réservation d'un nouvel ID modifierait l'état du serveur.
La prochaine étape, nous UPDATE (PUT méthode HTTP) la transaction avec toutes les données, engageant implicitement:
Si une transaction avec l'ID "1234" a déjà été PUT, le serveur donne une réponse d'erreur, sinon une réponse OK et une URL pour afficher la transaction terminée.
NB: dans / account / john, "john" devrait vraiment être le numéro de compte unique de John.
la source
Excellente question, REST est principalement expliqué avec des exemples de base de données, où quelque chose est stocké, mis à jour, récupéré, supprimé. Il existe quelques exemples comme celui-ci, où le serveur est censé traiter les données d'une manière ou d'une autre. Je ne pense pas que Roy Fielding en ait inclus dans sa thèse, qui était basée sur http après tout.
Mais il parle de "transfert d'état de représentation" comme d'une machine à états, avec des liens passant à l'état suivant. De cette façon, les documents (les représentations) gardent une trace de l'état du client, au lieu que le serveur ait à le faire. De cette façon, il n'y a pas d'état du client, mais seulement en fonction du lien sur lequel vous êtes.
J'y ai réfléchi, et il me semble raisonnable que pour que le serveur traite quelque chose pour vous, lorsque vous téléchargez, le serveur crée automatiquement des ressources associées et vous donne les liens vers elles (en fait, il ne le ferait pas). pas besoin de les créer automatiquement: il pourrait simplement vous indiquer les liens, et il ne les crée que lorsque et si vous les suivez - création paresseuse). Et pour vous donner également des liens pour créer de nouvelles ressources associées - une ressource associée a le même URI mais est plus longue (ajoute un suffixe). Par exemple:
/transaction
Glitches entraînera la création de plusieurs de ces ressources, chacune avec un URI différent./transaction/1234/proposed
,/transaction/1234/committed
Ceci est similaire au fonctionnement des pages Web, la page Web finale indiquant "êtes-vous sûr de vouloir faire cela?" Cette page Web finale est elle-même une représentation de l'état de la transaction, qui comprend un lien pour passer à l'état suivant. Pas seulement des transactions financières; aussi (par exemple) prévisualiser puis valider sur wikipedia. Je suppose que la distinction dans REST est que chaque étape de la séquence d'états a un nom explicite (son URI).
Dans les transactions / ventes réelles, il existe souvent des documents physiques différents pour les différentes étapes d'une transaction (proposition, bon de commande, reçu, etc.). Encore plus pour l'achat d'une maison, avec règlement, etc.
OTOH Cela me donne l'impression de jouer avec la sémantique; Je suis mal à l'aise avec la nominalisation de la conversion des verbes en noms pour le rendre RESTful, "parce qu'il utilise des noms (URI) au lieu de verbes (appels RPC)". c'est-à-dire le nom «ressource de transaction engagée» au lieu du verbe «commettre cette transaction». Je suppose que l'un des avantages de la nominalisation est que vous pouvez faire référence à la ressource par son nom, au lieu d'avoir besoin de la spécifier d'une autre manière (comme le maintien de l'état de session, vous savez donc ce qu'est "cette" transaction ...)
Mais la question importante est: quels sont les avantages de cette approche? ie En quoi ce style REST est-il meilleur que le style RPC? Une technique idéale pour les pages Web est-elle également utile pour le traitement des informations, au-delà du stockage / récupération / mise à jour / suppression? Je pense que le principal avantage de REST est l'évolutivité; un aspect de cela est de ne pas avoir besoin de maintenir explicitement l'état du client (mais de le rendre implicite dans l'URI de la ressource, et les états suivants comme liens dans sa représentation). En ce sens, cela aide. Peut-être que cela aide aussi à la stratification / pipelining? OTOH, seul un utilisateur examinera sa transaction spécifique, il n'y a donc aucun avantage à la mettre en cache pour que les autres puissent la lire, ce qui est un gros avantage pour http.
la source
Si vous prenez du recul pour résumer la discussion ici, il est assez clair que REST n'est pas approprié pour de nombreuses API, en particulier lorsque l'interaction client-serveur est intrinsèquement avec état, comme c'est le cas pour les transactions non triviales. Pourquoi sauter à travers tous les obstacles suggérés, tant pour le client que pour le serveur, afin de suivre pédantiquement un principe qui ne correspond pas au problème? Un meilleur principe est de donner au client le moyen le plus simple, le plus naturel et le plus productif de composer avec l'application.
En résumé, si vous effectuez vraiment beaucoup de transactions (types, pas d'instances) dans votre application, vous ne devriez vraiment pas créer une API RESTful.
la source
Je me suis éloigné de ce sujet pendant 10 ans. Pour revenir, je ne peux pas croire que la religion se déguise en science dans laquelle vous vous aventurez lorsque vous google rest + fiable. La confusion est mythique.
Je diviserais cette vaste question en trois:
Ceci est important car cela permet à toutes les requêtes suivantes d'être totalement idempotentes, en ce sens que si elles sont répétées n fois, elles renvoient le même résultat et ne font plus rien. Le serveur stocke toutes les réponses par rapport à l'ID d'action, et s'il voit la même demande, il relit la même réponse. Un traitement plus complet du modèle est dans ce document google . Le document suggère une implémentation qui, je crois (!), Suit largement les principes REST. Les experts me diront sûrement en quoi cela viole les autres. Ce modèle peut être utilement utilisé pour tout appel non sécurisé à votre service Web, qu'il y ait ou non des transactions en aval.
Votre exigence est fondamentale. Ne laissez pas les gens vous dire que votre solution n'est pas casher. Jugez leurs architectures en fonction de leur capacité et de leur simplicité à résoudre votre problème.
la source
Vous auriez à rouler votre propre type de gestion tx "transaction id". Donc ce serait 4 appels:
Vous devrez gérer le stockage des actions dans une base de données (si la charge est équilibrée) ou en mémoire ou autre, puis gérer la validation, la restauration, le délai d'expiration.
Pas vraiment une journée de repos dans le parc.
la source
Je pense que dans ce cas, il est tout à fait acceptable de casser la pure théorie de REST dans cette situation. Dans tous les cas, je ne pense pas qu'il y ait quoi que ce soit dans REST qui dise que vous ne pouvez pas toucher les objets dépendants dans les analyses de rentabilisation qui le nécessitent.
Je pense vraiment que cela ne vaut pas les obstacles supplémentaires que vous feriez pour créer un gestionnaire de transactions personnalisé, alors que vous pourriez simplement utiliser la base de données pour le faire.
la source
Tout d'abord, transférer de l'argent n'est rien que vous ne pouvez pas faire en un seul appel de ressource. L'action que vous voulez faire est d'envoyer de l'argent. Vous ajoutez donc une ressource de transfert d'argent au compte de l'expéditeur.
Terminé. Vous n'avez pas besoin de savoir que c'est une transaction qui doit être atomique, etc. Vous transférez simplement de l'argent aka. envoyer de l'argent de A à B.
Mais pour les rares cas, voici une solution générale:
Si vous voulez faire quelque chose de très complexe impliquant de nombreuses ressources dans un contexte défini avec de nombreuses restrictions qui franchissent en fait la barrière du quoi par rapport au pourquoi (connaissances métier ou implémentation), vous devez transférer l'état. Étant donné que REST doit être sans état, vous, en tant que client, devez transférer l'état.
Si vous transférez l'état, vous devez masquer les informations à l'intérieur du client. Le client ne doit pas connaître les informations internes uniquement nécessaires à la mise en œuvre mais ne porte pas d'informations pertinentes en termes d'affaires. Si ces informations n'ont aucune valeur commerciale, l'état doit être chiffré et une métaphore comme un jeton, un laissez-passer ou quelque chose doit être utilisée.
De cette façon, on peut transmettre l'état interne et en utilisant le cryptage et la signature, le système peut toujours être sécurisé et sain. Trouver la bonne abstraction pour le client pourquoi il transmet des informations d'état est quelque chose qui dépend de la conception et de l'architecture.
La vraie solution:
N'oubliez pas que REST parle de HTTP et HTTP est livré avec le concept d'utilisation de cookies. Ces cookies sont souvent oubliés lorsque les gens parlent de l'API REST et des flux de travail et interactions couvrant plusieurs ressources ou demandes.
Rappelez-vous ce qui est écrit sur Wikipédia à propos des cookies HTTP:
Donc, fondamentalement, si vous avez besoin de transmettre un état, utilisez un cookie. Il est conçu exactement pour la même raison, c'est HTTP et donc il est compatible avec REST de par sa conception :).
La meilleure solution:
Si vous parlez d'un client exécutant un workflow impliquant plusieurs requêtes, vous parlez généralement de protocole. Chaque forme de protocole est livrée avec un ensemble de conditions préalables pour chaque étape potentielle, comme effectuer l'étape A avant de pouvoir faire B.
C'est naturel, mais exposer le protocole aux clients rend tout plus complexe. Pour éviter cela, pensez simplement à ce que nous faisons lorsque nous devons faire des interactions complexes et des choses dans le monde réel .... Nous utilisons un agent.
En utilisant la métaphore de l'agent, vous pouvez fournir une ressource qui peut effectuer toutes les étapes nécessaires pour vous et stocker la mission / les instructions réelles sur lesquelles elle agit dans sa liste (afin que nous puissions utiliser POST sur l'agent ou une «agence»).
Un exemple complexe:
Acheter une maison:
Vous devez prouver votre crédibilité (comme fournir les entrées de votre casier judiciaire), vous devez vous assurer des détails financiers, vous devez acheter la maison réelle en utilisant un avocat et un tiers de confiance qui stocke les fonds, vérifier que la maison vous appartient maintenant et ajoutez les articles d'achat à vos dossiers fiscaux, etc. (à titre d'exemple, certaines étapes peuvent être erronées ou autre).
Ces étapes peuvent prendre plusieurs jours, certaines peuvent être effectuées en parallèle, etc.
Pour ce faire, vous donnez simplement à l'agent la tâche d'acheter une maison comme:
Terminé. L'agence vous renvoie une référence que vous pouvez utiliser pour voir et suivre l'état de ce travail et le reste est fait automatiquement par les agents de l'agence.
Pensez à un bug tracker par exemple. En gros, vous signalez le bogue et pouvez utiliser l'identifiant du bogue pour vérifier ce qui se passe. Vous pouvez même utiliser un service pour écouter les modifications de cette ressource. Mission terminée.
la source
Vous ne devez pas utiliser de transactions côté serveur dans REST.
L'une des contraintes REST:
Le seul moyen REST est de créer un journal de rétablissement des transactions et de le mettre à l'état client. Avec les demandes, le client envoie le journal de rétablissement et le serveur refait la transaction et
Mais il est peut-être plus simple d'utiliser une technologie basée sur la session serveur qui prend en charge les transactions côté serveur.
la source
Je pense que ce serait le cas d'utiliser un identifiant unique généré sur le client pour s'assurer que le hoquet de connexion n'implique pas une duplicité sauvegardée par l'API.
Je pense qu'utiliser un champ GUID généré par le client avec l'objet de transfert et s'assurer que le même GUID n'est pas réinséré à nouveau serait une solution plus simple au problème du virement bancaire.
Je ne connais pas les scénarios plus complexes, tels que la réservation de billets d'avion multiples ou les micro-architectures.
J'ai trouvé un article sur le sujet, relatant les expériences de gestion de l'atomicité des transactions dans les services RESTful .
la source
Dans le cas simple (sans ressources distribuées), vous pouvez considérer la transaction comme une ressource, où l'acte de la créer atteint l'objectif final.
Donc, pour transférer entre
<url-base>/account/a
et<url-base>/account/b
, vous pouvez publier ce qui suit sur<url-base>/transfer
.Cela créerait une nouvelle ressource de transfert et renverrait la nouvelle URL du transfert - par exemple
<url-base>/transfer/256
.Au moment de la publication réussie, la transaction «réelle» est alors effectuée sur le serveur, et le montant est retiré d'un compte et ajouté à un autre.
Ceci, cependant, ne couvre pas une transaction distribuée (si, disons 'a' est détenu dans une banque derrière un service, et 'b' est détenu dans une autre banque derrière un autre service) - autre que de dire "essayez de tout formuler des opérations qui ne nécessitent pas de transactions distribuées »
la source
Je suppose que vous pouvez inclure le TAN dans l'URL / la ressource:
Juste une idée.
la source