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