restful application module

Jonathan

I have been working on a single page web application called Moolah. Moolah uses a restful style to get data from the server in json format. When I started working on this, I couldn’t find a good pluggable module that would allow me to do this easily, so I wrote my own.

This module only works for json currently, but wouldn’t be very much work to extend to xml or other formats.

When POSTing a record, the result is the new record (including the new key). In the case of a validation failure, the errors object is returned instead.

I did some (non-extensive) searching for what a restful url scheme should look like, and didn’t really find anything conclusive. The url patterns that it uses are as follows:

get /data/account/id/123 (get item with id 123
get /data/account/search/123 (get items that contain 123
get /data/account/list/0/10?field=val (get a list from item 0 to item 10, where field=val
post /data/account/ (create a record)
delete /data/account/123 (delete a record with id 123)

It is possible that I should move to a url-pattern that looks more like:

get /data/account/123 (get item with id 123
get /data/account/?query=123 (get items that contain 123 (text search)
get /data/account/?start=0&items=10 (get a list from item 0 to item 10
post /data/account/ (create a record)
delete /data/account/123 (delete a record with id 123)

I didn’t find this urlpattern as natural, but am willing to have my mind changed.

It is written to be compatible with Google App Engine using app-engine-patch and uses the guidelines at app-engine-patch for making reusable modules.

It is completely pluggable and requires very little configuration. To use you must do the following:

  1. Within the main project:
    1. extract the zip file as a new application within your project
    2. modify the root-level settings.py file to add the “restful” application
  2. Within the application:
    1. Create a UserRestfulController class that inherits from restful.RestfulController
      class AccountForm(ModelForm):
          class Meta:
              model = Account

      # exclude any fields that shouldn’t be set or overridden from a POST
      exclude=(‘created’,'owner’)

      class AccountRestfulController(RestfulController):
      modelClass = Account
      formClass = AccountForm

    2. modify the application settings.py file and add “REST_CONTROLLERS={“account”:AccountRestfulController}” (where you want to expose a “User” model object.
  3. Then (as an example using jQuery) you can access the data with something like:
      getAccount: function(key, callback) {
         $.get("/data/account/id/" + key, function(data) {
                  callback(new CORE.Account(JSON.parse(data, CORE.util.stringToDate)[0]));
               });
      },
      getAccounts : function(offset, limit, callback) {
         $.get("/data/account/list/" + offset + "/" + limit + "/", function(data) {
                  callback(CORE.convertJsonListToObject(JSON.parse(data, CORE.util.stringToDate),
                        CORE.Account));
               });
      },
      deleteAccount : function(accountPk, callback) {
         $.ajax({
                  type : "DELETE",
                  url : "/data/account/" + accountPk,
                  success : function() {
                     callback();
                  }
               });
      },

Thats it.

There is a fair bit of flexibility in the way that the controller works by overriding methods in the RestController class. eg: We want to return a list of transactions associated with an account:

"/data/futureTransaction/list/" + offset + "/" + limit + "/?accountPk=" + account.pk;

then we have a RestfulController defined:

class TransactionRestfulController(RestfulController):
    modelClass = Transaction
    formClass = TransactionForm
    def list (self, offset, limit):
        accountPk = self.request.GET['accountPk']
        account = Account.get(accountPk)
        return Paginator(account.futuretransaction_set.order("created"), int(limit)).page((int(offset) / int(limit)) + 1).object_list

This gets the requested account, and gets the list of children objects from there and paginates them using standard Django classes.

Files for this post

  • restful gae module (.tar.gz, extract to the root of your project and follow the instructions above)

Leave a Reply