Overview
Routing in Flask maps URL patterns to Python functions (view functions). Flask uses Werkzeug’s routing system to match incoming requests to the appropriate view.
Basic Routing
The @app.route() decorator is the primary way to register routes:
from flask import Flask
app = Flask( __name__ )
@app.route ( '/' )
def index ():
return 'Hello, World!'
@app.route ( '/about' )
def about ():
return 'About Page'
Route Decorator
From scaffold.py:336-365, the route decorator is syntactic sugar for add_url_rule():
@app.route ( "/" )
def index ():
return "Hello, World!"
# Equivalent to:
def index ():
return "Hello, World!"
app.add_url_rule( "/" , view_func = index)
HTTP Methods
Specifying Methods
By default, routes only respond to GET requests. Specify other methods:
@app.route ( '/login' , methods = [ 'GET' , 'POST' ])
def login ():
if request.method == 'POST' :
# Process login
return redirect( '/dashboard' )
return render_template( 'login.html' )
HEAD and OPTIONS methods are automatically added. HEAD returns the same response as GET but without the body.
Method-Specific Shortcuts
Flask provides shortcuts for common HTTP methods (from scaffold.py:296-333):
@app.get ( '/users' )
def list_users ():
return jsonify(users)
@app.post ( '/users' )
def create_user ():
return jsonify(user), 201
@app.put ( '/users/<int:id>' )
def update_user ( id ):
return jsonify(user)
@app.delete ( '/users/<int:id>' )
def delete_user ( id ):
return '' , 204
@app.patch ( '/users/<int:id>' )
def partial_update_user ( id ):
return jsonify(user)
Variable Rules
URL Parameters
Capture parts of the URL as parameters:
@app.route ( '/user/<username>' )
def show_user ( username ):
return f 'User: { username } '
@app.route ( '/post/<int:post_id>' )
def show_post ( post_id ):
return f 'Post ID: { post_id } '
Converters
Flask supports several built-in converters:
Converter Description Example stringDefault, accepts text without slashes /user/<username>intAccepts integers /post/<int:id>floatAccepts floating point numbers /price/<float:amount>pathLike string but accepts slashes /file/<path:filename>uuidAccepts UUID strings /api/<uuid:id>
@app.route ( '/files/<path:filepath>' )
def serve_file ( filepath ):
return send_file(filepath)
@app.route ( '/api/resource/<uuid:resource_id>' )
def get_resource ( resource_id ):
return jsonify(resource)
URL Building
Using url_for()
Generate URLs dynamically using endpoint names:
from flask import url_for
@app.route ( '/' )
def index ():
return 'Index'
@app.route ( '/user/<username>' )
def profile ( username ):
return f 'Profile: { username } '
with app.test_request_context():
print (url_for( 'index' )) # /
print (url_for( 'profile' , username = 'john' )) # /user/john
print (url_for( 'profile' , username = 'jane' , page = 2 )) # /user/jane?page=2
External URLs
Generate absolute URLs with scheme and domain:
url_for( 'index' , _external = True )
# https://example.com/
url_for( 'profile' , username = 'john' , _external = True , _scheme = 'https' )
# https://example.com/user/john
URL Parameters
From app.py:1102-1222, url_for() supports several special parameters:
url_for( 'index' , _anchor = 'section' ) # /#section
url_for( 'api.users' , _method = 'POST' ) # Build URL for specific method
url_for( 'static' , filename = 'style.css' ) # /static/style.css
Endpoint Names
Each route has an endpoint name, which defaults to the function name:
@app.route ( '/users' )
def list_users (): # endpoint: 'list_users'
return jsonify(users)
# Custom endpoint name
@app.route ( '/users' , endpoint = 'user_list' )
def show_all_users ():
return jsonify(users)
url_for( 'user_list' ) # /users
URL Registration Methods
add_url_rule()
Register routes programmatically (from scaffold.py:368-433):
def index ():
return 'Hello, World!'
app.add_url_rule( '/' , 'index' , index)
# With options
app.add_url_rule(
'/api/users' ,
'api.users' ,
view_func = list_users,
methods = [ 'GET' , 'POST' ]
)
Endpoint Decorator
Separate URL rule registration from view function:
app.add_url_rule( '/admin' , endpoint = 'admin' )
@app.endpoint ( 'admin' )
def admin_panel ():
return 'Admin Panel'
Unique URLs and Trailing Slashes
Flask distinguishes between URLs with and without trailing slashes:
@app.route ( '/projects/' )
def projects ():
return 'Projects'
# /projects/ works
# /projects redirects to /projects/ (308 redirect)
@app.route ( '/about' )
def about ():
return 'About'
# /about works
# /about/ returns 404
Use trailing slashes for “folders” and no trailing slash for “files” to follow common conventions.
Request Dispatching
From app.py:966-990, Flask’s request dispatch process:
URL Matching - Match request URL to a registered rule
View Args - Extract variables from URL
View Function - Call the matched view function
Response - Convert return value to a Response object
def dispatch_request ( self , ctx ):
req = ctx.request
if req.routing_exception is not None :
self .raise_routing_exception(req)
rule = req.url_rule
view_args = req.view_args
return self .view_functions[rule.endpoint]( ** view_args)
Advanced Routing
Subdomain Routing
Route based on subdomains:
app.config[ 'SERVER_NAME' ] = 'example.com'
@app.route ( '/' , subdomain = 'api' )
def api_index ():
return 'API Index'
@app.route ( '/' , subdomain = '<user>' )
def user_subdomain ( user ):
return f 'User subdomain: { user } '
Host Matching
Match routes based on the full host:
app.url_map.host_matching = True
@app.route ( '/' , host = 'example.com' )
def main_site ():
return 'Main Site'
@app.route ( '/' , host = 'api.example.com' )
def api_site ():
return 'API Site'
URL Value Preprocessors
Modify URL values before they reach the view:
@app.url_value_preprocessor
def pull_lang_code ( endpoint , values ):
if values is not None :
g.lang_code = values.pop( 'lang_code' , None )
@app.route ( '/<lang_code>/page' )
def show_page ():
# lang_code is in g.lang_code, not as a parameter
return render_template( 'page.html' )
URL Defaults
Provide default values for URL generation:
@app.url_defaults
def add_language_code ( endpoint , values ):
if 'lang_code' in values or not g.lang_code:
return
if app.url_map.is_endpoint_expecting(endpoint, 'lang_code' ):
values[ 'lang_code' ] = g.lang_code
Error Handling for Routes
404 Not Found
Handle missing routes:
@app.errorhandler ( 404 )
def page_not_found ( error ):
return render_template( '404.html' ), 404
405 Method Not Allowed
Handle wrong HTTP methods:
@app.errorhandler ( 405 )
def method_not_allowed ( error ):
return jsonify({ 'error' : 'Method not allowed' }), 405
Best Practices
Use url_for() Always use url_for() instead of hardcoding URLs for flexibility
Consistent Naming Use descriptive endpoint names that reflect the resource
RESTful Routes Follow REST conventions for API endpoints
Trailing Slashes Be consistent with trailing slash usage across your app