summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2008-11-14 05:25:57 +0000
committerChris McDonough <chrism@agendaless.com>2008-11-14 05:25:57 +0000
commitf7241b44d41db7a6788aa219b556a18981a8c913 (patch)
tree446925220ebb7b2284c62f99e9b8c03717947986 /docs
parent91362d1cabc8429d9b31a1b64766fe03ece24767 (diff)
downloadpyramid-f7241b44d41db7a6788aa219b556a18981a8c913.tar.gz
pyramid-f7241b44d41db7a6788aa219b556a18981a8c913.tar.bz2
pyramid-f7241b44d41db7a6788aa219b556a18981a8c913.zip
- Document adding a request type interface to the request via a
subscriber function in the events narrative documentation.
Diffstat (limited to 'docs')
-rw-r--r--docs/narr/events.rst93
1 files changed, 78 insertions, 15 deletions
diff --git a/docs/narr/events.rst b/docs/narr/events.rst
index 1e69a6f7f..2e94c4407 100644
--- a/docs/narr/events.rst
+++ b/docs/narr/events.rst
@@ -88,6 +88,12 @@ application, because the interface defined at
``repoze.bfg.interfaces.INewResponse`` says it must. These particular
interfaces are documented in the :ref:`events_module` API chapter.
+.. note::
+
+ Usually postprocessing requests is better handled in middleware
+ components. The ``INewResponse`` event exists purely for symmetry
+ with ``INewRequest``, really.
+
The *subscriber* ZCML element takes two values: ``for``, which is the
interface the subscriber is registered for (which limits the events
that the subscriber will receive to those specified by the interface),
@@ -96,24 +102,81 @@ function.
The return value of a subscriber function is ignored.
-Uses For Events
----------------
+Using An Event to Vary the Request Type
+---------------------------------------
-Here are some things that events are useful for:
+The most common usage of the ``INewRequestEvent`` is to attach an
+:term:`interface` to the request to be able to differentiate a request
+issued by a browser from a request issued by an XML-RPC from a request
+issued by a REST client. This makes it possible to register different
+views against different ``request_type`` interfaces; for instance,
+depending on request headers, you might return JSON or XML data.
-- Attaching different interfaces to the request to be able to
- differentiate e.g. requests from a browser against requests from an
- XML-RPC client within view code. To do this, you'd subscribe a
- function to ```INewRequest``, and use the
- ``zope.interface.alsoProvides`` function to add one or more
- interfaces to the request object.
+To do this, you should subscribe an function to the ``INewRequest``
+event type, and use the ``zope.interface.alsoProvides`` API within the
+function to add one or more interfaces to the request object provided
+by the event. Here's an example.
-- Post-processing all response output by subscribing to
- ``INewResponse``, for example, modifying headers.
+.. code-block:: python
+ :linenos:
- .. note::
+ from zope.interface import alsoProvides
+ from zope.interface import Interface
+
+ class IRESTRequest(Interface):
+ """ A request from a REST client that sets an Accept:
+ application/xml header"""
+
+ class IJSONRequest(Interface):
+ """ A request from a JSON client """
+
+ def categorize_request(event):
+ request = event.request
+ accept = request.headers.get('accept', '')
+ if 'application/xml' in accept:
+ alsoProvides(request, IRestRequest)
+ if 'application.json' in accept:
+ alsoProvides(request, IJSONRequest)
+
+Then in your view registration ZCML, you can use the ``request_type``
+attribute to point at different view functions depending upon the
+interface implemented by the request. For example, if the above
+subscriber function was registered, the three view registrations below
+could be used to point at separate view functions using separate
+request type interfaces for the same model object.
- Usually postprocessing requests is better handled in middleware
- components. The ``INewResponse`` event exists purely for
- symmetry with ``INewRequest``, really.
+.. code-block:: xml
+ :linenos:
+ <!-- html view -->
+ <bfg:view
+ for=".models.MyModel"
+ request_type="repoze.bfg.interfaces.IRequest"
+ view=".views.html_view"/>
+
+ <!-- xml (REST) view -->
+ <bfg:view
+ for=".models.MyModel"
+ request_type=".interfaces.IRESTRequest"
+ view=".views.rest_view"/>
+
+ <!-- JSON view -->
+ <bfg:view
+ for=".models.MyModel"
+ request_type=".interfaces.IJSONRequest"
+ view=".views.json_view"/>
+
+The interface ``repoze.bfg.interfaces.IRequest`` is automatically
+implemented by every :mod:`repoze.bfg` request, so all requests will
+implement that type, and views registered against models which do not
+supply a ``request_type`` will be considered to be registered for this
+``IRequest`` as a default.
+
+Of course, you are not limited to using the ``Accept`` header to
+determine which interfaces to attach to a request. For example, you
+might also choose to use hostname
+(e.g. ``request.environ.get('HTTP_HOST',
+request.environ['SERVER_NAME'])``) in order to "skin" your application
+differently based on whether the user should see the "management"
+(e.g. "manage.myapp.com") presentation of the application or the
+"retail" presentation (e.g. "www.myapp.com").