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