=========== URL Routing =========== .. module:: werkzeug.routing When it comes to combining multiple controller or view functions (however you want to call them), you need a dispatcher. A simple way would be applying regular expression tests on ``PATH_INFO`` and call registered callback functions that return the value. Werkzeug provides a much more powerful system, similar to `Routes`_. All the objects mentioned on this page must be imported from :mod:`werkzeug.routing`, not from :mod:`werkzeug`! .. _Routes: https://routes.readthedocs.io/en/latest/ Quickstart ========== Here is a simple example which could be the URL definition for a blog:: from werkzeug.routing import Map, Rule, NotFound, RequestRedirect url_map = Map([ Rule('/', endpoint='blog/index'), Rule('//', endpoint='blog/archive'), Rule('///', endpoint='blog/archive'), Rule('////', endpoint='blog/archive'), Rule('////', endpoint='blog/show_post'), Rule('/about', endpoint='blog/about_me'), Rule('/feeds/', endpoint='blog/feeds'), Rule('/feeds/.rss', endpoint='blog/show_feed') ]) def application(environ, start_response): urls = url_map.bind_to_environ(environ) try: endpoint, args = urls.match() except HTTPException, e: return e(environ, start_response) start_response('200 OK', [('Content-Type', 'text/plain')]) return [f'Rule points to {endpoint!r} with arguments {args!r}'.encode()] So what does that do? First of all we create a new :class:`Map` which stores a bunch of URL rules. Then we pass it a list of :class:`Rule` objects. Each :class:`Rule` object is instantiated with a string that represents a rule and an endpoint which will be the alias for what view the rule represents. Multiple rules can have the same endpoint, but should have different arguments to allow URL construction. The format for the URL rules is straightforward, but explained in detail below. Inside the WSGI application we bind the url_map to the current request which will return a new :class:`MapAdapter`. This url_map adapter can then be used to match or build domains for the current request. The :meth:`MapAdapter.match` method can then either return a tuple in the form ``(endpoint, args)`` or raise one of the three exceptions :exc:`~werkzeug.exceptions.NotFound`, :exc:`~werkzeug.exceptions.MethodNotAllowed`, or :exc:`~werkzeug.exceptions.RequestRedirect`. For more details about those exceptions have a look at the documentation of the :meth:`MapAdapter.match` method. Rule Format =========== Rule strings are URL paths with placeholders for variable parts in the format ````. ``converter`` and ``arguments`` (with parentheses) are optional. If no converter is given, the ``default`` converter is used (``string`` by default). The available converters are discussed below. Rules that end with a slash are "branches", others are "leaves". If ``strict_slashes`` is enabled (the default), visiting a branch URL without a trailing slash will redirect to the URL with a slash appended. Many HTTP servers merge consecutive slashes into one when receiving requests. If ``merge_slashes`` is enabled (the default), rules will merge slashes in non-variable parts when matching and building. Visiting a URL with consecutive slashes will redirect to the URL with slashes merged. If you want to disable ``merge_slashes`` for a :class:`Rule` or :class:`Map`, you'll also need to configure your web server appropriately. Built-in Converters =================== Converters for common types of URL variables are built-in. The available converters can be overridden or extended through :attr:`Map.converters`. .. autoclass:: UnicodeConverter .. autoclass:: PathConverter .. autoclass:: AnyConverter .. autoclass:: IntegerConverter .. autoclass:: FloatConverter .. autoclass:: UUIDConverter Maps, Rules and Adapters ======================== .. autoclass:: Map :members: .. attribute:: converters The dictionary of converters. This can be modified after the class was created, but will only affect rules added after the modification. If the rules are defined with the list passed to the class, the `converters` parameter to the constructor has to be used instead. .. autoclass:: MapAdapter :members: .. autoclass:: Rule :members: empty Matchers ======== .. autoclass:: StateMachineMatcher :members: Rule Factories ============== .. autoclass:: RuleFactory :members: get_rules .. autoclass:: Subdomain .. autoclass:: Submount .. autoclass:: EndpointPrefix Rule Templates ============== .. autoclass:: RuleTemplate Custom Converters ================= You can add custom converters that add behaviors not provided by the built-in converters. To make a custom converter, subclass :class:`BaseConverter` then pass the new class to the :class:`Map` ``converters`` parameter, or add it to :attr:`url_map.converters `. The converter should have a ``regex`` attribute with a regular expression to match with. If the converter can take arguments in a URL rule, it should accept them in its ``__init__`` method. The entire regex expression will be matched as a group and used as the value for conversion. If a custom converter can match a forward slash, ``/``, it should have the attribute ``part_isolating`` set to ``False``. This will ensure that rules using the custom converter are correctly matched. It can implement a ``to_python`` method to convert the matched string to some other object. This can also do extra validation that wasn't possible with the ``regex`` attribute, and should raise a :exc:`werkzeug.routing.ValidationError` in that case. Raising any other errors will cause a 500 error. It can implement a ``to_url`` method to convert a Python object to a string when building a URL. Any error raised here will be converted to a :exc:`werkzeug.routing.BuildError` and eventually cause a 500 error. This example implements a ``BooleanConverter`` that will match the strings ``"yes"``, ``"no"``, and ``"maybe"``, returning a random value for ``"maybe"``. :: from random import randrange from werkzeug.routing import BaseConverter, ValidationError class BooleanConverter(BaseConverter): regex = r"(?:yes|no|maybe)" def __init__(self, url_map, maybe=False): super().__init__(url_map) self.maybe = maybe def to_python(self, value): if value == "maybe": if self.maybe: return not randrange(2) raise ValidationError return value == 'yes' def to_url(self, value): return "yes" if value else "no" from werkzeug.routing import Map, Rule url_map = Map([ Rule("/vote/", endpoint="vote"), Rule("/guess/", endpoint="guess") ], converters={'bool': BooleanConverter}) If you want to change the default converter, assign a different converter to the ``"default"`` key. Host Matching ============= .. versionadded:: 0.7 Starting with Werkzeug 0.7 it's also possible to do matching on the whole host names instead of just the subdomain. To enable this feature you need to pass ``host_matching=True`` to the :class:`Map` constructor and provide the `host` argument to all routes:: url_map = Map([ Rule('/', endpoint='www_index', host='www.example.com'), Rule('/', endpoint='help_index', host='help.example.com') ], host_matching=True) Variable parts are of course also possible in the host section:: url_map = Map([ Rule('/', endpoint='www_index', host='www.example.com'), Rule('/', endpoint='user_index', host='.example.com') ], host_matching=True) WebSockets ========== .. versionadded:: 1.0 If a :class:`Rule` is created with ``websocket=True``, it will only match if the :class:`Map` is bound to a request with a ``url_scheme`` of ``ws`` or ``wss``. .. note:: Werkzeug has no further WebSocket support beyond routing. This functionality is mostly of use to ASGI projects. .. code-block:: python url_map = Map([ Rule("/ws", endpoint="comm", websocket=True), ]) adapter = map.bind("example.org", "/ws", url_scheme="ws") assert adapter.match() == ("comm", {}) If the only match is a WebSocket rule and the bind is HTTP (or the only match is HTTP and the bind is WebSocket) a :exc:`WebsocketMismatch` (derives from :exc:`~werkzeug.exceptions.BadRequest`) exception is raised. As WebSocket URLs have a different scheme, rules are always built with a scheme and host, ``force_external=True`` is implied. .. code-block:: python url = adapter.build("comm") assert url == "ws://example.org/ws" State Machine Matching ====================== The default matching algorithm uses a state machine that transitions between parts of the request path to find a match. To understand how this works consider this rule:: /resource/ Firstly this rule is decomposed into two ``RulePart``. The first is a static part with a content equal to ``resource``, the second is dynamic and requires a regex match to ``[^/]+``. A state machine is then created with an initial state that represents the rule's first ``/``. This initial state has a single, static transition to the next state which represents the rule's second ``/``. This second state has a single dynamic transition to the final state which includes the rule. To match a path the matcher starts and the initial state and follows transitions that work. Clearly a trial path of ``/resource/2`` has the parts ``""``, ``resource``, and ``2`` which match the transitions and hence a rule will match. Whereas ``/other/2`` will not match as there is no transition for the ``other`` part from the initial state. The only diversion from this rule is if a ``RulePart`` is not part-isolating i.e. it will match ``/``. In this case the ``RulePart`` is considered final and represents a transition that must include all the subsequent parts of the trial path.