Flask
optional URL parameters
web development
Python web framework
routing

Can Flask have optional URL parameters?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Flask does not have native syntax for optional URL parameters in a single route definition. Instead, you achieve optional parameters by registering multiple routes on the same view function, using default argument values, or putting optional values in the query string. Each approach has trade-offs in clarity and URL design.

Stack two @app.route decorators on the same function — one with the parameter and one without:

python
1from flask import Flask
2app = Flask(__name__)
3
4@app.route('/users/')
5@app.route('/users/<int:page>')
6def list_users(page=1):
7    return f"Showing users page {page}"
8
9# GET /users/       → page=1 (default)
10# GET /users/3      → page=3

Flask matches either URL pattern and calls the same function. When the parameter is missing, the default value from the function signature is used.

Multiple Optional Parameters

python
1@app.route('/posts/')
2@app.route('/posts/<category>/')
3@app.route('/posts/<category>/<int:page>')
4def list_posts(category='all', page=1):
5    return f"Category: {category}, Page: {page}"
6
7# GET /posts/                → category='all', page=1
8# GET /posts/python/         → category='python', page=1
9# GET /posts/python/3        → category='python', page=3

Each combination that you want to support needs its own @app.route.

Method 2: Query String Parameters

Use request.args to read parameters from the query string (?key=value):

python
1from flask import Flask, request
2app = Flask(__name__)
3
4@app.route('/search')
5def search():
6    query = request.args.get('q', '')
7    page = request.args.get('page', 1, type=int)
8    per_page = request.args.get('per_page', 20, type=int)
9    return f"Searching '{query}' - page {page}, {per_page}/page"
10
11# GET /search?q=flask                 → q='flask', page=1, per_page=20
12# GET /search?q=flask&page=3          → q='flask', page=3, per_page=20
13# GET /search?q=flask&page=3&per_page=50 → q='flask', page=3, per_page=50

Query parameters are inherently optional — request.args.get() returns the default if the key is absent.

Method 3: Default Values in URL Rules

Use defaults in the route to provide a fallback:

python
1@app.route('/items/', defaults={'item_id': None})
2@app.route('/items/<int:item_id>')
3def get_items(item_id):
4    if item_id is None:
5        return "Listing all items"
6    return f"Showing item {item_id}"
7
8# GET /items/      → item_id=None → list all
9# GET /items/42    → item_id=42   → show specific

The defaults dict provides values for parameters that are missing from the URL.

Method 4: Catch-All with Path Converter

For truly variable URL segments:

python
1@app.route('/files/', defaults={'filepath': ''})
2@app.route('/files/<path:filepath>')
3def serve_file(filepath):
4    if not filepath:
5        return "File index"
6    return f"Serving: {filepath}"
7
8# GET /files/                    → filepath=''
9# GET /files/docs/readme.md     → filepath='docs/readme.md'

The path converter matches slashes, allowing multi-segment paths.

URL vs Query String: When to Use Each

python
1# URL parameters — for resource identification
2@app.route('/users/<int:user_id>/posts/<int:post_id>')
3def get_post(user_id, post_id):
4    pass
5# GET /users/5/posts/42
6
7# Query parameters — for filtering, sorting, pagination
8@app.route('/users/<int:user_id>/posts')
9def list_user_posts(user_id):
10    sort = request.args.get('sort', 'date')
11    order = request.args.get('order', 'desc')
12    page = request.args.get('page', 1, type=int)
13    pass
14# GET /users/5/posts?sort=title&order=asc&page=2

Use URL path parameters for required identifiers that define the resource. Use query string for optional modifiers like filters, sort order, and pagination.

Type Conversion

Flask provides built-in converters for URL parameters:

python
1@app.route('/item/<int:item_id>')       # Integer: /item/42
2@app.route('/weight/<float:weight>')     # Float: /weight/3.14
3@app.route('/file/<path:filepath>')      # Path with slashes: /file/a/b/c
4@app.route('/user/<uuid:user_id>')       # UUID: /user/a1b2c3d4-...
5
6# Query parameters need manual conversion
7page = request.args.get('page', 1, type=int)
8active = request.args.get('active', 'true') == 'true'

Flask-RESTful and Blueprints

python
1# With Flask-RESTful
2from flask_restful import Resource, Api, reqparse
3
4class UserList(Resource):
5    def get(self):
6        parser = reqparse.RequestParser()
7        parser.add_argument('page', type=int, default=1)
8        parser.add_argument('per_page', type=int, default=20)
9        args = parser.parse_args()
10        return {"page": args['page'], "per_page": args['per_page']}
11
12api = Api(app)
13api.add_resource(UserList, '/users/')

Common Pitfalls

  • Missing trailing slash: /users and /users/ are different URLs in Flask. By default, Flask redirects /users to /users/ if the route has a trailing slash. Be consistent.
  • Ambiguous routes: @app.route('/<category>/') and @app.route('/about/') — Flask might match /about/ to the <category> route. Put specific routes before generic ones, or use converters to constrain the parameter.
  • Type errors from query strings: request.args.get('page') returns a string, not an int. Use request.args.get('page', 1, type=int) for automatic conversion with fallback.
  • Too many stacked decorators: Three or more @app.route decorators on one function becomes hard to maintain. Consider using query parameters instead for truly optional values.
  • None vs empty string defaults: Choose a consistent default (None, empty string, or a meaningful default value) and document it.

Summary

  • Flask does not have built-in optional URL parameter syntax
  • Use multiple @app.route decorators with default function arguments for optional path segments
  • Use request.args.get('key', default) for optional query string parameters
  • Use defaults={'param': None} in the route to provide fallback values
  • URL parameters identify resources; query parameters filter and modify behavior
  • request.args.get() supports type=int for automatic type conversion

Course illustration
Course illustration

All Rights Reserved.