tags:

views:

1489

answers:

6

I'm wondering how you'd implement the following use-case in REST. Is it even possible to do without compromising the conceptual model?

Read or update multiple resources within the scope of a single transaction. For example, transfer $100 from Bob's bank account into John's account.

As far as I can tell, the only way to implement this is by cheating. You could POST to the resource associated with either John or Bob and carry out the entire operation using a single transaction. As far as I'm concerned this breaks the REST architecture because you're essentially tunneling an RPC call through POST instead of really operating on individual resources.

+6  A: 

You'd have to roll your own "transaction id" type of tx management. So it would be 4 calls:

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)

You'd have to handle the storing of the actions in a DB (if load balanced) or in memory or such, then handling commit, rollback, timeout.

Not really a RESTful day in the park.

TheSoftwareJedi
Ouch :) Thanks for the reply nonetheless...
Gili
A: 

I guess you could include the TAN in the URL/resource:

  1. PUT /transaction to get the ID (e.g. "1")
  2. [PUT, GET, POST, whatever] /1/account/bob
  3. [PUT, GET, POST, whatever] /1/account/bill
  4. DELETE /transaction with ID 1

Just an idea.

Till
I see two problems with this approach:1) It implies you can't access a resource outside a transaction (though maybe this isn't a big deal).2) None of the answers so far has touched upon the fact that the server is no longer stateless, though I suspect nothing can be done about that.
Gili
Well, /1/account/bob and /account/bob are just two different resources. :) And RE: stateless, it implies that the resource is always available and not dependent on a previous request. Since you asked for transactions, yes that is not the case. But then again, you wanted transactions.
Till
If a client has to assemble URIs, then your API is not RESTful.
Wahnfrieden
I can't understand you guys, really! If you treat a transaction as a resource (like in the example above) you simply stop treating transaction in the classical sense and utilize it in "the proper REST way" which further simplifies programming transactional processes. You can for example include an href to the transaction in your responses to go around the displacement in distributed server-side environment, it's still stateless (it's just a resource, isn't it?) and you can implement the actual transaction mechanism anyway you want (what if you don't have a DB in the back?)
Matthias Hryniszak
One way or the other if you simply stop thinking SQL/SOAP and start thinking HTTP (like the browser does) everything becomes simple
Matthias Hryniszak
+10  A: 

Consider a RESTful shopping basket scenario. The shopping basket is conceptually your transaction wrapper. In the same way that you can add multiple items to a shopping basket and then submit that basket to process the order, you can add Bob's account entry to the transaction wrapper and then Bill's account entry to the wrapper. When all the pieces are in place then you can POST/PUT the transaction wrapper with all the component pieces.

Darrel Miller
I get the shopping basket example, but how when you generalize this it doesn't sound RESTful at all (you're not operating on resources). There is no realistic bank-related resource to wrap John and Bob.Good answer though! I feel like you're definitely moving in the right direction.
Gili
Why would TransferMoneyTransaction not be a viable banking resource?
Darrel Miller
I thought a resource was supposed to be a real-life object, not a service (i.e. method invocation). If you're able to make up resources that mimic services then how is REST any different from RPC?
Gili
If your ensure that your endpoints refer to nouns then it is usually intuitive what the standard GET, PUT, POST, DELETE verbs will do to that noun. RPC allows endpoints to be verbs themselves and therefore they can conflict with the HTTP verbs and the intent becomes confusing.
Darrel Miller
e.g. What happens if you do an HTTP DELETE on the endpoint UpdateXYZ ? Does it delete XYZ? Does it delete the Update or does it just do an Update and ignore the HTTP verb delete. By keeping verbs out of the endpoint you remove the confusion.
Darrel Miller
And what about transactions across multiple services? and what about when you want to do a set of 'unrelated' changes that the service exposes no implicit transaction container.. plus, why have a specific transaction type when we're moved to general purpose transactions that are completely unrelated to your actual data changes. Transactions might not match restful, but it seems like transactions should be layered ontop, unrelated to the rest calls apart from the fact the request headers would contain a transaction reference.
meandmycode
@meandmycode Database transactions should be layered behind a REST interface. Alternately you can expose a business transactions (not a database transaction) as a resource in itself and then you need to take compensating action in case of failure.
Darrel Miller
this isnt what i mean.. scenario: i want to add an album to my catalog, and an artist to my artists catalog (with a link from album to artist). i want to have this all or nothing, and i dont want to compensate, the operation should feel atomic.
meandmycode
Put your scenario as a separate question and I'll answer it there. Comments are a pain for discussing this. Also, you will get input from others too.
Darrel Miller
+1  A: 

I think that in this case it is totally acceptable to break the pure theory of REST in this situation. In any case, I don't think there is anything actually in REST that says you can't touch dependent objects in business cases that require it.

I really think it's not worth the extra hoops you would jump through to create a custom transaction manager, when you could just leverage the database to do it.

Toby Hede
A: 

Vielleicht ist RETRO (A (hopefully) RESTful Transaction Model) interessant.

marabol
A: 

In the simple case (without distributed resources), you could consider the transaction as a resource, where the act of creating it attains the end objective.

So, to transfer between <url-base>/account/a and <url-base>/account/b, you could post the following to <url-base>/transfer.

<transfer>
    <from><url-base>/account/a</from>
    <to><url-base>/account/b</to>
    <amount>50</amount>
</transfer>

This would create a new transfer resource and return the new url of the transfer - for example <url-base>/transfer/256.

At the moment of successful post, then, the 'real' transaction is carried out on the server, and the amount removed from one account and added to another.

This, however, doesn't cover a distributed transaction (if, say 'a' is held at one bank behind one service, and 'b' is held at another bank behind another service) - other than to say "try to phrase all operations in ways that don't require distributed transactions".

Phasmal
If you can't "phrase all operations in ways that don't require distributed transactions", then you really do need a two phase commit. The best idea I could find for implementing two phase commit on REST is http://rest.blueoxen.net/cgi-bin/wiki.pl?TwoPhaseCommit, which importantly doesn't mess up the URL namespace and allows a two phase commit to be layered over clean REST semantics.
Phasmal