Porting Routes to a WSGI Web Framework %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% RoutesMiddleware ---------------- An application can create a raw mapper object and call its ``.match`` and ``.generate`` methods. However, WSGI applications probably want to use the ``RoutesMiddleware`` as Pylons does:: # In myapp/config/middleware.py from routes.middleware import RoutesMiddleware app = RoutesMiddleware(app, map) # ``map`` is a routes.Mapper. The middleware matches the requested URL and sets the following WSGI variables:: environ['wsgiorg.routing_args'] = ((url, match)) environ['routes.route'] = route environ['routes.url'] = url where ``match`` is the routing variables dict, ``route`` is the matched route, and ``url`` is a ``URLGenerator`` object. In Pylons, ``match`` is used by the dispatcher, and ``url`` is accessible as ``pylons.url``. The middleware handles redirect routes itself, issuing the appropriate redirect. The application is not called in this case. To debug routes, turn on debug logging for the "routes.middleware" logger. See the Routes source code for other features which may have been added. URL Resolution -------------- When the URL is looked up, it should be matched against the Mapper. When matching an incoming URL, it is assumed that the URL path is the only string being matched. All query args should be stripped before matching:: m.connect('/articles/{year}/{month}', controller='blog', action='view', year=None) m.match('/articles/2003/10') # {'controller':'blog', 'action':'view', 'year':'2003', 'month':'10'} Matching a URL will return a dict of the match results, if you'd like to differentiate between where the argument came from you can use routematch which will return the Route object that has all these details:: m.connect('/articles/{year}/{month}', controller='blog', action='view', year=None) result = m.routematch('/articles/2003/10') # result is a tuple of the match dict and the Route object # result[0] - {'controller':'blog', 'action':'view', 'year':'2003', 'month':'10'} # result[1] - Route object # result[1].defaults - {'controller':'blog', 'action':'view', 'year':None} # result[1].hardcoded - ['controller', 'action'] Your integration code is then expected to dispatch to a controller and action in the dict. How it does this is entirely up to the framework integrator. Your integration should also typically provide the web developer a mechanism to access the additional dict values. Request Configuration --------------------- If you intend to support ``url_for()`` and ``redirect_to()``, they depend on a singleton object which requires additional configuration. You're better off not supporting them at all because they will be deprecated soon. ``URLGenerator`` is the forward-compatible successor to ``url_for()``. ``redirect_to()`` is better done in the web framework`as in ``pylons.controllers.util.redirect_to()``. ``url_for()`` and ``redirect_to()`` need information on the current request, and since they can be called from anywhere they don't have direct access to the WSGI environment. To remedy this, Routes provides a thread-safe singleton class called "request_config", which holds the request information for the current thread. You should update this after matching the incoming URL but before executing any code that might call the two functions. Here is an example:: from routes import request_config config = request_config() config.mapper = m # Your mapper object config.mapper_dict = result # The dict from m.match for this URL request config.host = hostname # The server hostname config.protocol = port # Protocol used, http, https, etc. config.redirect = redir_func # A redirect function used by your framework, that is # expected to take as the first non-keyword arg a single # full or relative URL See the docstring for ``request_config`` in routes/__init__.py to make sure you've initialized everything necessary.