1.. _guide.handlers:
2
3Request handlers
4================
5In the webapp2 vocabulary, `request handler` or simply `handler` is a common
6term that refers to the callable that contains the application logic to handle
7a request. This sounds a lot abstract, but we will explain everything in
8details in this section.
9
10
11Handlers 101
12------------
13A handler is equivalent to the `Controller` in the
14`MVC <http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller>`_
15terminology: in a simplified manner, it is where you process the request,
16manipulate data and define a response to be returned to the client: HTML,
17JSON, XML, files or whatever the app requires.
18
19Normally a handler is a class that extends :class:`webapp2.RequestHandler`
20or, for compatibility purposes, ``webapp.RequestHandler``. Here is a simple
21one::
22
23    class ProductHandler(webapp2.RequestHandler):
24        def get(self, product_id):
25            self.response.write('You requested product %r.' % product_id)
26
27    app = webapp2.WSGIApplication([
28        (r'/products/(\d+)', ProductHandler),
29    ])
30
31This code defines one request handler, ``ProductHandler``, and a WSGI
32application that maps the URI ``r'/products/(\d+)'`` to that handler.
33When the application receives an HTTP request to a path that matches this
34regular expression, it instantiates the handler and calls the corresponding
35HTTP method from it. The handler above can only handle ``GET`` HTTP requests,
36as it only defines a ``get()`` method. To handle ``POST`` requests,
37it would need to implement a ``post()`` method, and so on.
38
39The handler method receives a ``product_id`` extracted from the URI, and
40sets a simple message containing the id as response. Not very useful, but this
41is just to show how it works. In a more complete example, the handler would
42fetch a corresponding record from a database and set an appropriate response
43-- HTML, JSON or XML with details about the requested product, for example.
44
45For more details about how URI variables are defined, see :ref:`guide.routing`.
46
47
48HTTP methods translated to class methods
49----------------------------------------
50The default behavior of the :class:`webapp2.RequestHandler` is to call a
51method that corresponds with the HTTP action of the request, such as the
52``get()`` method for a HTTP GET request. The method processes the request and
53prepares a response, then returns. Finally, the application sends the response
54to the client.
55
56The following example defines a request handler that responds to HTTP GET
57requests::
58
59    class AddTwoNumbers(webapp2.RequestHandler):
60        def get(self):
61            try:
62                first = int(self.request.get('first'))
63                second = int(self.request.get('second'))
64
65                self.response.write("<html><body><p>%d + %d = %d</p></body></html>" %
66                                        (first, second, first + second))
67            except (TypeError, ValueError):
68                self.response.write("<html><body><p>Invalid inputs</p></body></html>")
69
70A request handler can define any of the following methods to handle the
71corresponding HTTP actions:
72
73- ``get()``
74- ``post()``
75- ``head()``
76- ``options()``
77- ``put()``
78- ``delete()``
79- ``trace()``
80
81
82View functions
83--------------
84In some Python frameworks, handlers are called `view functions` or simply
85`views`. In Django, for example, `views` are normally simple functions that
86handle a request. Our examples use mostly classes, but webapp2 handlers can
87also be normal functions equivalent to Django's `views`.
88
89A webapp2 handler can, really, be **any** callable. The routing system has
90hooks to adapt how handlers are called, and two default adapters are used
91whether it is a function or a class. So, differently from webapp, ordinary
92functions can easily be used to handle requests in webapp2, and not only
93classes. The following example demonstrates it::
94
95    def display_product(request, *args, **kwargs):
96        return webapp2.Response('You requested product %r.' % args[0])
97
98    app = webapp2.WSGIApplication([
99        (r'/products/(\d+)', display_product),
100    ])
101
102Here, our handler is a simple function that receives the request instance,
103positional route variables as ``*args`` and named variables as ``**kwargs``,
104if they are defined.
105
106Apps can have mixed handler classes and functions. Also it is possible to
107implement new interfaces to define how handlers are called: this is done
108setting new handler adapters in the routing system.
109
110Functions are an alternative for those that prefer their simplicity or think
111that handlers don't benefit that much from the power and flexibility provided
112by classes: inheritance, attributes, grouped methods, descriptors, metaclasses,
113etc. An app can have mixed handler classes and functions.
114
115.. note::
116   We avoid using the term `view` because it is often confused with the `View`
117   definition from the classic `MVC` pattern. Django prefers to call its `MVC`
118   implementation `MTV` (model-template-view), so `view` may make sense in
119   their terminology. Still, we think that the term can cause unnecessary
120   confusion and prefer to use `handler` instead, like in other Python
121   frameworks (webapp, web.py or Tornado, for instance). In essence, though,
122   they are synonyms.
123
124
125.. _guide.handlers.returned_values:
126
127Returned values
128---------------
129A handler method doesn't need to return anything: it can simply write to the
130response object using ``self.response.write()``.
131
132But a handler **can** return values to be used in the response. Using the
133default dispatcher implementation, if a handler returns anything that is not
134``None`` it **must** be a :class:`webapp2.Response` instance. If it does so,
135that response object is used instead of the default one.
136
137For example, let's return a response object with a `Hello, world` message::
138
139    class HelloHandler(webapp2.RequestHandler):
140        def get(self):
141            return webapp2.Response('Hello, world!')
142
143This is the same as::
144
145    class HelloHandler(webapp2.RequestHandler):
146        def get(self):
147            self.response.write('Hello, world!')
148
149What if you think that returning a response object is verbose, and want to
150return simple strings? Fortunately webapp2 has all the necessary hooks to make
151this possible. To achieve it, we need to extend the router dispatcher to build
152a ``Response`` object using the returned string. We can go even further and
153also accept tuples: if a tuple is returned, we use its values as positional
154arguments to instantiate the ``Response`` object. So let's define our custom
155dispatcher and a handler that returns a string::
156
157    def custom_dispatcher(router, request, response):
158        rv = router.default_dispatcher(request, response)
159        if isinstance(rv, basestring):
160            rv = webapp2.Response(rv)
161        elif isinstance(rv, tuple):
162            rv = webapp2.Response(*rv)
163
164        return rv
165
166    class HelloHandler(webapp2.RequestHandler):
167        def get(self, *args, **kwargs):
168            return 'Hello, world!'
169
170    app = webapp2.WSGIApplication([
171        (r'/', HelloHandler),
172    ])
173    app.router.set_dispatcher(custom_dispatcher)
174
175And that's all. Now we have a custom dispatcher set using the router method
176:meth:`webapp2.Router.set_dispatcher`. Our ``HelloHandler`` returns a string
177(or it could be tuple) that is used to create a ``Response`` object.
178
179Our custom dispatcher could implement its own URI matching and handler
180dispatching mechanisms from scratch, but in this case it just extends the
181default dispatcher a little bit, wrapping the returned value under certain
182conditions.
183
184.. _guide.handlers.a.micro.framework.based.on.webapp2:
185
186A micro-framework based on webapp2
187----------------------------------
188Following the previous idea of a custom dispatcher, we could go a little
189further and extend webapp2 to accept routes registered using a decorator,
190like in those Python micro-frameworks.
191
192Without much ado, ladies and gentlemen, we present micro-webapp2::
193
194    import webapp2
195
196    class WSGIApplication(webapp2.WSGIApplication):
197        def __init__(self, *args, **kwargs):
198            super(WSGIApplication, self).__init__(*args, **kwargs)
199            self.router.set_dispatcher(self.__class__.custom_dispatcher)
200
201        @staticmethod
202        def custom_dispatcher(router, request, response):
203            rv = router.default_dispatcher(request, response)
204            if isinstance(rv, basestring):
205                rv = webapp2.Response(rv)
206            elif isinstance(rv, tuple):
207                rv = webapp2.Response(*rv)
208
209            return rv
210
211        def route(self, *args, **kwargs):
212            def wrapper(func):
213                self.router.add(webapp2.Route(handler=func, *args, **kwargs))
214                return func
215
216            return wrapper
217
218Save the above code as ``micro_webapp2.py``. Then you can import it in
219``main.py`` and define your handlers and routes like this::
220
221    import micro_webapp2
222
223    app = micro_webapp2.WSGIApplication()
224
225    @app.route('/')
226    def hello_handler(request, *args, **kwargs):
227        return 'Hello, world!'
228
229    def main():
230        app.run()
231
232    if __name__ == '__main__':
233        main()
234
235This example just demonstrates some of the power and flexibility that lies
236behind webapp2; explore the :ref:`webapp2 API <api.webapp2>` to discover other
237ways to modify or extend the application behavior.
238
239
240Overriding __init__()
241---------------------
242If you want to override the :meth:`webapp2.RequestHandler.__init__` method,
243you must call :meth:`webapp2.RequestHandler.initialize` at the beginning of
244the method. It'll set the current request, response and app objects as
245attributes of the handler. For example::
246
247    class MyHandler(webapp2.RequestHandler):
248        def __init__(self, request, response):
249            # Set self.request, self.response and self.app.
250            self.initialize(request, response)
251
252            # ... add your custom initializations here ...
253            # ...
254
255
256Overriding dispatch()
257---------------------
258One of the advantadges of webapp2 over webapp is that you can wrap the
259dispatching process of :class:`webapp2.RequestHandler` to perform actions
260before and/or after the requested method is dispatched. You can do this
261overriding the :meth:`webapp2.RequestHandler.dispatch` method. This can be
262useful, for example, to test if requirements were met before actually
263dispatching the requested method, or to perform actions in the response object
264after the method was dispatched. Here's an example::
265
266    class MyHandler(webapp2.RequestHandler):
267        def dispatch(self):
268            # ... check if requirements were met ...
269            # ...
270
271            if requirements_were_met:
272                # Parent class will call the method to be dispatched
273                # -- get() or post() or etc.
274                super(MyHandler, self).dispatch()
275            else:
276                self.abort(403)
277
278In this case, if the requirements were not met, the method won't ever be
279dispatched and a "403 Forbidden" response will be returned instead.
280
281There are several possibilities to explore overriding ``dispatch()``, like
282performing common checkings, setting common attributes or post-processing the
283response.
284