# Routing

So far we have seen a lot of this decorator in different forms.

But what is it? And how do we use it?


# Adding a route

The most basic way to wire up a handler to an endpoint is with app.add_route().

See API docs (opens new window) for more details.

async def handler(request):
    return text("OK")
app.add_route(handler, "/test")

By default, routes are available as an HTTP GET call. You can change a handler to respond to one or more HTTP methods.

    methods=["POST", "PUT"],

Using the decorator syntax, the previous example is identical to this.

@app.route('/test', methods=["POST", "PUT"])
async def handler(request):
    return text('OK')

# HTTP methods

Each of the standard HTTP methods has a convenience decorator.

    # Path parameters

    Sanic allows for pattern matching, and for extracting values from URL paths. These parameters are then injected as keyword arguments in the route handler.

    async def tag_handler(request, tag):
        return text("Tag - {}".format(tag))

    You can declare a type for the parameter. This will be enforced when matching, and also will type cast the variable.

    async def uuid_handler(request, foo_id: UUID):
        return text("UUID - {}".format(foo_id))

    # Supported types

      # Regex Matching

      More often than not, compared with complex routing, the above example is too simple, and we use a completely different routing matching pattern, so here we will explain the advanced usage of regex matching in detail.

      Sometimes, you want to match a part of a route:


      If you wanted to match the file pattern, but only capture the numeric portion, you need to do some regex fun 😄:


      Further, these should all be acceptable:

      @app.get(r"/<foo:[a-z]{3}.txt>")                # matching on the full pattern
      @app.get(r"/<foo:([a-z]{3}).txt>")              # defining a single matching group
      @app.get(r"/<foo:(?P<foo>[a-z]{3}).txt>")       # defining a single named matching group
      @app.get(r"/<foo:(?P<foo>[a-z]{3}).(?:txt)>")   # defining a single named matching group, with one or more non-matching groups

      Also, if using a named matching group, it must be the same as the segment label.

      @app.get(r"/<foo:(?P<foo>\d+).jpg>")  # OK
      @app.get(r"/<foo:(?P<bar>\d+).jpg>")  # NOT OK

      For more regular usage methods, please refer to Regular expression operations (opens new window)

      # Generating a URL

      Sanic provides a method to generate URLs based on the handler method name: app.url_for(). This is useful if you want to avoid hardcoding url paths into your app; instead, you can just reference the handler name.

      async def index(request):
          # generate a URL for the endpoint `post_handler`
          url = app.url_for('post_handler', post_id=5)
          # Redirect to `/posts/5`
          return redirect(url)
      async def post_handler(request, post_id):

      You can pass any arbitrary number of keyword arguments. Anything that is not a request parameter will be implemented as a part of the query string.

      >>> app.url_for(

      Also supported is passing multiple values for a single query key.

      >>> app.url_for(
          arg_one=["one", "two"],

      # Special keyword arguments

      See API Docs for more details.

      >>> app.url_for("post_handler", post_id=5, arg_one="one", _anchor="anchor")
      # _external requires you to pass an argument _server or set SERVER_NAME in app.config if not url will be same as no _external
      >>> app.url_for("post_handler", post_id=5, arg_one="one", _external=True)
      # when specifying _scheme, _external must be True
      >>> app.url_for("post_handler", post_id=5, arg_one="one", _scheme="http", _external=True)
      # you can pass all special arguments at once
      >>> app.url_for("post_handler", post_id=5, arg_one=["one", "two"], arg_two=2, _anchor="anchor", _scheme="http", _external=True, _server="another_server:8888")

      # Customizing a route name

      A custom route name can be used by passing a name argument while registering the route.

      @app.get("/get", name="get_handler")
      def handler(request):
          return text("OK")

      Now, use this custom name to retrieve the URL

      >>> app.url_for("get_handler", foo="bar")

      # Websockets routes

      Websocket routing works similar to HTTP methods.

      async def handler(request, ws):
          messgage = "Start"
          while True:
              await ws.send(message)
              message = ws.recv()
      app.add_websocket_route(handler, "/test")

      It also has a convenience decorator.

      async def handler(request, ws):
          messgage = "Start"
          while True:
              await ws.send(message)
              message = ws.recv()

      Read the websockets section to learn more about how they work.

      # Strict slashes

      Sanic routes can be configured to strictly match on whether or not there is a trailing slash: /. This can be configured at a few levels and follows this order of precedence:

      1. Route
      2. Blueprint
      3. BlueprintGroup
      4. Application
      # provide default strict_slashes value for all routes
      app = Sanic(__file__, strict_slashes=True)
      # overwrite strict_slashes value for specific route
      @app.get("/get", strict_slashes=False)
      def handler(request):
          return text("OK")
      # it also works for blueprints
      bp = Blueprint(__file__, strict_slashes=True)
      @bp.get("/bp/get", strict_slashes=False)
      def handler(request):
          return text("OK")
      bp1 = Blueprint(name="bp1", url_prefix="/bp1")
      bp2 = Blueprint(
      # This will enforce strict slashes check on the routes
      # under bp1 but ignore bp2 as that has an explicitly
      # set the strict slashes check to false
      group = Blueprint.group([bp1, bp2], strict_slashes=True)

      # Static files

      In order to serve static files from Sanic, use app.static().

      The order of arguments is important:

      1. Route the files will be served from
      2. Path to the files on the server

      See API docs for more details.

      app.static("/static", "/path/to/directory")

      You can also serve individual files.

      app.static("/", "/path/to/index.html")

      It is also sometimes helpful to name your endpoint


      Retrieving the URLs works similar to handlers. But, we can also add the filename argument when we need a specific file inside a directory.

      >>> app.url_for(
      >>> app.url_for(


      If you are going to have multiple static() routes, then it is highly suggested that you manually name them. This will almost certainly alleviate potential hard to discover bugs.

      app.static("/user/uploads", "/path/to/uploads", name="uploads")
      app.static("/user/profile", "/path/to/profile", name="profile_pics")
      MIT Licensed
      Copyright © 2018-present Sanic Community Organization

      ~ Made with ❤️ and ☕️ ~