Flask: URL Routing

The Art of URL Routing

Flask is an amazing python backend framework that gives lots of flexibility for developers. Here we are discussing different ways to do URL routing. In my opinion, we can classify Flask's view into two:

  1. Function-Based Views and
  2. Class-Based Views/ Pluggable Views

Most of the peoples use Function-Based Views. Since it is very simple and we can use decorators to route URLs easily. We do not want to import our views to another file in order to add some URL rules.

1. Function-Based Views

In this case, we have a function with a unique name. Also, we have a decorator with some arguments like route, methods. Here route is basically a string as well as methods is a list. In the methods list, we can give what are the HTTP methods we are allowed in that route. In Flask 2.0.x, there are of course some changes. Since Flask team made it something similar to the routing mechanism of FastAPI which is a popular Python ASGI framework. However, Flask 2.0.x is still back compatible with Flask 1.2.x.

app.py

from flask import Flask

app = Flask(__name__)

@app.route('/hello')
def index():
    return "Hello"

if __name__ == "__main__":
    app.run(debug=True)

Here, by default hello route can be accessed using the HTTP GET method. In Flask 2.0 we can use the following method:

@app.get('/hello')
def index():
    return "Hello"

But what if need to do we want to access the data also via the POST method?

For flask 1.2.x the solution is:

@app.route('/hello', methods=['GET', 'POST'])
def index():
    return "Hello"

In Flask 2.0.x we can do the same thing with the above syntax. But the preferred way to do so:

@app.get('/hello')
@app.post('/hello')
def index():
    return "Hello"

Stacking The Routes

I don't know it is the correct term to use for this functionality. We can stack the route on top of each other just like above we scene above**. For example we are serving same template from different endpoint we do not want to create different view functions to do so.

@app.route('/hello')
@app.route('/')
@app.route('/hai')
def index():
    return "Hello"

We can also serve different content from view function using conditions based on HTTP methods request.method == HTTP_METHOD where HTTP_METHOD is a valid HTTP method like GET, POST, DELETE, PUT, PATCH etc. Here I am interested to share Flask 2.0.x example instead Flask 1.2.x.


from flask import Flask, request

app = Flask(__name__)

@app.get('/hello')
@app.post('/')
def index():
    if request.method == 'POST':
        return "Got request successfully"
    return "Hello"

if __name__ == "__main__":
    app.run(debug=True)

For Flask 1.2.x also this method will work if added route like

@app.route('/hello')
@app.route('/', methods=['POST'])

Dynamic Routes

The dynamic routes are awesome routing mechanism available in the modern web frameworks. It is samething like query string. But while reading query string another developer will get what is happening in our backend. But this is not possible while we are usig path parameters or dynamic routes. For example a query string will look like https://somewebsite.com?name=arun&dob=18-07-1975 here we are explicitly saying name is arun and his date of birth is 18-07-1975. But in dynamic routes we are not giving such clues and the URL will look like https://somewebsite.com/arun/18-07-1975. I believes the worst example I gave. In the context of Flask the program will look like:

@app.get('/apis/user/<uname>/<dob>')
def index(uname, dob):
    :
    :

Here the caret (<>) symbols indicates that these useraname and dob are variables. Here view function must be taken these path parameters or variables (uname and dob) as an argument. Unless Flask will throw an error by saying view_function() got an unexpected keyword argument 'argument'.

Another important aspect of dynamic routing is, here we can check data types using data constraint. The available data constraints in Flask are:

  • string: Accepts any text without a slash (the default).
  • int: Accepts integers.
  • float: Accepts numerical values containing decimal points.
  • path: Similar to a string, but accepts slashes.
@app.get('/calc/<float:number1>/<int:number2>')
def index(number1, number2):
    try:
        return str(number1/ number2)
    except ZeroDivisionError:
        return "Can't divide with zero"

If we did not entered float for number1 flask will return 404 NOT FOUND response.

2. Pluggable Views

Will update soon.