Home | History | Annotate | Download | only in guide
      1 .. _guide.handlers:
      2 
      3 Request handlers
      4 ================
      5 In the webapp2 vocabulary, `request handler` or simply `handler` is a common
      6 term that refers to the callable that contains the application logic to handle
      7 a request. This sounds a lot abstract, but we will explain everything in
      8 details in this section.
      9 
     10 
     11 Handlers 101
     12 ------------
     13 A handler is equivalent to the `Controller` in the
     14 `MVC <http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller>`_
     15 terminology: in a simplified manner, it is where you process the request,
     16 manipulate data and define a response to be returned to the client: HTML,
     17 JSON, XML, files or whatever the app requires.
     18 
     19 Normally a handler is a class that extends :class:`webapp2.RequestHandler`
     20 or, for compatibility purposes, ``webapp.RequestHandler``. Here is a simple
     21 one::
     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 
     31 This code defines one request handler, ``ProductHandler``, and a WSGI
     32 application that maps the URI ``r'/products/(\d+)'`` to that handler.
     33 When the application receives an HTTP request to a path that matches this
     34 regular expression, it instantiates the handler and calls the corresponding
     35 HTTP method from it. The handler above can only handle ``GET`` HTTP requests,
     36 as it only defines a ``get()`` method. To handle ``POST`` requests,
     37 it would need to implement a ``post()`` method, and so on.
     38 
     39 The handler method receives a ``product_id`` extracted from the URI, and
     40 sets a simple message containing the id as response. Not very useful, but this
     41 is just to show how it works. In a more complete example, the handler would
     42 fetch 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 
     45 For more details about how URI variables are defined, see :ref:`guide.routing`.
     46 
     47 
     48 HTTP methods translated to class methods
     49 ----------------------------------------
     50 The default behavior of the :class:`webapp2.RequestHandler` is to call a
     51 method 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
     53 prepares a response, then returns. Finally, the application sends the response
     54 to the client.
     55 
     56 The following example defines a request handler that responds to HTTP GET
     57 requests::
     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 
     70 A request handler can define any of the following methods to handle the
     71 corresponding HTTP actions:
     72 
     73 - ``get()``
     74 - ``post()``
     75 - ``head()``
     76 - ``options()``
     77 - ``put()``
     78 - ``delete()``
     79 - ``trace()``
     80 
     81 
     82 View functions
     83 --------------
     84 In some Python frameworks, handlers are called `view functions` or simply
     85 `views`. In Django, for example, `views` are normally simple functions that
     86 handle a request. Our examples use mostly classes, but webapp2 handlers can
     87 also be normal functions equivalent to Django's `views`.
     88 
     89 A webapp2 handler can, really, be **any** callable. The routing system has
     90 hooks to adapt how handlers are called, and two default adapters are used
     91 whether it is a function or a class. So, differently from webapp, ordinary
     92 functions can easily be used to handle requests in webapp2, and not only
     93 classes. 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 
    102 Here, our handler is a simple function that receives the request instance,
    103 positional route variables as ``*args`` and named variables as ``**kwargs``,
    104 if they are defined.
    105 
    106 Apps can have mixed handler classes and functions. Also it is possible to
    107 implement new interfaces to define how handlers are called: this is done
    108 setting new handler adapters in the routing system.
    109 
    110 Functions are an alternative for those that prefer their simplicity or think
    111 that handlers don't benefit that much from the power and flexibility provided
    112 by classes: inheritance, attributes, grouped methods, descriptors, metaclasses,
    113 etc. 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 
    127 Returned values
    128 ---------------
    129 A handler method doesn't need to return anything: it can simply write to the
    130 response object using ``self.response.write()``.
    131 
    132 But a handler **can** return values to be used in the response. Using the
    133 default dispatcher implementation, if a handler returns anything that is not
    134 ``None`` it **must** be a :class:`webapp2.Response` instance. If it does so,
    135 that response object is used instead of the default one.
    136 
    137 For 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 
    143 This is the same as::
    144 
    145     class HelloHandler(webapp2.RequestHandler):
    146         def get(self):
    147             self.response.write('Hello, world!')
    148 
    149 What if you think that returning a response object is verbose, and want to
    150 return simple strings? Fortunately webapp2 has all the necessary hooks to make
    151 this possible. To achieve it, we need to extend the router dispatcher to build
    152 a ``Response`` object using the returned string. We can go even further and
    153 also accept tuples: if a tuple is returned, we use its values as positional
    154 arguments to instantiate the ``Response`` object. So let's define our custom
    155 dispatcher 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 
    175 And 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 
    179 Our custom dispatcher could implement its own URI matching and handler
    180 dispatching mechanisms from scratch, but in this case it just extends the
    181 default dispatcher a little bit, wrapping the returned value under certain
    182 conditions.
    183 
    184 .. _guide.handlers.a.micro.framework.based.on.webapp2:
    185 
    186 A micro-framework based on webapp2
    187 ----------------------------------
    188 Following the previous idea of a custom dispatcher, we could go a little
    189 further and extend webapp2 to accept routes registered using a decorator,
    190 like in those Python micro-frameworks.
    191 
    192 Without 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 
    218 Save 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 
    235 This example just demonstrates some of the power and flexibility that lies
    236 behind webapp2; explore the :ref:`webapp2 API <api.webapp2>` to discover other
    237 ways to modify or extend the application behavior.
    238 
    239 
    240 Overriding __init__()
    241 ---------------------
    242 If you want to override the :meth:`webapp2.RequestHandler.__init__` method,
    243 you must call :meth:`webapp2.RequestHandler.initialize` at the beginning of
    244 the method. It'll set the current request, response and app objects as
    245 attributes 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 
    256 Overriding dispatch()
    257 ---------------------
    258 One of the advantadges of webapp2 over webapp is that you can wrap the
    259 dispatching process of :class:`webapp2.RequestHandler` to perform actions
    260 before and/or after the requested method is dispatched. You can do this
    261 overriding the :meth:`webapp2.RequestHandler.dispatch` method. This can be
    262 useful, for example, to test if requirements were met before actually
    263 dispatching the requested method, or to perform actions in the response object
    264 after 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 
    278 In this case, if the requirements were not met, the method won't ever be
    279 dispatched and a "403 Forbidden" response will be returned instead.
    280 
    281 There are several possibilities to explore overriding ``dispatch()``, like
    282 performing common checkings, setting common attributes or post-processing the
    283 response.
    284