[Catalyst] Dispatching with Chained vs HTTP method

Toby Corkindale tjc at wintrmute.net
Wed May 7 06:57:07 BST 2008


Hi Adam,

On Wed, May 07, 2008 at 03:30:12PM +1000, Adam Clarke wrote:
> On 07/05/2008, at 11:05 AM, Toby Corkindale wrote:
>
>> Ah, I was thinking of transactions vs a REST API, eg:
>>    PUT /user/1234/account_balance?subtract=1
>>    POST /user/4567/account_balance?add=1
>> Since those are two separate HTTP requests, and REST specifically states 
>> you
>> cannot maintain state on the server, how would you perform those two
>> operations inside a transaction?
>>
>> (My "solution" is to implement it in one request, like:
>>    PUT /user/1234/money_transfer?user=4567;amount=1
>> However that is not CRUD-like, nor a direct mapping of DBIC functionality 
>> to
>> REST)
>
> The solution suggested in "Restful Web Services" is to POST to a "factory" 
> resource which creates you with a transaction resource. e.g. "POST 
> /transactions/account-transfer" returns "Location:  
> /transactions/account-transfer/11a5", where the 11a5 is a unique 
> transaction identifier.
>
> Then "PUT /transactions/account-transfer/11a5/accounts/checking/11", where 
> 11 is the account identifier. The body carries the transaction details, in 
> the example the balances are adjusted absolutely, i.e. "balance=150". A 
> similar PUT is sent for the other account.
>
> Once the required components of the transaction have been PUT it is 
> possible to rollback by DELETEing the transaction resource or commit it by 
> putting "committed=true" to the resource.
>
> While seeming a bit fiddly, it does keep the state on the client and allows 
> the client to make (at least some of) the commit / rollback decision rather 
> than (only) the server.

I've read parts of RESTful Web Services, but not that bit.. I'll have to go
back and look.

I wonder how one goes about implementing such a transaction on the server
side.. One would not want to lock DB rows indefinitely, waiting for the client
to finally complete the transaction. But if one just recorded the queries and
then executed them all (internally) at the end, then other risks exist, eg:

$id = POST transaction
$amount = GET /user/1/account_balance
$amount2 = GET /user/2/account_balance
PUT /user/1/account_balance/$amount-1
PUT /user/2/account_balance/$amount+1
PUT transaction/$id?completed

In that example, user one might receive their paycheque after you've queried
their account balance, but before you've written the new amount.

Hmm. I suppose one could try for the method of actually locking the DB rows
until the REST completed the transaction, and putting some kind of timeout on
it; but anything that does long DB locks scares me with the potential of
deadlocks.

Have you implemented anything like this? I'm curious to know how well it might
work (or not work) in practice.

Toby
(Who likes REST but still isn't sure about doing double-entry bookkeeping with
it)



More information about the Catalyst mailing list