1.. _guide.routing:
2
3URI routing
4===========
5`URI routing` is the process of taking the requested URI and deciding which
6application handler will handle the current request. For this, we initialize
7the :class:`WSGIApplication` defining a list of `routes`: each `route`
8analyses the current request and, if it matches certain criterias, returns
9the handler and optional variables extracted from the URI.
10
11webapp2 offers a powerful and extensible system to match and build URIs,
12which is explained in details in this section.
13
14
15Simple routes
16-------------
17The simplest form of URI route in webapp2 is a tuple ``(regex, handler)``,
18where `regex` is a regular expression to match the requested URI path and
19`handler` is a callable to handle the request. This routing mechanism is
20fully compatible with App Engine's webapp framework.
21
22This is how it works: a list of routes is registered in the
23:ref:`WSGI application <guide.app>`. When the application receives a request,
24it tries to match each one in order until one matches, and then call the
25corresponding handler. Here, for example, we define three handlers and
26register three routes that point to those handlers::
27
28    class HomeHandler(webapp2.RequestHandler):
29        def get(self):
30            self.response.write('This is the HomeHandler.')
31
32    class ProductListHandler(webapp2.RequestHandler):
33        def get(self):
34            self.response.write('This is the ProductListHandler.')
35
36    class ProductHandler(webapp2.RequestHandler):
37        def get(self, product_id):
38            self.response.write('This is the ProductHandler. '
39                'The product id is %s' % product_id)
40
41    app = webapp2.WSGIApplication([
42        (r'/', HomeHandler),
43        (r'/products', ProductListHandler),
44        (r'/products/(\d+)', ProductHandler),
45    ])
46
47When a request comes in, the application will match the request path to find
48the corresponding handler. If no route matches, an ``HTTPException`` is raised
49with status code 404, and the WSGI application can handle it accordingly (see
50:ref:`guide.exceptions`).
51
52The `regex` part is an ordinary regular expression (see the :py:mod:`re`
53module) that can define groups inside parentheses. The matched group values are
54passed to the handler as positional arguments. In the example above, the last
55route defines a group, so the handler will receive the matched value when the
56route matches (one or more digits in this case).
57
58The `handler` part is a callable as explained in :ref:`guide.handlers`, and
59can also be a string in dotted notation to be lazily imported when needed
60(see explanation below in :ref:`Lazy Handlers <guide.routing.lazy-handlers>`).
61
62Simple routes are easy to use and enough for a lot of cases but don't support
63keyword arguments, URI building, domain and subdomain matching, automatic
64redirection and other useful features. For this, webapp2 offers the extended
65routing mechanism that we'll see next.
66
67
68Extended routes
69---------------
70webapp2 introduces a routing mechanism that extends the webapp model to provide
71additional features:
72
73- **URI building:** the registered routes can be built when needed, avoiding
74  hardcoded URIs in the app code and templates. If you change the route
75  definition in a compatible way during development, all places that use that
76  route will continue to point to the correct URI. This is less error prone and
77  easier to maintain.
78- **Keyword arguments:** handlers can receive keyword arguments from the
79  matched URIs. This is easier to use and also more maintanable than positional
80  arguments.
81- **Nested routes:** routes can be extended to match more than the request
82  path. We will see below a route class that can also match domains and
83  subdomains.
84
85And several other features and benefits.
86
87The concept is similar to the simple routes we saw before, but instead of a
88tuple ``(regex, handler)``, we define each route using the class
89:class:`webapp2.Route`. Let's remake our previous routes using it::
90
91    app = webapp2.WSGIApplication([
92        webapp2.Route(r'/', handler=HomeHandler, name='home'),
93        webapp2.Route(r'/products', handler=ProductListHandler, name='product-list'),
94        webapp2.Route(r'/products/<product_id:\d+>', handler=ProductHandler, name='product'),
95    ])
96
97The first argument in the routes above is a
98:ref:`URL template <guide.routing.the-url-template>`, the `handler`
99argument is the :ref:`request handler <guide.handlers>` to be used, and the
100`name` argument third is a name used to
101:ref:`build a URI <guide.routing.building-uris>` for that route.
102
103Check :meth:`webapp2.Route.__init__` in the API reference for the parameters
104accepted by the ``Route`` constructor. We will explain some of them in details
105below.
106
107.. _guide.routing.the-url-template:
108
109The URL template
110~~~~~~~~~~~~~~~~
111The URL template defines the URL path to be matched. It can have regular
112expressions for variables using the syntax ``<name:regex>``; everything
113outside of ``<>`` is not interpreted as a regular expression to be matched.
114Both name and regex are optional, like in the examples below:
115
116=================  ==================================
117Format             Example
118=================  ==================================
119``<name>``         ``'/blog/<year>/<month>'``
120``<:regex>``       ``'/blog/<:\d{4}>/<:\d{2}>'``
121``<name:regex>``   ``'/blog/<year:\d{4}>/<month:\d{2}>'``
122=================  ==================================
123
124The same template can mix parts with name, regular expression or both.
125
126The name, if defined, is used to build URLs for the route. When it is set,
127the value of the matched regular expression is passed as keyword argument to
128the handler. Otherwise it is passed as positional argument.
129
130If only the name is set, it will match anything except a slash. So these
131routes are equivalent::
132
133    Route('/<user_id>/settings', handler=SettingsHandler, name='user-settings')
134    Route('/<user_id:[^/]+>/settings', handler=SettingsHandler, name='user-settings')
135
136.. note::
137   The handler only receives ``*args`` if no named variables are
138   set. Otherwise, the handler only receives ``**kwargs``. This
139   allows you to set regular expressions that are not captured:
140   just mix named and unnamed variables and the handler will
141   only receive the named ones.
142
143.. _guide.routing.lazy-handlers:
144
145Lazy handlers
146~~~~~~~~~~~~~
147One additional feature compared to webapp is that the handler can also be
148defined as a string in dotted notation to be lazily imported when needed.
149
150This is useful to avoid loading all modules when the app is initialized: we
151can define handlers in different modules without needing to import all of them
152to initialize the app. This is not only convenient but also speeds up the
153application startup.
154
155The string must contain the package or module name and the name of the handler
156(a class or function name). Our previous example could be rewritten using
157strings instead of handler classes and splitting our handlers in two files,
158``handlers.py`` and ``products.py``::
159
160    app = webapp2.WSGIApplication([
161        (r'/', 'handlers.HomeHandler'),
162        (r'/products', 'products.ProductListHandler'),
163        (r'/products/(\d+)', 'products.ProductHandler'),
164    ])
165
166In the first time that one of these routes matches, the handlers will be
167automatically imported by the routing system.
168
169.. _guide.routing.custom-methods:
170
171Custom methods
172~~~~~~~~~~~~~~
173A parameter ``handler_method`` can define the method of the handler that will
174be called, if handler is a class. If not defined, the default behavior is to
175translate the HTTP method to a handler method, as explained in
176:ref:`guide.handlers`. For example::
177
178    webapp2.Route(r'/products', handler='handlers.ProductsHandler', name='products-list', handler_method='list_products')
179
180Alternatively, the handler method can be defined in the handler string,
181separated by a colon. This is equivalent to the previous example::
182
183    webapp2.Route(r'/products', handler='handlers.ProductsHandler:list_products', name='products-list')
184
185.. _guide.routing.restricting-http-methods:
186
187Restricting HTTP methods
188~~~~~~~~~~~~~~~~~~~~~~~~
189If needed, the route can define a sequence of allowed HTTP methods. Only if the
190request method is in that list or tuple the route will match. If the method is
191not allowed, an ``HTTPMethodNotAllowed`` exception is raised with status code
192405. For example::
193
194    webapp2.Route(r'/products', handler='handlers.ProductsHandler', name='products-list', methods=['GET'])
195
196This is useful when using functions as handlers, or alternative handlers that
197don't translate the HTTP method to the handler method like the default
198:class:`webapp2.RequestHandler` does.
199
200.. _guide.routing.restricting-uri-schemes:
201
202Restricting URI schemes
203~~~~~~~~~~~~~~~~~~~~~~~
204Like with HTTP methods, you can specify the URI schemes allowed for a route,
205if needed. This is useful if some URIs must be accessed using 'http' or 'https'
206only. For this, set the ``schemes`` parameter when defining a route::
207
208    webapp2.Route(r'/products', handler='handlers.ProductsHandler', name='products-list', schemes=['https'])
209
210The above route will only match if the URI scheme is 'https'.
211
212
213.. _guide.routing.domain-and-subdomain-routing:
214
215Domain and subdomain routing
216----------------------------
217The routing system can also handle domain and subdomain matching. This is done
218using a special route class provided in the :mod:`webapp2_extras.routes`
219module: the :class:`webapp2_extras.routes.DomainRoute`. It is initialized with
220a pattern to match the current server name and a list of nested
221:class:`webapp2.Route` instances that will only be tested if the domain or
222subdomain matches.
223
224For example, to restrict routes to a subdomain of the appspot domain::
225
226    import webapp2
227    from webapp2_extras import routes
228
229    app = webapp2.WSGIApplication([
230        routes.DomainRoute('<subdomain>.app-id.appspot.com', [
231            webapp2.Route('/', handler=SubdomainHomeHandler, name='subdomain-home'),
232        ]),
233        webapp2.Route('/', handler=HomeHandler, name='home'),
234    ])
235
236In the example above, we define a template ``'<subdomain>.app-id.appspot.com'``
237for the domain matching. When a request comes in, only if the request server
238name matches that pattern, the nested route will be tested. Otherwise the
239routing system will test the next route until one matches. So the first route
240with path ``/`` will only match when a subdomain of the ``app-id.appspot.com``
241domain is accessed. Otherwise the second route with path ``/`` will be used.
242
243The template follows the same syntax used by :class:`webapp2.Route` and
244must define named groups if any value must be added to the match results.
245In the example above, an extra `subdomain` keyword is passed to the handler,
246but if the regex didn't define any named groups, nothing would be added.
247
248Matching only www, or anything except www
249~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
250A common need is to set some routes for the main subdomain (``www``) and
251different routes for other submains. The webapp2 routing system can handle
252this easily.
253
254To match only the ``www`` subdomain, simple set the domain template to a fixed
255value::
256
257    routes.DomainRoute('www.mydomain.com', [
258        webapp2.Route('/', handler=HomeHandler, name='home'),
259    ])
260
261To match any subdomain except the ``www`` subdomain, set a regular expression
262that excludes ``www``::
263
264    routes.DomainRoute(r'<subdomain:(?!www\.)[^.]+>.mydomain.com', [
265        webapp2.Route('/', handler=HomeHandler, name='home'),
266    ])
267
268Any subdomain that matches and is not ``www`` will be passed as a parameter
269``subdomain`` to the handler.
270
271Similarly, you can restrict matches to the main ``appspot`` domain **or**
272a ``www`` domain from a custom domain::
273
274    routes.DomainRoute(r'<:(app-id\.appspot\.com|www\.mydomain\.com)>', [
275        webapp2.Route('/', handler=HomeHandler, name='home'),
276    ])
277
278And then have a route that matches subdomains of the main ``appspot`` domain
279**or** from a custom domain, except ``www``::
280
281    routes.DomainRoute(r'<subdomain:(?!www)[^.]+>.<:(app-id\.appspot\.com|mydomain\.com)>', [
282        webapp2.Route('/', handler=HomeHandler, name='home'),
283    ])
284
285
286.. _guide.routing.path-prefix-routes:
287
288Path prefix routes
289------------------
290The :mod:`webapp2_extras.routes` provides a class to wrap routes that start
291with a common path: the :mod:`webapp2_extras.routes.PathPrefixRoute`.
292The intention is to avoid repetition when defining routes.
293
294For example, imagine we have these routes::
295
296    app = WSGIApplication([
297        Route('/users/<user:\w+>/', UserOverviewHandler, 'user-overview'),
298        Route('/users/<user:\w+>/profile', UserProfileHandler, 'user-profile'),
299        Route('/users/<user:\w+>/projects', UserProjectsHandler, 'user-projects'),
300    ])
301
302We could refactor them to reuse the common path prefix::
303
304    import webapp2
305    from webapp2_extras import routes
306
307    app = WSGIApplication([
308        routes.PathPrefixRoute('/users/<user:\w+>', [
309            webapp2.Route('/', UserOverviewHandler, 'user-overview'),
310            webapp2.Route('/profile', UserProfileHandler, 'user-profile'),
311            webapp2.Route('/projects', UserProjectsHandler, 'user-projects'),
312        ]),
313    ])
314
315This is not only convenient, but also performs better: the nested routes
316will only be tested if the path prefix matches.
317
318
319.. _guide.routing.other-prefix-routes:
320
321Other prefix routes
322-------------------
323The :mod:`webapp2_extras.routes` has other convenience classes that accept
324nested routes with a common attribute prefix:
325
326- :mod:`webapp2_extras.routes.HandlerPrefixRoute`: receives a handler module
327  prefix in dotted notation and a list of routes that use that module.
328- :mod:`webapp2_extras.routes.NamePrefixRoute`: receives a handler name
329  prefix and a list of routes that start with that name.
330
331
332.. _guide.routing.building-uris:
333
334Building URIs
335-------------
336Because our routes have a ``name``, we can use the routing system to build
337URIs whenever we need to reference those resources inside the application.
338This is done using the function :func:`webapp2.uri_for` or the method
339:meth:`webapp2.RequestHandler.uri_for` inside a handler, or calling
340:meth:`webapp2.Router.build` directly (a ``Router`` instance is set as an
341attribute ``router`` in the WSGI application).
342
343For example, if you have these routes defined for the application::
344
345    app = webapp2.WSGIApplication([
346        webapp2.Route('/', handler='handlers.HomeHandler', name='home'),
347        webapp2.Route('/wiki', handler=WikiHandler, name='wiki'),
348        webapp2.Route('/wiki/<page>', handler=WikiHandler, name='wiki-page'),
349    ])
350
351Here are some examples of how to generate URIs for them::
352
353    # /
354    uri = uri_for('home')
355    # http://localhost:8080/
356    uri = uri_for('home', _full=True)
357    # /wiki
358    uri = uri_for('wiki')
359    # http://localhost:8080/wiki
360    uri = uri_for('wiki', _full=True)
361    # http://localhost:8080/wiki#my-heading
362    uri = uri_for('wiki', _full=True, _fragment='my-heading')
363    # /wiki/my-first-page
364    uri = uri_for('wiki-page', page='my-first-page')
365    # /wiki/my-first-page?format=atom
366    uri = uri_for('wiki-page', page='my-first-page', format='atom')
367
368Variables are passed as positional or keyword arguments and are required if
369the route defines them. Keyword arguments that are not present in the route
370are added to the URI as a query string.
371
372Also, when calling ``uri_for()``, a few keywords have special meaning:
373
374_full
375  If True, builds an absolute URI.
376_scheme
377  URI scheme, e.g., `http` or `https`. If defined, an absolute URI is always
378  returned.
379_netloc
380  Network location, e.g., `www.google.com`. If defined, an absolute URI is
381  always returned.
382_fragment
383  If set, appends a fragment (or "anchor") to the generated URI.
384
385Check :meth:`webapp2.Router.build` in the API reference for a complete
386explanation of the parameters used to build URIs.
387
388
389Routing attributes in the request object
390----------------------------------------
391The parameters from the matched route are set as attributes of the request
392object when a route matches. They are ``request.route_args``, for positional
393arguments, and ``request.route_kwargs``, for keyword arguments.
394
395The matched route object is also available as ``request.route``.
396