The URL router is the central part of a nacelle application, mapping incoming URLs to the appropriate handlers.
By default, nacelle looks for ROUTES (should be an iterable containing webapp2.Route objects as in webapp2 itself) in the app module. This location can be configured using nacelle’s settings.py as such:
# Python dotted path to the routes for the app ROUTES_MODULE = 'app.ROUTES' # default routes module
For example, if your list of configured routes was defined as routes in the apps.core.routes module, you could update your settings.py to include the line:
# Python dotted path to the routes for the app ROUTES_MODULE = 'apps.core.routes.routes' # custom routes module
For the most part, nacelle uses webapp2’s routing infrastructure, and you should consult those docs when you have any questions or issues.
When a request comes in, the application will match the request path to find the corresponding handler. If no route matches, an HTTPException is raised with status code 404, and the WSGI application can handle it accordingly.
As a simple example, assuming the default configuration, the following could be defined in app.py and would map 3 different URL patterns to 3 different request handlers:
ROUTES = [ webapp2.Route(r'/', handler=HomeHandler, name='home'), webapp2.Route(r'/products', handler=ProductListHandler, name='product-list'), webapp2.Route(r'/products/<product_id>', handler=ProductHandler, name='product'), ]
The first argument in the routes above is a URL template, the handler argument is the request handler to be used (can also be a string in dotted notation to be lazily imported when needed), and the name argument third is a name used to build a URI for that route.
The webapp2_extras.routes provides several classes to wrap routes that share common characteristics:
- webapp2_extras.routes.PathPrefixRoute: receives a url path prefix and a list of routes that start with that prefix.
- webapp2_extras.routes.HandlerPrefixRoute: receives a handler module prefix in dotted notation and a list of routes that use that module.
- webapp2_extras.routes.NamePrefixRoute: receives a handler name prefix and a list of routes that start with that name.
The intention is to avoid repetition when defining routes. nacelle takes this concept one step further and provides a single route class that allows combining all three types of built-in PrefixRoute.
For example, imagine we have these routes:
from webapp2 import Route ROUTES = [ Route('/users/<user:\w+>/', 'users.UserOverviewHandler', 'user-overview'), Route('/users/<user:\w+>/profile', 'users.UserProfileHandler', 'user-profile'), Route('/users/<user:\w+>/projects', 'users.UserProjectsHandler', 'user-projects'), ]
We could refactor them to use common prefixes:
from nacelle.core.routes import MultiPrefixRoute from webapp2 import Route ROUTES = [ MultiPrefixRoute( handler_pfx='users.', name_pfx='user-', path_pfx='/users/<user:\w+>', routes=[ Route('/', 'UserOverviewHandler', 'overview'), Route('/profile', 'UserProfileHandler', 'profile'), Route('/projects', 'UserProjectsHandler', 'projects'), ], ) ]
This is not only convenient, but also performs better: the nested routes will only be tested if the path prefix matches.