1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
.. index::
triple: differences; URL dispatch; traversal
pair: mapping; URLs
.. _url_mapping_chapter:
Mapping URLs to Code
--------------------
:mod:`repoze.bfg` supports :term:`URL dispatch` via a subsystem that
was inspired by the :term:`Routes` system used by :term:`Pylons`.
:term:`URL dispatch` is convenient and straightforward: an incoming
URL is checked against a list of potential matches in a predefined
order. Each potential match often maps directly to a :term:`view
callable`. When a match is found, it usually means that a particular
:term:`view callable` is invoked.
Like :term:`Zope`, :mod:`repoze.bfg` can also map URLs to code
slightly differently, by using using object graph :term:`traversal`.
Graph-traversal based dispatching is useful if you like your URLs to
represent an arbitrary hierarchy of potentially heterogeneous items,
or if you need to attach "instance-level" security (akin to
"row-level" security in relational parlance) declarations to
:term:`model` instances. Traversal is slightly more complex than URL
dispatch, but it is also a bit more powerful.
:term:`URL dispatch` can easily handle URLs such as
``http://example.com/members/Chris``, where it's assumed that each
item "below" ``members`` in the URL represents a member in the system.
You just match everything "below" ``members`` to a particular view.
For example, you might configure a :term:`route` to match against the
following URL patterns:
.. code-block:: text
archives/:year/:month/:day
members/:membername
In this configuration, there are exactly two types of URLs that will
match views in your application: ones that start with ``/archives``
and have subsequent path elements that represent a year, month, and
day. And ones that start with ``/members`` which are followed by a
path segment containing a member's name. This is very simple. When
you limit your application to using URL dispatch, you know every URL
that your application might generate or respond to, and all the URL
matching elements are listed in a single place.
:term:`URL dispatch` is not very good, however, at inferring the
difference between sets of URLs such as:
.. code-block:: text
http://example.com/members/Chris/document
http://example.com/members/Chris/stuff/page
...wherein you'd like the ``document`` in the first URL to represent a
PDF document, and ``/stuff/page`` in the second to represent an
*OpenOffice* document in a "stuff" folder. It takes more pattern
matching assertions to be able to make URLs like these work in
URL-dispatch based systems, and some assertions just aren't possible.
For example, URL-dispatch based systems don't deal very well with URLs
that represent arbitrary-depth hierarchies.
:term:`traversal` works well for these types of "ambiguous" URLs and
for URLs that represent arbitrary-depth hierarchies. When traversal
is used, each URL segment represents a single traversal step through
an edge of a graph. So a URL like ``http://example.com/a/b/c`` can be
thought of as a graph traversal on the ``example.com`` site through
the edges ``a``, ``b``, and ``c``.
If you're willing to treat your application models as a graph that can
be traversed, it also becomes easy to provide "row-level security" (in
common relational parlance): you just attach a security declaration to
each instance in the graph. This is not as easy in frameworks that
use URL-based dispatch.
Graph traversal is materially more complex than URL-based dispatch,
however, if only because it requires the construction and maintenance
of a graph, and it requires the developer to think about mapping URLs
to code in terms of traversing the graph. (How's *that* for
self-referential! ;-) )
In essence, the choice to use graph traversal vs. URL dispatch is
largely religious. Graph traversal dispatch probably just doesn't
make any sense when you possess completely "square" data stored in a
relational database. However, when you have a hierarchical data
store, it can provide advantages over using URL-based dispatch.
:mod:`repoze.bfg` provides support for both approaches. You can use
either as you see fit.
.. toctree::
:maxdepth: 2
traversal
urldispatch
hybrid
|