Transactions dans REST?

147

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.

Gili
la source

Réponses:

91

Considérez un scénario de panier d'achat RESTful. Le panier est conceptuellement votre emballage de transaction. De la même manière que vous pouvez ajouter plusieurs articles à un panier, puis soumettre ce panier pour traiter la commande, vous pouvez ajouter l'entrée de compte de Bob à l'encapsuleur de transaction, puis l'entrée de compte de Bill dans l'encapsuleur. Lorsque toutes les pièces sont en place, vous pouvez POST / METTRE le wrapper de transaction avec tous les composants.

Darrel Miller
la source
18
Pourquoi TransferMoneyTransaction ne serait-elle pas une ressource bancaire viable?
Darrel Miller le
8
Si vous vous assurez que vos points de terminaison font référence à des noms, il est généralement intuitif ce que les verbes standard GET, PUT, POST, DELETE feront à ce nom. RPC permet aux points de terminaison d'être eux-mêmes des verbes et, par conséquent, ils peuvent entrer en conflit avec les verbes HTTP et l'intention devient confuse.
Darrel Miller le
10
Par exemple, que se passe-t-il si vous effectuez un SUPPRESSION HTTP sur le point final UpdateXYZ? Supprime-t-il XYZ? Supprime-t-il la mise à jour ou fait-il simplement une mise à jour et ignore la suppression du verbe HTTP. En gardant les verbes hors du point final, vous supprimez la confusion.
Darrel Miller le
5
Et qu'en est-il des transactions sur plusieurs services? et qu'en est-il lorsque vous souhaitez effectuer un ensemble de modifications «non liées» que le service n'expose aucun conteneur de transaction implicite. De plus, pourquoi avoir un type de transaction spécifique lorsque nous sommes déplacés vers des transactions à usage général qui ne sont absolument pas liées à vos données réelles changements. Les transactions peuvent ne pas correspondre au repos, mais il semble que les transactions devraient être superposées, sans rapport avec les autres appels, à part le fait que les en-têtes de demande contiendraient une référence de transaction.
meandmycode
4
Les transactions de la base de données @meandmycode doivent être superposées derrière une interface REST. Vous pouvez également exposer une transaction commerciale (pas une transaction de base de données) en tant que ressource en soi, puis vous devez prendre des mesures de compensation en cas d'échec.
Darrel Miller
60

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.

POST /transfer/txn
{"source":"john's account", "destination":"bob's account", "amount":10}

{"id":"/transfer/txn/12345", "state":"pending", "source":...}

Une fois que vous avez cette transaction, vous pouvez la valider, quelque chose comme:

PUT /transfer/txn/12345
{"id":"/transfer/txn/12345", "state":"committed", ...}

{"id":"/transfer/txn/12345", "state":"committed", ...}

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.

