Home | History | Annotate | Download | only in guide
      1 .. _guide.exceptions:
      2 
      3 Exception handling
      4 ==================
      5 A good app is prepared even when something goes wrong: a service is down,
      6 the application didn't expect a given input type or many other errors that
      7 can happen in a web application. To react to these cases, we need a good
      8 exception handling mechanism and prepare the app to handle the unexpected
      9 scenarios.
     10 
     11 
     12 HTTP exceptions
     13 ---------------
     14 WebOb provides a collection of exceptions that correspond to HTTP status codes.
     15 They all extend a base class, ``webob.exc.HTTPException``, also available in
     16 webapp2 as ``webapp2.HTTPException``.
     17 
     18 An ``HTTPException`` is also a WSGI application, meaning that an instance of it
     19 can be returned to be used as response. If an ``HTTPException`` is not handled,
     20 it will be used as a standard response, setting the header status code and
     21 a default error message in the body.
     22 
     23 
     24 Exceptions in handlers
     25 ----------------------
     26 Handlers can catch exceptions implementing the method
     27 :meth:`webapp2.RequestHandler.handle_exception`. It is a good idea to define
     28 a base class that catches generic exceptions, and if needed override
     29 ``handle_exception()`` in extended classes to set more specific responses.
     30 
     31 Here we will define a exception handling function in a base class, and the real
     32 app classes extend it::
     33 
     34     import logging
     35 
     36     import webapp2
     37 
     38     class BaseHandler(webapp2.RequestHandler):
     39         def handle_exception(self, exception, debug):
     40             # Log the error.
     41             logging.exception(exception)
     42 
     43             # Set a custom message.
     44             response.write('An error occurred.')
     45 
     46             # If the exception is a HTTPException, use its error code.
     47             # Otherwise use a generic 500 error code.
     48             if isinstance(exception, webapp2.HTTPException):
     49                 response.set_status(exception.code)
     50             else:
     51                 response.set_status(500)
     52 
     53     class HomeHandler(BaseHandler):
     54         def get(self):
     55             self.response.write('This is the HomeHandler.')
     56 
     57     class ProductListHandler(BaseHandler):
     58         def get(self):
     59             self.response.write('This is the ProductListHandler.')
     60 
     61 If something unexpected happens during the ``HomeHandler`` or
     62 ``ProductListHandler`` lifetime, ``handle_exception()`` will catch it because
     63 they extend a class that implements exception handling.
     64 
     65 You can use exception handling to log errors and display custom messages
     66 instead of a generic error. You could also render a template with a friendly
     67 message, or return a JSON with an error code, depending on your app.
     68 
     69 
     70 Exceptions in the WSGI app
     71 --------------------------
     72 Uncaught exceptions can also be handled by the WSGI application. The WSGI app
     73 is a good place to handle '404 Not Found' or '500 Internal Server Error'
     74 errors, since it serves as a last attempt to handle all uncaught exceptions,
     75 including non-registered URI paths or unexpected application behavior.
     76 
     77 We catch exceptions in the WSGI app using error handlers registered in
     78 :attr:`webapp2.WSGIApplication.error_handlers`. This is a dictionary that
     79 maps HTTP status codes to callables that will handle the corresponding error
     80 code. If the exception is not an ``HTTPException``, the status code 500 is
     81 used.
     82 
     83 Here we set error handlers to handle "404 Not Found" and "500 Internal Server
     84 Error"::
     85 
     86     import logging
     87 
     88     import webapp2
     89 
     90     def handle_404(request, response, exception):
     91         logging.exception(exception)
     92         response.write('Oops! I could swear this page was here!')
     93         response.set_status(404)
     94 
     95     def handle_500(request, response, exception):
     96         logging.exception(exception)
     97         response.write('A server error occurred!')
     98         response.set_status(500)
     99 
    100     app = webapp2.WSGIApplication([
    101         webapp2.Route('/', handler='handlers.HomeHandler', name='home')
    102     ])
    103     app.error_handlers[404] = handle_404
    104     app.error_handlers[500] = handle_500
    105 
    106 The error handler can be a simple function that accepts
    107 ``(request, response, exception)`` as parameters, and is responsible for
    108 setting the response status code and, if needed, logging the exception.
    109 
    110 
    111 abort()
    112 -------
    113 The function :func:`webapp2.abort` is a shortcut to raise one of the HTTP
    114 exceptions provided by WebOb: it takes an HTTP status code (403, 404, 500 etc)
    115 and raises the corresponding exception.
    116 
    117 Use ``abort`` (or :func:`webapp2.RequestHandler.abort` inside handlers)
    118 to raise an ``HTTPException`` to be handled by an exception handler.
    119 For example, we could call ``abort(404)`` when a requested item is not found
    120 in the database, and have an exception handler ready to handle 404s.
    121 
    122 Besides the status code, some extra keyword arguments can be passed to
    123 ``abort()``:
    124 
    125 detail
    126   An explanation about the error.
    127 comment
    128   An more detailed comment to be included in the response body.
    129 headers
    130   Extra response headers to be set.
    131 body_template
    132   A string to be used as template for the response body. The default template
    133   has the following format, with variables replaced by arguments, if defined:
    134 
    135 .. code-block:: html
    136 
    137    ${explanation}<br /><br />
    138    ${detail}
    139    ${html_comment}
    140