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