Routing and View Function Registration
When you want to map a URL like /user/profile to a Python function so that Flask knows which code to execute when a request arrives, you use the routing system. If you forget to register a route or misconfigure the HTTP methods, Flask will return a 404 Not Found or 405 Method Not Allowed error.
The @app.route Decorator
The most common way to register a route is using the @app.route decorator. It associates a URL rule with a view function.
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
return "Hello, World!"
@app.route("/login", methods=["GET", "POST"])
def login():
return "Login Page"
Internally, the Scaffold.route method in flask.sansio.scaffold acts as a wrapper around add_url_rule. It extracts the endpoint (defaulting to the function name) and passes the rule and options down for registration.
Method-Specific Shortcuts
Flask provides shortcuts for common HTTP methods. These are often more readable than passing a methods list to @app.route.
@app.get("/api/data")
def get_data():
return {"data": "some value"}
@app.post("/api/data")
def post_data():
return "Data received", 201
These shortcuts (@app.get, @app.post, @app.put, @app.delete, @app.patch) are implemented in Scaffold by calling self.route with the specific method pre-filled:
# From flask.sansio.scaffold
@setupmethod
def get(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]:
return self._method_route("GET", rule, options)
Programmatic Registration with add_url_rule
In some cases, such as when building a CMS or dynamically generating routes from a database, decorators are not suitable. You can use app.add_url_rule directly.
def profile(username):
return f"User: {username}"
app.add_url_rule("/user/<username>", view_func=profile)
The App.add_url_rule method in flask.sansio.app is the core implementation. It performs several critical tasks:
- Endpoint Resolution: If no
endpointis provided, it usesview_func.__name__. - Method Normalization: It ensures
methodsis a set of uppercase strings. If you pass a single string like"GET POST", Flask raises aTypeError. - Rule Creation: It creates a
werkzeug.routing.Ruleobject. - Map Integration: It adds the rule to
self.url_map, which Werkzeug uses for matching. - View Function Mapping: It stores the function in
self.view_functions[endpoint].
If you attempt to register a different function to an existing endpoint, Flask raises an AssertionError to prevent accidental overwrites.
Endpoints and View Functions
An endpoint is a unique identifier for a route, used primarily for URL generation via url_for. While the endpoint usually matches the function name, you can decouple them.
Using @app.endpoint
You can register a view function for an endpoint without immediately attaching a URL rule. This is useful when the same logic should handle multiple distinct URLs registered elsewhere.
@app.endpoint("user_profile")
def profile_logic(username):
return f"Profile for {username}"
app.add_url_rule("/user/<username>", endpoint="user_profile")
app.add_url_rule("/u/<username>", endpoint="user_profile")
The @app.endpoint decorator simply populates the self.view_functions dictionary in the Scaffold instance.
Automatic OPTIONS and HEAD Handling
Flask automatically handles OPTIONS and HEAD requests for your routes to comply with HTTP standards.
- HEAD: If a route handles
GET, Flask automatically addsHEAD. It calls your view function but discards the body, returning only the headers. - OPTIONS: Flask generates an
Allowheader containing the methods supported by the URL.
You can control this behavior using the provide_automatic_options parameter in add_url_rule or by setting a function attribute:
def custom_options():
return "Custom OPTIONS response"
custom_options.provide_automatic_options = False
app.add_url_rule("/special", view_func=custom_options, methods=["GET", "OPTIONS"])
Internally, App.dispatch_request checks rule.provide_automatic_options. If True and the request is OPTIONS, it calls make_default_options_response, which inspects the url_adapter to find all allowed methods for that path.
View Function Return Requirements
Every view function must return a value that Flask can convert into a Response object. If a function returns None (e.g., by forgetting a return statement), Flask raises a TypeError.
The Flask.make_response method in flask.app handles the conversion of the following types:
- str / bytes: Becomes the response body.
- dict / list: Automatically converted to a JSON response.
- tuple: Can be
(body, status),(body, headers), or(body, status, headers). - Response object: Returned as-is (or coerced to the app's
response_class). - WSGI callable: Executed as a standard WSGI application.
@app.route("/api/status")
def status():
# Returning a tuple (body, status_code)
return {"status": "ok"}, 200
If make_response receives a type it doesn't recognize, it will raise a TypeError explaining that the return type must be a string, dict, list, tuple, Response instance, or WSGI callable.