Jon Watte
la source
Discussion intéressante! Je voudrais ajouter que le message initial doit être effectué en une seule étape. Il ne peut pas être ajouté plus tard (alors nous sommes dans le territoire des paniers d'achat et les paniers d'achat ont de nombreux freins et contrepoids pour les empêcher de nuire à l'utilisateur final, même la législation, les virements bancaires ne le font pas) ...
Erk
33

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 :

POST /transaction

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:

PUT /transaction/1234
<transaction>
  <from>/account/john</from>
  <to>/account/bob</to>
  <amount>100</amount>
</transaction>

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.

Tuckster
la source
4
Assimiler REST à CRUD est une grave erreur. POST ne signifie pas nécessairement CRÉER.
12
Une grave erreur? Je sais qu'il existe des différences entre PUT et POST, mais il y a un mappage lâche vers CRUD. "Sérieusement"?
Ted Johnson
3
Oui, vraiment. CRUD est un moyen de structurer le stockage des données; REST est un moyen de structurer le flux de données d'application. Vous pouvez faire CRUD sur REST, mais vous ne pouvez pas faire REST sur CRUD. Ils ne sont pas équivalents.
Jon Watte
20

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:

  1. Vous téléchargez ( POST ) la représentation du concept de transaction avec toutes les informations. Cela ressemble à un appel RPC, mais cela crée vraiment la "ressource de transaction proposée". Par exemple, URI: /transaction Glitches entraînera la création de plusieurs de ces ressources, chacune avec un URI différent.
  2. La réponse du serveur indique l'URI de la ressource créée, sa représentation - cela inclut le lien ( URI ) pour créer la ressource associée d' une nouvelle "ressource de transaction validée". D'autres ressources associées sont le lien pour supprimer la transaction proposée. Ce sont des états dans la machine à états, que le client peut suivre. Logiquement, ceux-ci font partie de la ressource qui a été créée sur le serveur, au-delà des informations fournies par le client. par exemple URIs: /transaction/1234/proposed, /transaction/1234/committed
  3. Vous POSTEZ sur le lien pour créer la "ressource de transaction validée" , qui crée cette ressource, en modifiant l'état du serveur (les soldes des deux comptes) **. De par sa nature, cette ressource ne peut être créée qu'une seule fois et ne peut pas être mise à jour. Par conséquent, les problèmes de validation de nombreuses transactions ne peuvent pas se produire.
  4. Vous pouvez OBTENIR ces deux ressources, pour voir quel est leur état. En supposant qu'un POST peut modifier d'autres ressources, la proposition serait désormais signalée comme "validée" (ou peut-être pas disponible du tout).

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.

13ren
la source
Pourriez-vous expliquer comment "ne pas avoir besoin de conserver l'état sur le client" contribue à l'évolutivité? Quel type d'évolutivité? Évolutivité dans quel sens?
jhegedus
11

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.

Péris
la source
9
D'accord, mais quelle devrait être une alternative en cas d'architecture de micro-services distribués?
Vitamon le
11

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:

  • Services en aval. Tout service Web que vous développez aura des services en aval que vous utilisez et dont vous n'avez d'autre choix que de suivre la syntaxe de transaction. Vous devez essayer de cacher tout cela aux utilisateurs de votre service et vous assurer que toutes les parties de votre opération réussissent ou échouent en tant que groupe, puis renvoyez ce résultat à vos utilisateurs.
  • Vos services. Les clients veulent des résultats sans ambiguïté pour les appels de service Web, et le modèle REST habituel consistant à faire des demandes POST, PUT ou DELETE directement sur des ressources substantielles me semble être un moyen médiocre et facilement amélioré de fournir cette certitude. Si vous vous souciez de la fiabilité, vous devez identifier les demandes d'action. Cet identifiant peut être un guid créé sur le client, ou une valeur de départ d'une base de données relationnelle sur le serveur, cela n'a pas d'importance. Pour les identifiants générés par le serveur, utilisez une demande-réponse 'Preflight' pour échanger l'identifiant de l'action. Si cette demande échoue ou réussit à moitié, pas de problème, le client ne fait que répéter la demande. Les identifiants inutilisés ne font aucun mal.

    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.
  • Intégration de votre service dans des «transactions» contrôlées par des services en amont. Dans le contexte des services Web, les transactions ACID complètes sont généralement considérées comme ne valant pas la peine, mais vous pouvez grandement aider les consommateurs de votre service en fournissant des liens d'annulation et / ou de confirmation dans votre réponse de confirmation, et ainsi réaliser des transactions par compensation .

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.

bbsimonbb
la source
9

Vous auriez à rouler votre propre type de gestion tx "transaction id". Donc ce serait 4 appels:

http://service/transaction (some sort of tx request)
http://service/bankaccount/bob (give tx id)
http://service/bankaccount/john (give tx id)
http://service/transaction (request to commit)

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.

TheSoftwareJedi
la source
4
Je ne pense pas que ce soit une illustration particulièrement bonne. Vous n'avez besoin que de deux étapes: Créer une transaction (crée une transaction à l'état "en attente") et Valider la transaction (valide si elle n'est pas validée et déplace la ressource vers l'état validée ou annulée).
Jon Watte
2

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.

Toby Hede
la source
2

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.

POST: accounts/alice, new Transfer {target:"BOB", abmount:100, currency:"CHF"}.

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:

Les cookies ont été conçus pour être un mécanisme fiable permettant aux sites Web de mémoriser des informations avec état (tels que des éléments dans un panier) ou d'enregistrer l'activité de navigation de l'utilisateur (y compris en cliquant sur des boutons particuliers, en se connectant ou en enregistrant les pages visitées par l'utilisateur jusqu'à présent. il y a des mois ou des années).

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:

POST: agency.com/ { task: "buy house", target:"link:toHouse", credibilities:"IamMe"}.

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.

