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

06/11/10 20:58:57 (11 years ago)
Dominic König



  • DeveloperGuidelines/Tutorial/RESTCustomisation

    v1 v2  
    1 == REST Customisation ==
     1== REST Customisation Mini Tutorial ==
    33It seems generally difficult for new developers to understand how to take control of functionality in the [wiki:RESTController] of the S3 framework.
    9090information 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.
    92 However - there are plenty of possibilities.
    94 Dominic
     92Let me give you another recipe:
     94Imagine you have a resource "warehouse" and want to implement a function "report" that generates a report about the current status of the warehouse.
     96Now you're gonna provide this report in a RESTful way, i.e. you want to provide it as a resource that can be addressed via URLs like:
     102and is provided in several different data formats beyond HTML (the interactive view), let's say - XLS and XML:
     109How to tackle this?
     111Yes - you can use shn_rest_controller for this!
     113This could be your "warehouse" controller:
     116def warehouse():
     117   """ RESTful CRUD controller """
     118   return shn_rest_controller(module, resource, ...)
     121At first you implement your report function (in the controller file). This function takes the argument jr (=S3RESTRequest) and a dict of named arguments (just the same named arguments from the shn_rest_controller call above). This function returns the report. Then, in your controller, you plug in this function to your resource - together it would look like that:
     124def warehouse():
     125    """ RESTful CRUD controller """
     126    s3xrc.model.set_method(module, resource,
     127                     method="report", action=warehouse_report)
     128    return shn_rest_controller(module, resource, ...)
     130def warehouse_report(jr, **attr):
     131    """" Warehouse report """
     132    <Code to produce the report>
     133    return report
     136How to implement the report function now? Well - that's entirely up to you. In case if interactive views, you would usually return a dict of values that
     137are then formatted as HTML in the view template:
     140def warehouse_report(jr, **attr):
     141    """" Warehouse report """
     142    <Code to produce the report>
     143    # Assemble the report as dict:
     144    report = dict(title="Page Title", ...)
     145    return report
     148Note that if "report" is a dict, then the REST controller automatically adds the S3RESTRequest as "jr" to that dict before returning it. Thus, "jr" is
     149available to the view templates. That also means: do not use "jr" as key in that dict.
     151However, there may be other formats than HTML - to implement other formats, you might need to check for the representation of the request. This can be
     152found in jr:
     155def warehouse_report(jr, **attr):
     156    """" Warehouse report """
     157    if jr.representation in ("html", "popup"):
     158        <Code to produce the interactive report>
     159        # Assemble the report as dict:
     160        report = dict(title="Page Title", ...)
     161    elif jr.representation == "xls":
     162        <Code to produce the XLS report>
     163    elif jr.representation in shn_xml_export_formats:
     164        <Code to produce the XML report>
     165    else:
     166        session.error = BADFORMAT
     167        redirect(URL(r=jr.request))
     168    return report
     171See [wiki:S3REST#S3RESTRequest S3RESTRequest] to find out more about "jr".
     173To produce the XML report, it is probably sufficient to just export the requested warehouse information in S3XRC-XML, and then use XSLT stylesheets to produce the finally desired XML formats. That's pretty easy:
     176def warehouse_report(jr, **attr):
     177    ...
     178    elif jr.representation in shn_xml_export_formats:
     179        return export_xml(xrequest)
     180    ...
     183Perhaps you want to add an RSS feed:
     186def warehouse_report(jr, **attr):
     187    ...
     188    elif jr.representation == "rss":
     189        <Code to produce the RSS report>
     190        return report
     191    ...
     194Ah - now I forgot to mention how you can get at the data in the warehouse_report example. Your implementation already supports a variety of URLs:
     196This URL addresses the report for all warehouses:
     201This URL addresses the report for the warehouse record with ID=1.
     206This URL addresses the report in XLS format for the warehouse record with the UUID=123654278 (assuming that you have UUID's in your warehouse table).
     211The S3RESTRequest provides the resource information to your warehouse_report function.
     213In case a specific record has been requested, you can access it as:
     215    record = jr.record
     217If jr.record is None, then the request is targeting all warehouse records, so you'd take:
     219    table = jr.table
     220    records = db().select(table.ALL)
     221    for record in records:
     222       ...
     226NOTE: representation in jr is always all lowercase, there is no differentiation between the ".XML" and ".xml" extension in the URL.
     228And...not to forget:
     230Your warehouse_report is still a controller function, that means you can implement forms as usual (e.g. operated with form.accepts).
     232To distinguish between different HTTP methods (in case you need that), you can use:
     234http_method = jr.http # gives one of "GET", "POST", "PUT" or "DELETE"
     236(...whatever PUT or DELETE would mean for a warehouse report, you would probably just ignore these)