Home | History | Annotate | Download | only in guide
      1 .. _guide.routing:
      2 
      3 URI routing
      4 ===========
      5 `URI routing` is the process of taking the requested URI and deciding which
      6 application handler will handle the current request. For this, we initialize
      7 the :class:`WSGIApplication` defining a list of `routes`: each `route`
      8 analyses the current request and, if it matches certain criterias, returns
      9 the handler and optional variables extracted from the URI.
     10 
     11 webapp2 offers a powerful and extensible system to match and build URIs,
     12 which is explained in details in this section.
     13 
     14 
     15 Simple routes
     16 -------------
     17 The simplest form of URI route in webapp2 is a tuple ``(regex, handler)``,
     18 where `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
     20 fully compatible with App Engine's webapp framework.
     21 
     22 This is how it works: a list of routes is registered in the
     23 :ref:`WSGI application <guide.app>`. When the application receives a request,
     24 it tries to match each one in order until one matches, and then call the
     25 corresponding handler. Here, for example, we define three handlers and
     26 register 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 
     47 When a request comes in, the application will match the request path to find
     48 the corresponding handler. If no route matches, an ``HTTPException`` is raised
     49 with status code 404, and the WSGI application can handle it accordingly (see
     50 :ref:`guide.exceptions`).
     51 
     52 The `regex` part is an ordinary regular expression (see the :py:mod:`re`
     53 module) that can define groups inside parentheses. The matched group values are
     54 passed to the handler as positional arguments. In the example above, the last
     55 route defines a group, so the handler will receive the matched value when the
     56 route matches (one or more digits in this case).
     57 
     58 The `handler` part is a callable as explained in :ref:`guide.handlers`, and
     59 can 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 
     62 Simple routes are easy to use and enough for a lot of cases but don't support
     63 keyword arguments, URI building, domain and subdomain matching, automatic
     64 redirection and other useful features. For this, webapp2 offers the extended
     65 routing mechanism that we'll see next.
     66 
     67 
     68 Extended routes
     69 ---------------
     70 webapp2 introduces a routing mechanism that extends the webapp model to provide
     71 additional 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 
     85 And several other features and benefits.
     86 
     87 The concept is similar to the simple routes we saw before, but instead of a
     88 tuple ``(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 
     97 The first argument in the routes above is a
     98 :ref:`URL template <guide.routing.the-url-template>`, the `handler`
     99 argument 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 
    103 Check :meth:`webapp2.Route.__init__` in the API reference for the parameters
    104 accepted by the ``Route`` constructor. We will explain some of them in details
    105 below.
    106 
    107 .. _guide.routing.the-url-template:
    108 
    109 The URL template
    110 ~~~~~~~~~~~~~~~~
    111 The URL template defines the URL path to be matched. It can have regular
    112 expressions for variables using the syntax ``<name:regex>``; everything
    113 outside of ``<>`` is not interpreted as a regular expression to be matched.
    114 Both name and regex are optional, like in the examples below:
    115 
    116 =================  ==================================
    117 Format             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 
    124 The same template can mix parts with name, regular expression or both.
    125 
    126 The name, if defined, is used to build URLs for the route. When it is set,
    127 the value of the matched regular expression is passed as keyword argument to
    128 the handler. Otherwise it is passed as positional argument.
    129 
    130 If only the name is set, it will match anything except a slash. So these
    131 routes 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 
    145 Lazy handlers
    146 ~~~~~~~~~~~~~
    147 One additional feature compared to webapp is that the handler can also be
    148 defined as a string in dotted notation to be lazily imported when needed.
    149 
    150 This is useful to avoid loading all modules when the app is initialized: we
    151 can define handlers in different modules without needing to import all of them
    152 to initialize the app. This is not only convenient but also speeds up the
    153 application startup.
    154 
    155 The 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
    157 strings 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 
    166 In the first time that one of these routes matches, the handlers will be
    167 automatically imported by the routing system.
    168 
    169 .. _guide.routing.custom-methods:
    170 
    171 Custom methods
    172 ~~~~~~~~~~~~~~
    173 A parameter ``handler_method`` can define the method of the handler that will
    174 be called, if handler is a class. If not defined, the default behavior is to
    175 translate 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 
    180 Alternatively, the handler method can be defined in the handler string,
    181 separated 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 
    187 Restricting HTTP methods
    188 ~~~~~~~~~~~~~~~~~~~~~~~~
    189 If needed, the route can define a sequence of allowed HTTP methods. Only if the
    190 request method is in that list or tuple the route will match. If the method is
    191 not allowed, an ``HTTPMethodNotAllowed`` exception is raised with status code
    192 405. For example::
    193 
    194     webapp2.Route(r'/products', handler='handlers.ProductsHandler', name='products-list', methods=['GET'])
    195 
    196 This is useful when using functions as handlers, or alternative handlers that
    197 don'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 
    202 Restricting URI schemes
    203 ~~~~~~~~~~~~~~~~~~~~~~~
    204 Like with HTTP methods, you can specify the URI schemes allowed for a route,
    205 if needed. This is useful if some URIs must be accessed using 'http' or 'https'
    206 only. 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 
    210 The above route will only match if the URI scheme is 'https'.
    211 
    212 
    213 .. _guide.routing.domain-and-subdomain-routing:
    214 
    215 Domain and subdomain routing
    216 ----------------------------
    217 The routing system can also handle domain and subdomain matching. This is done
    218 using a special route class provided in the :mod:`webapp2_extras.routes`
    219 module: the :class:`webapp2_extras.routes.DomainRoute`. It is initialized with
    220 a 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
    222 subdomain matches.
    223 
    224 For 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 
    236 In the example above, we define a template ``'<subdomain>.app-id.appspot.com'``
    237 for the domain matching. When a request comes in, only if the request server
    238 name matches that pattern, the nested route will be tested. Otherwise the
    239 routing system will test the next route until one matches. So the first route
    240 with path ``/`` will only match when a subdomain of the ``app-id.appspot.com``
    241 domain is accessed. Otherwise the second route with path ``/`` will be used.
    242 
    243 The template follows the same syntax used by :class:`webapp2.Route` and
    244 must define named groups if any value must be added to the match results.
    245 In the example above, an extra `subdomain` keyword is passed to the handler,
    246 but if the regex didn't define any named groups, nothing would be added.
    247 
    248 Matching only www, or anything except www
    249 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    250 A common need is to set some routes for the main subdomain (``www``) and
    251 different routes for other submains. The webapp2 routing system can handle
    252 this easily.
    253 
    254 To match only the ``www`` subdomain, simple set the domain template to a fixed
    255 value::
    256 
    257     routes.DomainRoute('www.mydomain.com', [
    258         webapp2.Route('/', handler=HomeHandler, name='home'),
    259     ])
    260 
    261 To match any subdomain except the ``www`` subdomain, set a regular expression
    262 that excludes ``www``::
    263 
    264     routes.DomainRoute(r'<subdomain:(?!www\.)[^.]+>.mydomain.com', [
    265         webapp2.Route('/', handler=HomeHandler, name='home'),
    266     ])
    267 
    268 Any subdomain that matches and is not ``www`` will be passed as a parameter
    269 ``subdomain`` to the handler.
    270 
    271 Similarly, you can restrict matches to the main ``appspot`` domain **or**
    272 a ``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 
    278 And 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 
    288 Path prefix routes
    289 ------------------
    290 The :mod:`webapp2_extras.routes` provides a class to wrap routes that start
    291 with a common path: the :mod:`webapp2_extras.routes.PathPrefixRoute`.
    292 The intention is to avoid repetition when defining routes.
    293 
    294 For 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 
    302 We 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 
    315 This is not only convenient, but also performs better: the nested routes
    316 will only be tested if the path prefix matches.
    317 
    318 
    319 .. _guide.routing.other-prefix-routes:
    320 
    321 Other prefix routes
    322 -------------------
    323 The :mod:`webapp2_extras.routes` has other convenience classes that accept
    324 nested 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 
    334 Building URIs
    335 -------------
    336 Because our routes have a ``name``, we can use the routing system to build
    337 URIs whenever we need to reference those resources inside the application.
    338 This 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
    341 attribute ``router`` in the WSGI application).
    342 
    343 For 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 
    351 Here 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 
    368 Variables are passed as positional or keyword arguments and are required if
    369 the route defines them. Keyword arguments that are not present in the route
    370 are added to the URI as a query string.
    371 
    372 Also, 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 
    385 Check :meth:`webapp2.Router.build` in the API reference for a complete
    386 explanation of the parameters used to build URIs.
    387 
    388 
    389 Routing attributes in the request object
    390 ----------------------------------------
    391 The parameters from the matched route are set as attributes of the request
    392 object when a route matches. They are ``request.route_args``, for positional
    393 arguments, and ``request.route_kwargs``, for keyword arguments.
    394 
    395 The matched route object is also available as ``request.route``.
    396