Re: [Catalyst] Dispatching with Chained vs HTTP method
On Wed, May 07, 2008 at 03:57:07PM +1000, Toby Corkindale wrote: [snip] $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 Whoops, that should read: PUT /user/2/account_balance/$amount2+1 Go me and my badly named example variables :/ ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Dispatching with Chained vs HTTP method
On Wed, May 7, 2008 at 7:57 AM, Toby Corkindale [EMAIL PROTECTED] wrote: 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 How about: $id = POST transaction PUT /transaction/$id/payer/1 PUT /transaction/$id/receiver/2 PUT /transaction/$id/amount/1 PUT /transaction/$id?completed or even $id = POST transaction PUT /transaction/$id?payer=1;receiver=2;amount=1 PUT /transaction/$id?completed And - yeah - looks like we have differnet goals. But I'll watch your project proceeding :) -- Zbigniew Lukasiak http://brudnopis.blogspot.com/ ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Dispatching with Chained vs HTTP method
On 07/05/2008, at 3:57 PM, Toby Corkindale wrote: On Wed, May 07, 2008 at 03:30:12PM +1000, Adam Clarke wrote: 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: I haven't done this before, but I have thought about it a bit. I think I would handle this as a two-phase commit. PostgreSQL has PREPARE TRANSACTION which allows you to start a transaction and assign it a transaction_id for use with a subsequent COMMIT TRANSACTION. I would also use Multi-Version Concurrency Control (MVCC) rather than any kind of blocking locks to minimise the impact of the longer transaction lifetime. This would at least keep a good deal of the hard work in the DB. Cheers -- Adam ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Dispatching with Chained vs HTTP method
On Wed, May 07, 2008 at 09:55:10AM +0200, Zbigniew Lukasiak wrote: On Wed, May 7, 2008 at 7:57 AM, Toby Corkindale [EMAIL PROTECTED] wrote: [snip] 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 How about: $id = POST transaction PUT /transaction/$id/payer/1 PUT /transaction/$id/receiver/2 PUT /transaction/$id/amount/1 PUT /transaction/$id?completed or even $id = POST transaction PUT /transaction/$id?payer=1;receiver=2;amount=1 PUT /transaction/$id?completed There are other ways of doing it that would avoid the problem, but I'm just trying to demonstrate potential flaws in any transaction that does not do locking to prevent other things accessing it at the same time. Perhaps I should try another example if the other wasn't clear. Given this series of calls: transaction 1) get value of item 2) get users bank balance if balance item-value, then: 3) subtract value from bank balance 4) assign item to user /transaction What if the internet connection died for 30 seconds between step (2) and (4), and in that 30 seconds, the user bought something elsewhere, thus reducing his or her balance to below the value? That's the sort of race condition that real databases can avoid, because they'll basically stop anyone else modifying the balance after you've checked it, until you commit or rollback the transaction. We could do that too.. But imagine if we locked the user's DB row at step (2).. but then imagine if the internet connection to the person who started the transaction died.. for hours.. and during that time no other transactions could be made! That's not so good either. Toby ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Dispatching with Chained vs HTTP method
On Wed, May 07, 2008 at 06:02:46PM +1000, Adam Clarke wrote: On 07/05/2008, at 3:57 PM, Toby Corkindale wrote: On Wed, May 07, 2008 at 03:30:12PM +1000, Adam Clarke wrote: 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: I haven't done this before, but I have thought about it a bit. I think I would handle this as a two-phase commit. PostgreSQL has PREPARE TRANSACTION which allows you to start a transaction and assign it a transaction_id for use with a subsequent COMMIT TRANSACTION. I would also use Multi-Version Concurrency Control (MVCC) rather than any kind of blocking locks to minimise the impact of the longer transaction lifetime. I'm not sure the former command does what we'd like it to - after running it, I don't think you can add any further commands to it; it's merely held in stasis until you commit/rollback it, and you can start another transaction meanwhile. I *think* but I haven't used it either. Regarding the MVCC; that's a rather good idea, although my understanding of postgres is that it will start blocking in conditions where you're updating the same thing. (Edit: Just tested - it seems to) That said, I don't know how other systems handle it, or if in fact the SET SERIALISATION parameter to psql can alter this behaviour.. Are there other MVCC implementations which manage it? You seem to have a good idea about using that rather than locking. Something else occured to me - Have you had any experience at trying to get DB transactions to span connections? Since the HTTP requests could hit different processes for each request (or possibly even different servers in a farm).. I suppose one could push the DB requests to a back-end processing daemon that could ensure a consistent connection was used, but again seems to be tieing up resources if there's a network drop-out. I haven't looked into that at all really though. I was just assuming one might have to use locks as they would span, but that would be ugly, and breaks the concept of not storing state on the server for REST. This would at least keep a good deal of the hard work in the DB. *nods* I agree that's the best option. I'm mainly familiar with Postgres (and a little of MySQL) so I don't know if the commercial DBs have added features to help with these issues already? ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Dispatching with Chained vs HTTP method
On Wed, May 07, 2008 at 08:38:18AM -0400, Garrett Goebel wrote: snip Also important is how to allow people to limit which sets of tuples and relationships are publically accessible. For production work the default should probably require the REST interfaces to be explicitly published. Otherwise, with any set of tables with more than a handful of records, it will be fairly simple to bring the database to its knees with a URL that performs multiple joins on a large set of records. As a compromise, you might allow primary key candidates (keys which match exactly one record) and have one relationships to be public by default, but not have many or many to many relationships. or ask the database how long the query will take and then limit on that? Regards, Paddy ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Dispatching with Chained vs HTTP method
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. -- Adam ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
[Catalyst] Dispatching with Chained vs HTTP method
just looking for some advice on the best way to do something.. So I wrote a controller class using Chained that basically auto-converts any DBIx::Schema (which includes a tiny extra base class itself) into a REST API.. Well, a simple one anyway - it supports find and search so far, and foreign keys in the objects get serialised into hashes of the URIs to fetch them. All working nicely so far, but this is all for GET queries. But the behaviour should be different depending upon whether you GET /item/1234 or DELETE /item/1234 etc. I was thinking something like this: (Abbreviated code below) sub item_by_id : Chained CaptureArgs(2) { my ($self, $c, $type, $id) = @_; $c-stash-{item} = $c-model(DB:$type)-find($id); } sub delete : Chained('item_by_id') Args ActionClass('MethodDELETE') { my ($self, $c) = @_; $c-stash-{item}-delete; } sub modify : Chained('item_by_id') Args ActionClass('MethodPUT') { my ($self, $c) = @_; $c-stash-{item}-update($c-request-params); } Then the appropriate ActionClasses would check if the $c-req-method eq 'GET' or 'DELETE' or whatever. But I was just wondering if you had other ideas, and if using ActionClasses with Chained actions is crackfuelled and going to lead to a world of misery and pain. Cheers! Toby ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Dispatching with Chained vs HTTP method
Hi Toby, I don't know if you are aware - but building a REST-like CRUD interface to DBIx::Schema is my long term goal (started with Catalyst::Example::InstantCRUD). Do you think we could collaborate? Cheers, Zbyszek On Wed, Apr 30, 2008 at 10:26 AM, Toby Corkindale [EMAIL PROTECTED] wrote: just looking for some advice on the best way to do something.. So I wrote a controller class using Chained that basically auto-converts any DBIx::Schema (which includes a tiny extra base class itself) into a REST API.. Well, a simple one anyway - it supports find and search so far, and foreign keys in the objects get serialised into hashes of the URIs to fetch them. All working nicely so far, but this is all for GET queries. But the behaviour should be different depending upon whether you GET /item/1234 or DELETE /item/1234 etc. I was thinking something like this: (Abbreviated code below) sub item_by_id : Chained CaptureArgs(2) { my ($self, $c, $type, $id) = @_; $c-stash-{item} = $c-model(DB:$type)-find($id); } sub delete : Chained('item_by_id') Args ActionClass('MethodDELETE') { my ($self, $c) = @_; $c-stash-{item}-delete; } sub modify : Chained('item_by_id') Args ActionClass('MethodPUT') { my ($self, $c) = @_; $c-stash-{item}-update($c-request-params); } Then the appropriate ActionClasses would check if the $c-req-method eq 'GET' or 'DELETE' or whatever. But I was just wondering if you had other ideas, and if using ActionClasses with Chained actions is crackfuelled and going to lead to a world of misery and pain. Cheers! Toby ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/ -- Zbigniew Lukasiak http://brudnopis.blogspot.com/ ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Dispatching with Chained vs HTTP method
Hi Zbyszek, do you plan FormFu support? In case the submitted values are not valid the response is a xml/json/whatever which includes the error messages. That would be really great :) cheers, moritz Am 30.04.2008 um 11:24 schrieb Zbigniew Lukasiak: Hi Toby, I don't know if you are aware - but building a REST-like CRUD interface to DBIx::Schema is my long term goal (started with Catalyst::Example::InstantCRUD). Do you think we could collaborate? Cheers, Zbyszek On Wed, Apr 30, 2008 at 10:26 AM, Toby Corkindale [EMAIL PROTECTED] wrote: just looking for some advice on the best way to do something.. So I wrote a controller class using Chained that basically auto- converts any DBIx::Schema (which includes a tiny extra base class itself) into a REST API.. Well, a simple one anyway - it supports find and search so far, and foreign keys in the objects get serialised into hashes of the URIs to fetch them. All working nicely so far, but this is all for GET queries. But the behaviour should be different depending upon whether you GET /item/1234 or DELETE /item/1234 etc. I was thinking something like this: (Abbreviated code below) sub item_by_id : Chained CaptureArgs(2) { my ($self, $c, $type, $id) = @_; $c-stash-{item} = $c-model(DB:$type)-find($id); } sub delete : Chained('item_by_id') Args ActionClass('MethodDELETE') { my ($self, $c) = @_; $c-stash-{item}-delete; } sub modify : Chained('item_by_id') Args ActionClass('MethodPUT') { my ($self, $c) = @_; $c-stash-{item}-update($c-request-params); } Then the appropriate ActionClasses would check if the $c-req- method eq 'GET' or 'DELETE' or whatever. But I was just wondering if you had other ideas, and if using ActionClasses with Chained actions is crackfuelled and going to lead to a world of misery and pain. Cheers! Toby ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/ -- Zbigniew Lukasiak http://brudnopis.blogspot.com/ ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/ ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Dispatching with Chained vs HTTP method
On Wed, Apr 30, 2008 at 11:46 AM, Moritz Onken [EMAIL PROTECTED] wrote: Hi Zbyszek, do you plan FormFu support? In case the submitted values are not valid the response is a xml/json/whatever which includes the error messages. That would be really great :) I have not yet settled down with the choice of the form processor. I've started with FormFu - but now I am playing with Rose::HTML::Form - and I found it much more flexible. -- Zbigniew Lukasiak http://brudnopis.blogspot.com/ ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Dispatching with Chained vs HTTP method
Maybe you could make it modular so we can easily add another processor like formfu Am 30.04.2008 um 12:03 schrieb Zbigniew Lukasiak: On Wed, Apr 30, 2008 at 11:46 AM, Moritz Onken [EMAIL PROTECTED] wrote: Hi Zbyszek, do you plan FormFu support? In case the submitted values are not valid the response is a xml/json/whatever which includes the error messages. That would be really great :) I have not yet settled down with the choice of the form processor. I've started with FormFu - but now I am playing with Rose::HTML::Form - and I found it much more flexible. -- Zbigniew Lukasiak http://brudnopis.blogspot.com/ ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/ ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Dispatching with Chained vs HTTP method
On Wed, Apr 30, 2008 at 11:24:36AM +0200, Zbigniew Lukasiak wrote: Hi Toby, I don't know if you are aware - but building a REST-like CRUD interface to DBIx::Schema is my long term goal (started with Catalyst::Example::InstantCRUD). Do you think we could collaborate? Sure, if you liked. I'm not sure I want to aim for total DBIx::Class:Schema emulation, as I think there are many corner cases which could start getting hard to implement /well/. I'd rather approach creating something which does a sub-set of the features, but does them well. For instance, how would you handle transactions? Or specifying complex searches with aggregate clauses and self-joins? Those would seem to be more suited to an RPC protocol rather than an object-based REST situation. I think? The system I have so far works quite well for find and search, and I have a client library which re-vivifies stuff back into Perl DBIC-like objects.. So in theory you can have an application which can operate upon a local database, OR a remote database, transparently. (As long as it only uses the simpler DBIC methods) I'm learning more about the innards of Catalyst and DBIx::Class in the process too :) Toby On Wed, Apr 30, 2008 at 10:26 AM, Toby Corkindale [EMAIL PROTECTED] wrote: just looking for some advice on the best way to do something.. So I wrote a controller class using Chained that basically auto-converts any DBIx::Schema (which includes a tiny extra base class itself) into a REST API.. Well, a simple one anyway - it supports find and search so far, and foreign keys in the objects get serialised into hashes of the URIs to fetch them. All working nicely so far, but this is all for GET queries. But the behaviour should be different depending upon whether you GET /item/1234 or DELETE /item/1234 etc. I was thinking something like this: (Abbreviated code below) sub item_by_id : Chained CaptureArgs(2) { my ($self, $c, $type, $id) = @_; $c-stash-{item} = $c-model(DB:$type)-find($id); } sub delete : Chained('item_by_id') Args ActionClass('MethodDELETE') { my ($self, $c) = @_; $c-stash-{item}-delete; } sub modify : Chained('item_by_id') Args ActionClass('MethodPUT') { my ($self, $c) = @_; $c-stash-{item}-update($c-request-params); } Then the appropriate ActionClasses would check if the $c-req-method eq 'GET' or 'DELETE' or whatever. But I was just wondering if you had other ideas, and if using ActionClasses with Chained actions is crackfuelled and going to lead to a world of misery and pain. Cheers! Toby ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/