# Routing

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

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

@app.route("/stairway")
...

@app.get("/to")
...

@app.post("/heaven")
...

# Adding a route

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

See API docs 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.

app.add_route(
    handler,
    '/test',
    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.

    @app.get("/tag/<tag>")
    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.

    @app.get("/foo/<foo_id:uuid>")
    async def uuid_handler(request, foo_id: UUID):
        return text("UUID - {}".format(foo_id))
    

    # Supported types

      # 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.

      @app.route('/')
      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)
      
      @app.route('/posts/<post_id>')
      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(
          "post_handler",
          post_id=5,
          arg_one="one",
          arg_two="two",
      )
      '/posts/5?arg_one=one&arg_two=two'
      

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

      >>> app.url_for(
          "post_handler",
          post_id=5,
          arg_one=["one", "two"],
      )
      '/posts/5?arg_one=one&arg_one=two'
      

      # Special keyword arguments

      See API Docs for more details.

      >>> app.url_for("post_handler", post_id=5, arg_one="one", _anchor="anchor")
      '/posts/5?arg_one=one#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)
      '//server/posts/5?arg_one=one'
      
      # when specifying _scheme, _external must be True
      >>> app.url_for("post_handler", post_id=5, arg_one="one", _scheme="http", _external=True)
      'http://server/posts/5?arg_one=one'
      
      # 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")
      'http://another_server:8888/posts/5?arg_one=one&arg_one=two&arg_two=2#anchor'
      

      # 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")
      '/get?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.

      @app.websocket("/test")
      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. 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")
      

      # 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

      app.static(
          "/user/uploads",
          "/path/to/uploads",
          name="uploads",
      )
      

      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(
          "static",
          name="static",
          filename="file.txt",
      )
      '/static/file.txt'
      
      ```python
      >>> app.url_for(
          "static",
          name="uploads",
          filename="image.png",
      )
      '/user/uploads/image.png'
      
      
      MIT Licensed | Copyright © 2018-present Sanic Community Organization