Flask route parameters - separate route to root page


One way to overcome the starnge situation that /user/Foo works but /user/ gives a 404 Not Found error is to add an extra route that will specifically handle that case.

examples/flask/path-separate/app.py
from flask import Flask, jsonify
app = Flask(__name__)

@app.route("/")
def index():
    return '''
Main<br>
<a href="/user/23">23</a><br>
<a href="/user/42">42</a><br>
<a href="/user/Joe">Joe</a><br>
'''

@app.route("/user/<uid>")
def api_info(uid):
    return uid

@app.route("/user/")
def user():
    return 'User List'

FLASK_APP=app.py FLASK_DEBUG=0  flask run

With the tests we can see that now /user/ works and returns the value we expected. Howerver there is anothe special address and that is the /user path, the one without the trailing slash. Flask will handle this too by automatiocally redirecting the browser to the /user/ page.

You can see uisng the test case that the /user path returns a '308 Permanent Redirect' error and sets the "Location" in the response header. Regular browsers would automatically move to the /user/ page and show the response from there.

Flask will also send some HTML content explaining the situation. This is only relevant for browsers, or other HTTP clients that don't automatically follow the redirection.

For example curl will not automaticall follow this redirection. However if you supply the -L flag then it will.

curl -L http://127.0.0.1:5000/user


examples/flask/path-separate/test_app.py
import app
import pytest

@pytest.fixture()
def web():
    return app.app.test_client()

def test_app(web):
    rv = web.get('/')
    assert rv.status == '200 OK'
    assert b'Main<br>' in rv.data

@pytest.mark.parametrize('uid', ['23', '42', 'Joe'])
def test_user(web, uid):
    rv = web.get(f'/user/{uid}')
    assert rv.status == '200 OK'
    assert uid == rv.data.decode('utf-8')

def test_user_root_slash(web):
    rv = web.get(f'/user/')
    assert rv.status == '200 OK'
    assert b'User List' == rv.data

def test_user_root(web):
    rv = web.get(f'/user')
    assert rv.status == '308 PERMANENT REDIRECT'
    assert rv.headers['Location'] == 'http://localhost/user/'
    assert b'<p>You should be redirected automatically to target URL:' in rv.data