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.
A handler is equivalent to the Controller in the MVC 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
or, for compatibility purposes,
webapp.RequestHandler. Here is a simple
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
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 URI routing.
The default behavior of the
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:
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) 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
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.
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.
A handler method doesn’t need to return anything: it can simply write to the
response object using
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
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
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
HelloHandler returns a string
(or it could be tuple) that is used to create a
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.
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 webapp2 API to discover other ways to modify or extend the application behavior.
If you want to override the
you must call
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 ... # ...
One of the advantages of webapp2 over webapp is that you can wrap the
dispatching process of
webapp2.RequestHandler to perform actions
before and/or after the requested method is dispatched. You can do this
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
performing common checking, setting common attributes or post-processing the