diff options
author | Ryan Petrello <lists@ryanpetrello.com> | 2012-03-29 10:07:08 -0700 |
---|---|---|
committer | Ryan Petrello <lists@ryanpetrello.com> | 2012-03-29 10:07:08 -0700 |
commit | 0a3f41ccddd3c506127bcc1cf241196f5cbea6fe (patch) | |
tree | 2544e88d458b66e06e82f515ca28246a7615be8c | |
parent | a7d4684ac5dc704b3fe8320618e71d462ee1209e (diff) | |
parent | 00360001b19999cb491f10049ce6e0d63e3b59cf (diff) | |
download | pecan-0a3f41ccddd3c506127bcc1cf241196f5cbea6fe.tar.gz |
Merge pull request #120 from coderpete/next
Custom Error Docs
-rw-r--r-- | docs/source/errors.rst | 113 | ||||
-rw-r--r-- | pecan/middleware/errordocument.py | 11 | ||||
-rw-r--r-- | pecan/scaffolds/base/config.py_tmpl | 2 |
3 files changed, 122 insertions, 4 deletions
diff --git a/docs/source/errors.rst b/docs/source/errors.rst index 01f2a87..afb4a9b 100644 --- a/docs/source/errors.rst +++ b/docs/source/errors.rst @@ -2,4 +2,115 @@ Custom Error Documents ====================== -TODO +In this article we will configure a Pecan application to display a custom +Error page whenever the server returns ``404 Page not Found`` status. + +This article assumes that you have already created a test application as +described in :ref:`quick_start` + +.. note:: + While this example focuses on the ``HTTP 404 status`` message, the same + technique may be applied to define custom actions for any of the ``HTTP`` + status response codes in the 400 and 500 range. You are well advised to use + this power judiciously. + +.. _overview: + +Overview +-------- + +Pecan makes it simple to customize error documents in two simple steps: + + * :ref:`configure` of the HTTP status messages you want to handle + in your application's config.py + * :ref:`controllers` to handle the status messages you have configured + +.. _configure: + +Configure Routing +----------------- +Let's configure our application *test_project* to route the ``HTTP 404`` +(page not found) messages to our custom built controller. + +First, we tweak test_project/config.py:: + + # Pecan Application Configurations + app = { + 'root' : 'test_project.controllers.root.RootController', + 'modules' : ['test_project'], + 'static_root' : '%(confdir)s/public', + 'template_path' : '%(confdir)s/test_project/templates', + 'reload' : True, + 'debug' : True, + + ## modify the 'errors' element to direct HTTP status codes to your + ## own controller. + 'errors' : { + #404 : '/error/404', + 404 : '/notfound', + '__force_dict__' : True + } + } + +Instead of the default error page, Pecan will now route 404 messages to our +very own controller named *notfound*. + +Let us now implement the *notfound* Controller + +.. _controllers: + +Write Custom Controllers +------------------------ +The easiest way to implement our custom *notfound* error controller is to +add it to ``test_project.root.RootController`` class +(typically in test_project/controllers/root.py):: + + from pecan import expose + from webob.exc import status_map + + + class RootController(object): + + @expose(generic=True, template='index.html') + def index(self): + return dict() + + @index.when(method='POST') + def index_post(self, q): + redirect('http://pecan.readthedocs.org/en/latest/search.html?q=%s' % q) + + + ## custom handling of '404 Page Not Found' messages + @expose('error.html') + def notfound(self): + return dict(status=404, message="test_project does not have this page") + + + @expose('error.html') + def error(self, status): + try: + status = int(status) + except ValueError: + status = 0 + message = getattr(status_map.get(status), 'explanation', '') + return dict(status=status, message=message) + + +And that's it! + +Notice that the only bit of code we added to our RootController is:: + + ## custom handling of '404 Page Not Found' messages + @expose('error.html') + def notfound(self): + return dict(status=404, message="test_project does not have this page") + +We simply ``@expose`` the ``notfound`` controller with the ``error.html`` +template (which was conveniently generated for us and placed under +test_project/templates/ when we created ``test_project``). As with any common +controller *@expose*'d through a template, we return a dictionary of variables +for interpolation by the template renderer. + +Now we can modify the error template, or write a brand new one to make the 404 +error status page or ``test_project`` as pretty or fancy as we want. + diff --git a/pecan/middleware/errordocument.py b/pecan/middleware/errordocument.py index 8a7aeab..22443cc 100644 --- a/pecan/middleware/errordocument.py +++ b/pecan/middleware/errordocument.py @@ -36,7 +36,11 @@ class StatusPersist(object): class ErrorDocumentMiddleware(object): - + ''' + Intersects HTTP response status code, looks it up in the error map defined + in the Pecan app config.py, and routes to the controller assigned to that + status. + ''' def __init__(self, app, error_map): self.app = app self.error_map = error_map @@ -44,6 +48,10 @@ class ErrorDocumentMiddleware(object): def __call__(self, environ, start_response): def replacement_start_response(status, headers, exc_info=None): + ''' + Overrides the default response if the status is defined in the + Pecan app error map configuration. + ''' try: status_code = int(status.split(' ')[0]) except (ValueError, TypeError): # pragma: nocover @@ -60,7 +68,6 @@ class ErrorDocumentMiddleware(object): self.error_map[status_code] ) raise ForwardRequestException(factory=factory) - return start_response(status, headers, exc_info) app_iter = self.app(environ, replacement_start_response) diff --git a/pecan/scaffolds/base/config.py_tmpl b/pecan/scaffolds/base/config.py_tmpl index b820e59..06507d9 100644 --- a/pecan/scaffolds/base/config.py_tmpl +++ b/pecan/scaffolds/base/config.py_tmpl @@ -12,7 +12,7 @@ app = { 'template_path': '%(confdir)s/${package}/templates', 'debug': True, 'errors': { - '404': '/error/404', + 404: '/error/404', '__force_dict__': True } } |