| 92 | | However - there are plenty of possibilities. |
| 93 | | |
| 94 | | Dominic |
| | 92 | Let me give you another recipe: |
| | 93 | |
| | 94 | Imagine you have a resource "warehouse" and want to implement a function "report" that generates a report about the current status of the warehouse. |
| | 95 | |
| | 96 | Now 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: |
| | 97 | |
| | 98 | {{{ |
| | 99 | http://site.myserver.org/eden/wm/warehouse/report |
| | 100 | }}} |
| | 101 | |
| | 102 | and is provided in several different data formats beyond HTML (the interactive view), let's say - XLS and XML: |
| | 103 | |
| | 104 | {{{ |
| | 105 | http://site.myserver.org/eden/wm/warehouse/report.xls |
| | 106 | http://site.myserver.org/eden/wm/warehouse/report.xml |
| | 107 | }}} |
| | 108 | |
| | 109 | How to tackle this? |
| | 110 | |
| | 111 | Yes - you can use shn_rest_controller for this! |
| | 112 | |
| | 113 | This could be your "warehouse" controller: |
| | 114 | |
| | 115 | {{{ |
| | 116 | def warehouse(): |
| | 117 | """ RESTful CRUD controller """ |
| | 118 | return shn_rest_controller(module, resource, ...) |
| | 119 | }}} |
| | 120 | |
| | 121 | At 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: |
| | 122 | |
| | 123 | {{{ |
| | 124 | def 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, ...) |
| | 129 | |
| | 130 | def warehouse_report(jr, **attr): |
| | 131 | """" Warehouse report """ |
| | 132 | <Code to produce the report> |
| | 133 | return report |
| | 134 | }}} |
| | 135 | |
| | 136 | How 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 |
| | 137 | are then formatted as HTML in the view template: |
| | 138 | |
| | 139 | {{{ |
| | 140 | def 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 |
| | 146 | }}} |
| | 147 | |
| | 148 | Note 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 |
| | 149 | available to the view templates. That also means: do not use "jr" as key in that dict. |
| | 150 | |
| | 151 | However, 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 |
| | 152 | found in jr: |
| | 153 | |
| | 154 | {{{ |
| | 155 | def 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 |
| | 169 | }}} |
| | 170 | |
| | 171 | See [wiki:S3REST#S3RESTRequest S3RESTRequest] to find out more about "jr". |
| | 172 | |
| | 173 | To 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: |
| | 174 | |
| | 175 | {{{ |
| | 176 | def warehouse_report(jr, **attr): |
| | 177 | ... |
| | 178 | elif jr.representation in shn_xml_export_formats: |
| | 179 | return export_xml(xrequest) |
| | 180 | ... |
| | 181 | }}} |
| | 182 | |
| | 183 | Perhaps you want to add an RSS feed: |
| | 184 | |
| | 185 | {{{ |
| | 186 | def warehouse_report(jr, **attr): |
| | 187 | ... |
| | 188 | elif jr.representation == "rss": |
| | 189 | <Code to produce the RSS report> |
| | 190 | return report |
| | 191 | ... |
| | 192 | }}} |
| | 193 | |
| | 194 | Ah - 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: |
| | 195 | |
| | 196 | This URL addresses the report for all warehouses: |
| | 197 | {{{ |
| | 198 | http://site.myserver.org/eden/wm/warehouse/report |
| | 199 | }}} |
| | 200 | |
| | 201 | This URL addresses the report for the warehouse record with ID=1. |
| | 202 | {{{ |
| | 203 | http://site.myserver.org/eden/wm/warehouse/1/report |
| | 204 | }}} |
| | 205 | |
| | 206 | This 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). |
| | 207 | {{{ |
| | 208 | http://site.myserver.org/eden/wm/warehouse/report.xls?warehouse.uid=123654278 |
| | 209 | }}} |
| | 210 | |
| | 211 | The S3RESTRequest provides the resource information to your warehouse_report function. |
| | 212 | |
| | 213 | In case a specific record has been requested, you can access it as: |
| | 214 | {{{ |
| | 215 | record = jr.record |
| | 216 | }}} |
| | 217 | If jr.record is None, then the request is targeting all warehouse records, so you'd take: |
| | 218 | {{{ |
| | 219 | table = jr.table |
| | 220 | records = db().select(table.ALL) |
| | 221 | for record in records: |
| | 222 | ... |
| | 223 | }}} |
| | 224 | instead. |
| | 225 | |
| | 226 | NOTE: representation in jr is always all lowercase, there is no differentiation between the ".XML" and ".xml" extension in the URL. |
| | 227 | |
| | 228 | And...not to forget: |
| | 229 | |
| | 230 | Your warehouse_report is still a controller function, that means you can implement forms as usual (e.g. operated with form.accepts). |
| | 231 | |
| | 232 | To distinguish between different HTTP methods (in case you need that), you can use: |
| | 233 | |
| | 234 | http_method = jr.http # gives one of "GET", "POST", "PUT" or "DELETE" |
| | 235 | |
| | 236 | (...whatever PUT or DELETE would mean for a warehouse report, you would probably just ignore these) |