RESTfulness in Pylons --------------------- I've been trying to buld a web application in a RESTful fashion, using for guidance among other resources the Leonard Richardson and Sam Ruby book _RESTful Web Services_. I've learned that REST is a style of architecting applications, and that Pylons with the map.resource() function of routes can be seen as one particular way of defining and working within some RESTful constraints.
The way that map.resource() sets things up is basically as follows. There are two types of URL, collections (/resources) and individuals (/ resources/6), and four HTTP verbs, GET, POST, PUT, and DELETE. These are variously combined to allow for seven different REST actions: index, show, new, edit, create, update, and delete. If you group the REST actions by type of URL, you get the actions that work on collections: index, new, create and the actions that work on individuals: show, edit, update, delete To make a RESTful web application under these conditions means to express all functionality the application provides in terms of resources and those seven actions acting on resources. This is an interesting and challenging project, and to the extent that it can be successful, the benefits of the RESTful approach are significant. Now, on to my current problem! Batch Operations ---------------- How do you implement batch operations on collections of resources? Imagine you have a resource Messages. If you "GET /messages" it returns an index of messages. If you "DELETE /messages/4" it will delete message 4. Perhaps the "GET /messages" index includes for each resource in the collection a form with a button that allows the client to send an HTTP DELETE to that message's URL. So if there are ten messages in the URL, there will be ten items returned by the index action, and those will include ten forms, one to send a DELETE to each of the ten messages. Now, suppose you wish to have a way for the user to do a batch delete on a subset of messages. The traditional (non-RESTful) way to achieve this is to have the list of ten messages inside a single form, with a checkbox for each list item. The Delete button would submit an overloaded POST to some URL such as "POST /messages/delete" and the server can delete all the checked off items. Or, alternatively, there will be an even more generic URL, "/messages/batch" and the fact that the selected messages are to be deleted or moved to a different folder will be specified as an input element of the form. But of course neither of these is available in the current RESTful framework. The way to delete a set of five different messages is to send five HTTP requests, each of the form "DELETE /messages/:id". Is it possible to allow batch operations within the RESTful constraints? If so, what is the best way to do this? Three Ideas ----------- 1. Use AJAX techniques to submit the five requests for the user. Basically have the form submit intercepted by a javascript which fires off five asynchronous HTTP DELETE requests to the five URLS and collects the responses for display. This requires no changes to the server API. If the client does not have javascript, the interface can degrade gracefully to requiring a separate submit button click for each delete. 2. Of the seven REST actions, four of them (show, edit, update, delete) act upon individual resources. Extend these to be able to act on collections of resources, and therefore also generalize the URL formats to allow for addressing subsets of collections. For example, the URL "/messages/3,4,18,22-50" refers to a subset of the collection of messages. An HTTP DELETE to that URL would delete each resource in that subset. In this case, of the remaining 3 REST actions that act only upon collections, index, new, and create, one of them, index, would be updated to act on proper subsets of the collections, and the other two would behave the same whether the URL refers to the entire collection or some subset. One big challenge of this approach is creating a scheme for addressing arbitrary subsets of a collection, and by addressing I mean having it in the URL. The scheme would have to be such that the URLs could be created using HTML forms. Finally, after developing the scheme it would also require significant changes to routes to support it. 3. Use overloaded POST to create new REST actions in addition to the basic seven that are meant to support batch operations. For example, three new actions called batch_create, batch_update, batch_delete. In this case it is not necessary to address subsets in the URL; the collection URL for a resource can be used instead. However support in routes map.resource might be required to route the incoming POST to the proper RestController action. The POST request body for each of those actions can contain the set of resources and representations to act upon. One difficulty here is figuring out the best way to modify the route configuration to identify the three new actions. Currently, the only trickery routes explicitly supports for RESTful apps is the _method input element used to translate POST to PUT or DELETE, which makes up for a deficiency in modern browsers and/or HTML 4 that makes it impossible for most clients to construct an actual HTTP PUT request. But the current problem doesn't need to translate one HTTP method to another HTTP method, it needs to include additional information to distinguish between multiple actions at the collection level. Perhaps it can be done on the model of the new action, for which the url is '/ messages/new'. So in this case we can have '/messages/batch_create', '/ messages/batch_update', etc. I'm currently leaning toward option 3. One downside is that a strength of the RESTful approach is the simple server API. Option 3 does increase the breadth of the server API, but on the other hand it isn't obvious that it does this in a way that is inconsistent with REST principles. So, has anyone tried to tackle this problem before, of batch operations in the RESTful framework? Did you try anything like the approaches I've described above? Any stories of success, pitfalls to beware, known theoretical limits or false assumptions I've made, or general engineering advice? Thanks --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "pylons-discuss" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/pylons-discuss?hl=en -~----------~----~----~----~------~----~------~--~---