Martin Kersten
la source
1

Vous ne devez pas utiliser de transactions côté serveur dans REST.

L'une des contraintes REST:

Apatride

La communication client-serveur est en outre limitée par le fait qu'aucun contexte client n'est stocké sur le serveur entre les demandes. Chaque demande d'un client contient toutes les informations nécessaires pour traiter la demande, et tout état de session est conservé dans le client.

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

  1. annule la transaction mais fournit un nouveau journal de rétablissement de transaction (une étape de plus)
  2. ou enfin terminer la transaction.

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.

bebbo
la source
Le devis provient de l'entrée REST de wikipedia. Est-ce la vraie source ou est-ce que Wikipédia l'a obtenu de quelque part? Qui doit dire quel est le contexte client et quel contexte serveur?
bbsimonbb
1

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 .

Eduardo Rolim
la source
0

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/aet <url-base>/account/b, vous pouvez publier ce qui suit sur <url-base>/transfer.

<transfert>
    <from> <url-base> / compte / a </from>
    <to> <url-base> / account / b </to>
    <amount> 50 </amount>
</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 »

Phasmal
la source
2
Si vous ne pouvez pas «formuler toutes les opérations d'une manière qui ne nécessite pas de transactions distribuées», alors vous avez vraiment besoin d'une validation en deux phases. La meilleure idée que j'ai pu trouver pour implémenter un commit en deux phases sur REST est rest.blueoxen.net/cgi-bin/wiki.pl?TwoPhaseCommit , qui ne gâche surtout pas l'espace de noms d'URL et permet de superposer un commit en deux phases nettoyer la sémantique REST.
Phasmal
3
L'autre problème avec cette suggestion est que, si un cache hoquet et POST deux fois, vous obtenez deux transferts.
Jon Watte
Certes, dans ce cas, vous auriez besoin d'un processus en deux étapes - créez une ressource de «transfert» avec une URL unique, puis ajoutez-y les détails du transfert dans le cadre de la validation (deux parties comme mentionné dans les autres réponses). Bien entendu, cela pourrait alors être formulé comme créant une ressource "transaction" puis en y ajoutant une opération "transfert".
Phasmal du
-3

Je suppose que vous pouvez inclure le TAN dans l'URL / la ressource:

  1. PUT / transaction pour obtenir l'ID (par exemple "1")
  2. [PUT, GET, POST, peu importe] / 1 / account / bob
  3. [PUT, GET, POST, peu importe] / 1 / compte / facture
  4. SUPPRIMER / transaction avec ID 1

Juste une idée.

Till
la source
Je vois deux problèmes avec cette approche: 1) Cela implique que vous ne pouvez pas accéder à une ressource en dehors d'une transaction (bien que ce ne soit peut-être pas un gros problème). 2) Aucune des réponses jusqu'à présent n'a abordé le fait que le serveur n'est plus apatride, même si je soupçonne que rien ne peut être fait à ce sujet.
Gili le
Eh bien, / 1 / account / bob et / account / bob ne sont que deux ressources différentes. :) Et RE: sans état, cela implique que la ressource est toujours disponible et non dépendante d'une demande précédente. Puisque vous avez demandé des transactions, oui ce n'est pas le cas. Mais là encore, vous vouliez des transactions.
Jusqu'au
1
Si un client doit assembler des URI, votre API n'est pas RESTful.
aehlke
1
Je ne peux pas vous comprendre, vraiment! Si vous traitez une transaction comme une ressource (comme dans l'exemple ci-dessus), vous arrêtez simplement de traiter la transaction dans le sens classique du terme et l'utilisez "de la manière REST appropriée", ce qui simplifie encore la programmation des processus transactionnels. Vous pouvez par exemple inclure un href à la transaction dans vos réponses pour contourner le déplacement dans un environnement distribué côté serveur, il est toujours sans état (c'est juste une ressource, n'est-ce pas?) Et vous pouvez implémenter le mécanisme de transaction réel de toute façon vous voulez (et si vous n'avez pas de DB à l'arrière?)
Matthias Hryniszak
1
D'une manière ou d'une autre, si vous arrêtez simplement de penser à SQL / SOAP et que vous commencez à penser HTTP (comme le fait le navigateur), tout devient simple
Matthias Hryniszak