| .. _guide.handlers: |
| |
| Request handlers |
| ================ |
| In the webapp2 vocabulary, `request handler` or simply `handler` is a common |
| term that refers to the callable that contains the application logic to handle |
| a request. This sounds a lot abstract, but we will explain everything in |
| details in this section. |
| |
| |
| Handlers 101 |
| ------------ |
| A handler is equivalent to the `Controller` in the |
| `MVC <http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller>`_ |
| terminology: in a simplified manner, it is where you process the request, |
| manipulate data and define a response to be returned to the client: HTML, |
| JSON, XML, files or whatever the app requires. |
| |
| Normally a handler is a class that extends :class:`webapp2.RequestHandler` |
| or, for compatibility purposes, ``webapp.RequestHandler``. Here is a simple |
| one:: |
| |
| class ProductHandler(webapp2.RequestHandler): |
| def get(self, product_id): |
| self.response.write('You requested product %r.' % product_id) |
| |
| app = webapp2.WSGIApplication([ |
| (r'/products/(\d+)', ProductHandler), |
| ]) |
| |
| This code defines one request handler, ``ProductHandler``, and a WSGI |
| application that maps the URI ``r'/products/(\d+)'`` to that handler. |
| When the application receives an HTTP request to a path that matches this |
| regular expression, it instantiates the handler and calls the corresponding |
| HTTP method from it. The handler above can only handle ``GET`` HTTP requests, |
| as it only defines a ``get()`` method. To handle ``POST`` requests, |
| it would need to implement a ``post()`` method, and so on. |
| |
| The handler method receives a ``product_id`` extracted from the URI, and |
| sets a simple message containing the id as response. Not very useful, but this |
| is just to show how it works. In a more complete example, the handler would |
| fetch a corresponding record from a database and set an appropriate response |
| -- HTML, JSON or XML with details about the requested product, for example. |
| |
| For more details about how URI variables are defined, see :ref:`guide.routing`. |
| |
| |
| HTTP methods translated to class methods |
| ---------------------------------------- |
| The default behavior of the :class:`webapp2.RequestHandler` is to call a |
| method that corresponds with the HTTP action of the request, such as the |
| ``get()`` method for a HTTP GET request. The method processes the request and |
| prepares a response, then returns. Finally, the application sends the response |
| to the client. |
| |
| The following example defines a request handler that responds to HTTP GET |
| requests:: |
| |
| class AddTwoNumbers(webapp2.RequestHandler): |
| def get(self): |
| try: |
| first = int(self.request.get('first')) |
| second = int(self.request.get('second')) |
| |
| self.response.write("<html><body><p>%d + %d = %d</p></body></html>" % |
| (first, second, first + second)) |
| except (TypeError, ValueError): |
| self.response.write("<html><body><p>Invalid inputs</p></body></html>") |
| |
| A request handler can define any of the following methods to handle the |
| corresponding HTTP actions: |
| |
| - ``get()`` |
| - ``post()`` |
| - ``head()`` |
| - ``options()`` |
| - ``put()`` |
| - ``delete()`` |
| - ``trace()`` |
| |
| |
| View functions |
| -------------- |
| In some Python frameworks, handlers are called `view functions` or simply |
| `views`. In Django, for example, `views` are normally simple functions that |
| handle a request. Our examples use mostly classes, but webapp2 handlers can |
| also be normal functions equivalent to Django's `views`. |
| |
| A webapp2 handler can, really, be **any** callable. The routing system has |
| hooks to adapt how handlers are called, and two default adapters are used |
| whether it is a function or a class. So, differently from webapp, ordinary |
| functions can easily be used to handle requests in webapp2, and not only |
| classes. The following example demonstrates it:: |
| |
| def display_product(request, *args, **kwargs): |
| return webapp2.Response('You requested product %r.' % args[0]) |
| |
| app = webapp2.WSGIApplication([ |
| (r'/products/(\d+)', display_product), |
| ]) |
| |
| Here, our handler is a simple function that receives the request instance, |
| positional route variables as ``*args`` and named variables as ``**kwargs``, |
| if they are defined. |
| |
| Apps can have mixed handler classes and functions. Also it is possible to |
| implement new interfaces to define how handlers are called: this is done |
| setting new handler adapters in the routing system. |
| |
| Functions are an alternative for those that prefer their simplicity or think |
| that handlers don't benefit that much from the power and flexibility provided |
| by classes: inheritance, attributes, grouped methods, descriptors, metaclasses, |
| etc. An app can have mixed handler classes and functions. |
| |
| .. note:: |
| We avoid using the term `view` because it is often confused with the `View` |
| definition from the classic `MVC` pattern. Django prefers to call its `MVC` |
| implementation `MTV` (model-template-view), so `view` may make sense in |
| their terminology. Still, we think that the term can cause unnecessary |
| confusion and prefer to use `handler` instead, like in other Python |
| frameworks (webapp, web.py or Tornado, for instance). In essence, though, |
| they are synonyms. |
| |
| |
| .. _guide.handlers.returned_values: |
| |
| Returned values |
| --------------- |
| A handler method doesn't need to return anything: it can simply write to the |
| response object using ``self.response.write()``. |
| |
| But a handler **can** return values to be used in the response. Using the |
| default dispatcher implementation, if a handler returns anything that is not |
| ``None`` it **must** be a :class:`webapp2.Response` instance. If it does so, |
| that response object is used instead of the default one. |
| |
| For example, let's return a response object with a `Hello, world` message:: |
| |
| class HelloHandler(webapp2.RequestHandler): |
| def get(self): |
| return webapp2.Response('Hello, world!') |
| |
| This is the same as:: |
| |
| class HelloHandler(webapp2.RequestHandler): |
| def get(self): |
| self.response.write('Hello, world!') |
| |
| What if you think that returning a response object is verbose, and want to |
| return simple strings? Fortunately webapp2 has all the necessary hooks to make |
| this possible. To achieve it, we need to extend the router dispatcher to build |
| a ``Response`` object using the returned string. We can go even further and |
| also accept tuples: if a tuple is returned, we use its values as positional |
| arguments to instantiate the ``Response`` object. So let's define our custom |
| dispatcher and a handler that returns a string:: |
| |
| def custom_dispatcher(router, request, response): |
| rv = router.default_dispatcher(request, response) |
| if isinstance(rv, basestring): |
| rv = webapp2.Response(rv) |
| elif isinstance(rv, tuple): |
| rv = webapp2.Response(*rv) |
| |
| return rv |
| |
| class HelloHandler(webapp2.RequestHandler): |
| def get(self, *args, **kwargs): |
| return 'Hello, world!' |
| |
| app = webapp2.WSGIApplication([ |
| (r'/', HelloHandler), |
| ]) |
| app.router.set_dispatcher(custom_dispatcher) |
| |
| And that's all. Now we have a custom dispatcher set using the router method |
| :meth:`webapp2.Router.set_dispatcher`. Our ``HelloHandler`` returns a string |
| (or it could be tuple) that is used to create a ``Response`` object. |
| |
| Our custom dispatcher could implement its own URI matching and handler |
| dispatching mechanisms from scratch, but in this case it just extends the |
| default dispatcher a little bit, wrapping the returned value under certain |
| conditions. |
| |
| .. _guide.handlers.a.micro.framework.based.on.webapp2: |
| |
| A micro-framework based on webapp2 |
| ---------------------------------- |
| Following the previous idea of a custom dispatcher, we could go a little |
| further and extend webapp2 to accept routes registered using a decorator, |
| like in those Python micro-frameworks. |
| |
| Without much ado, ladies and gentlemen, we present micro-webapp2:: |
| |
| import webapp2 |
| |
| class WSGIApplication(webapp2.WSGIApplication): |
| def __init__(self, *args, **kwargs): |
| super(WSGIApplication, self).__init__(*args, **kwargs) |
| self.router.set_dispatcher(self.__class__.custom_dispatcher) |
| |
| @staticmethod |
| def custom_dispatcher(router, request, response): |
| rv = router.default_dispatcher(request, response) |
| if isinstance(rv, basestring): |
| rv = webapp2.Response(rv) |
| elif isinstance(rv, tuple): |
| rv = webapp2.Response(*rv) |
| |
| return rv |
| |
| def route(self, *args, **kwargs): |
| def wrapper(func): |
| self.router.add(webapp2.Route(handler=func, *args, **kwargs)) |
| return func |
| |
| return wrapper |
| |
| Save the above code as ``micro_webapp2.py``. Then you can import it in |
| ``main.py`` and define your handlers and routes like this:: |
| |
| import micro_webapp2 |
| |
| app = micro_webapp2.WSGIApplication() |
| |
| @app.route('/') |
| def hello_handler(request, *args, **kwargs): |
| return 'Hello, world!' |
| |
| def main(): |
| app.run() |
| |
| if __name__ == '__main__': |
| main() |
| |
| This example just demonstrates some of the power and flexibility that lies |
| behind webapp2; explore the :ref:`webapp2 API <api.webapp2>` to discover other |
| ways to modify or extend the application behavior. |
| |
| |
| Overriding __init__() |
| --------------------- |
| If you want to override the :meth:`webapp2.RequestHandler.__init__` method, |
| you must call :meth:`webapp2.RequestHandler.initialize` at the beginning of |
| the method. It'll set the current request, response and app objects as |
| attributes of the handler. For example:: |
| |
| class MyHandler(webapp2.RequestHandler): |
| def __init__(self, request, response): |
| # Set self.request, self.response and self.app. |
| self.initialize(request, response) |
| |
| # ... add your custom initializations here ... |
| # ... |
| |
| |
| Overriding dispatch() |
| --------------------- |
| One of the advantadges of webapp2 over webapp is that you can wrap the |
| dispatching process of :class:`webapp2.RequestHandler` to perform actions |
| before and/or after the requested method is dispatched. You can do this |
| overriding the :meth:`webapp2.RequestHandler.dispatch` method. This can be |
| useful, for example, to test if requirements were met before actually |
| dispatching the requested method, or to perform actions in the response object |
| after the method was dispatched. Here's an example:: |
| |
| class MyHandler(webapp2.RequestHandler): |
| def dispatch(self): |
| # ... check if requirements were met ... |
| # ... |
| |
| if requirements_were_met: |
| # Parent class will call the method to be dispatched |
| # -- get() or post() or etc. |
| super(MyHandler, self).dispatch() |
| else: |
| self.abort(403) |
| |
| In this case, if the requirements were not met, the method won't ever be |
| dispatched and a "403 Forbidden" response will be returned instead. |
| |
| There are several possibilities to explore overriding ``dispatch()``, like |
| performing common checkings, setting common attributes or post-processing the |
| response. |