Changes between Initial Version and Version 1 of DeveloperGuidelines/Tutorial/RESTCustomisation


Ignore:
Timestamp:
06/11/10 11:11:55 (15 years ago)
Author:
Fran Boon
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • DeveloperGuidelines/Tutorial/RESTCustomisation

    v1 v1  
     1== REST Customisation ==
     2
     3It seems generally difficult for new developers to understand how to take control of functionality in the [wiki:RESTController] of the S3 framework.
     4
     5IMHO that is because most of the examples look like that:
     6{{{
     7def myresource():
     8   """ RESTful CRUD controller """
     9   return shn_rest_controller(module, resource)
     10}}}
     11This in fact leaves it all to the shn_rest_controller function - hard to see what really happens.
     12
     13However, shn_rest_controller does not actually mean you would be tied to the CRUD method handlers of {{{01_crud.py}}} either. REST merely cares for the proper resolution of URLs and HTTP methods, and then calls hooked-in functions to process the requests.
     14
     15First of all - shn_rest_controller returns some output:
     16{{{
     17def myresource():
     18   """ RESTful CRUD controller """
     19   output = shn_rest_controller(module, resource)
     20   return output
     21}}}
     22
     23In case of interactive views, this output would be a dict with the components that are then passed to the view (by "return output" here). This could contain a form, for example:
     24{{{
     25def myresource():
     26   """ RESTful CRUD controller """
     27   output = shn_rest_controller(module, resource)
     28   if isinstance(output, dict) and "form" in output:
     29       form = output.get("form")
     30       <your form manipulation here>
     31   return output
     32}}}
     33
     34That also means, you can add more items to the output dict:
     35{{{
     36def myresource():
     37   """ RESTful CRUD controller """
     38   output = shn_rest_controller(module, resource)
     39   if isinstance(output, dict):
     40       if "form" in output:
     41           form = output.get("form")
     42           <your form manipulation here>
     43       myitem = "I can send this item to the view"
     44       output.update(myitem=myitem)
     45   return output
     46}}}
     47
     48Secondly, the shn_rest_controller has multiple hooks, among others for CRUD method handlers. Look at how shn_rest_controller is actually defined:
     49{{{
     50def shn_rest_controller(module, resource, **attr):
     51
     52   s3rest.set_handler("import_xml", import_xml)
     53   s3rest.set_handler("import_json", import_json)
     54   s3rest.set_handler("list", shn_list)
     55   s3rest.set_handler("read", shn_read)
     56   s3rest.set_handler("create", shn_create)
     57   s3rest.set_handler("update", shn_update)
     58   s3rest.set_handler("delete", shn_delete)
     59   s3rest.set_handler("search", shn_search)
     60   s3rest.set_handler("options", shn_options)
     61
     62   output = s3rest(session, request, response, module, resource, **attr)
     63   return output
     64}}}
     65
     66This is nothing else than a wrapper for the global s3rest object (an instance of S3RESTController), which configures the CRUD handlers of {{{01_crud.py}}} as handlers for CRUD methods. You don't have to use shn_rest_controller to have a RESTful API, you can make your own handler configuration and call s3rest directly.
     67
     68But even when using shn_rest_controller, you can take control over what actually happens. A very comfortable (and recommended) way to get control over s3rest when using shn_rest_controller is to hook in prep and postp functions. Look at [wiki:S3REST] to find out when prep and postp hooks are invoked.
     69
     70A prep hook would allow you to change a handler configuration in certain situations, e.g. testing a URL variable:
     71{{{
     72def myresource():
     73   """ RESTful CRUD controller """
     74
     75   def _prep(jr):
     76       mylist = jr.request.vars.get("mylist")
     77       if mylist:
     78           s3rest.set_handler("list", my_list_controller)
     79       return True # do not forget to return True!
     80   response.s3.prep = _prep
     81
     82   output = shn_rest_controller(module, resource)
     83   return output
     84}}}
     85This example would switch to my_list_controller instead of shn_list in case there is a ?mylist= in the URL. In all other cases, the default handlers are executed as usual, you still have a RESTful API for your resources.
     86
     87While you can define prep's and postp's as local functions (as in the example above) or even lambdas, it is also very well possible to create more generic, reusable prep and postp functions (e.g. to implement different method handler configurations, or to catch certain situations to bypass the CRUD handlers, or to manipulate the output dict in a certain way).
     88
     89A very important structure during prep and postp is the S3RESTRequest object (usually instantiated as "jr"). This object contains all necessary
     90information to process the current REST request, and it is passed to both prep and postp. See [wiki:S3REST#S3RESTRequest] for a list of attributes and methods.
     91
     92However - there are plenty of possibilities.
     93
     94Dominic