46 | | === Pre- and Post-Hooks === |
47 | | |
48 | | You can hook in a '''preprocessing''' function into the REST controller (as response.s3.prep) which will be called ''after'' the controller has parsed the request, but ''before'' it gets actually executed - with the current S3RESTRequest as argument (which includes the primary resource record, if any). |
49 | | |
50 | | This allows you to easily make changes to resource settings (e.g. access control, list fields etc.), or even to the REST controller configuration (e.g. custom methods) depending on the request type, its parameters or the addressed resource, without having to parse the web2py request manually. You can even bypass the execution of the request and thus hook in your own REST controller - with the advantage that you don't need to parse the request anymore. |
51 | | |
52 | | '''NB: Hooks should be added at the top of your controller function, especially pre-processing hooks.''' |
53 | | |
54 | | A simple example: |
55 | | |
56 | | Original code fragment: |
57 | | {{{ |
58 | | if len(request.args) == 0: |
59 | | # List View - reduce fields to declutter |
60 | | table.message.readable = False |
61 | | table.categories.readable = False |
62 | | table.verified_details.readable = False |
63 | | table.actioned_details.readable = False |
64 | | |
65 | | response.s3.pagination = True #enable SSPag here! |
66 | | |
67 | | return shn_rest_controller(module, resource, listadd=False) |
68 | | }}} |
69 | | |
70 | | Using the pre-processor hook instead: |
71 | | {{{ |
72 | | def log_prep(jr): |
73 | | if jr.representation == "html" and \ |
74 | | jr.method is None and \ |
75 | | jr.component is None: |
76 | | # List View - reduce fields to declutter |
77 | | table.message.readable = False |
78 | | table.categories.readable = False |
79 | | table.verified_details.readable = False |
80 | | table.actioned_details.readable = False |
81 | | return True |
82 | | |
83 | | response.s3.prep = log_prep |
84 | | response.s3.pagination = True #enable SSPag here! |
85 | | |
86 | | return shn_rest_controller(module, resource, listadd=False) |
87 | | }}} |
88 | | |
89 | | The return value of the preprocessor function can simply be True, in which case the REST request will be executed as usual. Returning False would lead to a HTTP400 "Invalid Request" exception being raised. |
90 | | |
91 | | The return value of the preprocessor function can also be a dict for more granular control - containing the following elements (all optional): |
92 | | |
93 | | - '''success''': boolean (default: True) |
94 | | - '''output''': dict (default: None) |
95 | | - '''bypass''': boolean (default: False) |
96 | | |
97 | | If ''bypass'' is True, then the REST controller does not execute the request (the post-hook is executed, though). ''output'' must not be None in this case - it will be returned from the REST controller. |
98 | | |
99 | | If ''success'' is False, and ''output'' is not None, then the REST controller does not execute the request, but just returns "output" (post-hook will ''not'' be executed in this case). |
100 | | |
101 | | If ''success'' is False and ''output'' is None, a HTTP400 "Invalid Request" will be raised instead. |
102 | | |
103 | | Examples: |
104 | | |
105 | | In most cases, you will just return "True" - in some cases you might want to raise an error, e.g.: |
106 | | {{{ |
107 | | response.error = "This request cannot be executed" |
108 | | return dict( |
109 | | success=False, |
110 | | output=dict(title="My Pagetitle", item="Sorry, no data...")) |
111 | | }}} |
112 | | |
113 | | There is also a '''post-processing hook''' (response.s3.postp) that allows you to execute something directly after the REST request has been executed, but before the shn_rest_controller returns. The post-hook function will be called with the current S3RESTRequest and the output dict of its execution as arguments. |
114 | | |
115 | | PostP Examples: |
116 | | {{{ |
117 | | def user_postp(jr, output): |
118 | | # Replace the ID column in List views with 'Action Buttons' |
119 | | shn_action_buttons(jr) |
120 | | return output |
121 | | response.s3.postp = user_postp |
122 | | }}} |
123 | | |
124 | | {{{ |
125 | | def postp(r, output): |
126 | | # Redirect to read/edit view after create rather than to list view |
127 | | if r.representation == "html" and r.method == "create": |
128 | | r.next = r.other(method="", record_id=s3xrc.get_session(session, |
129 | | module, resource)) |
130 | | return output |
131 | | response.s3.postp = postp |
132 | | }}} |