Skip to main content

Blueprint and Endpoint Resolution

The Request object in Flask, implemented in flask.wrappers.Request, extends the base Werkzeug request to provide deep integration with Flask's routing and blueprint systems. It tracks not only the matched URL but also the specific endpoint and the hierarchy of blueprints that the request belongs to.

Endpoint Resolution

When a request matches a route, Flask populates the url_rule attribute of the Request object with the werkzeug.routing.Rule that matched. From this rule, the endpoint property is derived.

The endpoint is a string that uniquely identifies the view function. If the view is part of a blueprint, the endpoint is prefixed with the blueprint's registered name.

# src/flask/wrappers.py

@property
def endpoint(self) -> str | None:
"""The endpoint that matched the request URL."""
if self.url_rule is not None:
return self.url_rule.endpoint

return None

Blueprint Identification

The blueprint property identifies the name of the blueprint that contains the current endpoint. It is extracted by taking everything before the last dot in the endpoint string.

It is important to note that request.blueprint returns the registered name of the blueprint. This may differ from the name used when the Blueprint object was created if it was renamed during registration (using the name parameter in register_blueprint) or if it is nested.

# src/flask/wrappers.py

@property
def blueprint(self) -> str | None:
"""The registered name of the current blueprint."""
endpoint = self.endpoint

if endpoint is not None and ". " in endpoint:
return endpoint.rpartition(".")[0]

return None

For example, if a blueprint created as bp = Blueprint("user", ...) is registered with app.register_blueprint(bp, name="auth"), the request.blueprint for routes within it will be "auth".

Blueprint Hierarchy

Flask supports nested blueprints, where one blueprint is registered on another. The blueprints property provides a list of all blueprints in the hierarchy, from the most specific (the current blueprint) up to the top-level parent.

This hierarchy is resolved using the internal _split_blueprint_path helper in src/flask/helpers.py, which recursively splits the blueprint name by dots.

# src/flask/wrappers.py

@property
def blueprints(self) -> list[str]:
"""The registered names of the current blueprint upwards through
parent blueprints.
"""
name = self.blueprint

if name is None:
return []

return _split_blueprint_path(name)

If the endpoint is admin.users.list, the hierarchy resolved is:

  1. admin.users (Current blueprint)
  2. admin (Parent blueprint)

Example: Nested Resolution

The following behavior is demonstrated in tests/test_blueprints.py, showing how nesting and renaming affect the resolved endpoint and blueprint names:

bp = Blueprint("bp", __name__)
bp2 = Blueprint("bp2", __name__)

@bp.get("/")
def index():
return flask.request.endpoint

bp.register_blueprint(bp2, url_prefix="/a", name="sub")
app.register_blueprint(bp, url_prefix="/a")
app.register_blueprint(bp, url_prefix="/b", name="alt")

# GET /a/ -> endpoint: "bp.index", blueprint: "bp"
# GET /b/ -> endpoint: "alt.index", blueprint: "alt"
# GET /a/a/ -> endpoint: "bp.sub.index2", blueprint: "bp.sub", blueprints: ["bp.sub", "bp"]
# GET /b/a/ -> endpoint: "alt.sub.index2", blueprint: "alt.sub", blueprints: ["alt.sub", "alt"]

Internal Usage and Hook Execution

Flask relies on the blueprint hierarchy to determine which scoped hooks and error handlers to execute.

Hook Execution Order

When processing a request, Flask executes before_request hooks from the application level down to the most specific blueprint. Conversely, after_request hooks are executed from the most specific blueprint up to the application level.

In src/flask/app.py, the preprocess_request method uses request.blueprints to find these hooks:

# src/flask/app.py

def preprocess_request(self, ctx: AppContext) -> ft.ResponseReturnValue | None:
req = ctx.request
# (None, *reversed(req.blueprints)) results in: [None, Parent, Child]
names = (None, *reversed(req.blueprints))

for name in names:
if name in self.before_request_funcs:
for before_func in self.before_request_funcs[name]:
rv = self.ensure_sync(before_func)()
if rv is not None:
return rv

Error Handler Resolution

Similarly, when an exception occurs, Flask searches for an error handler by traversing the hierarchy provided by request.blueprints. It checks the current blueprint, then each parent in order, and finally the application-level handlers.

Relative URL Generation

The request.blueprint property is essential for resolving relative endpoints in url_for. When an endpoint starts with a dot (e.g., .index), Flask uses request.blueprint to prepend the current blueprint's path to the endpoint name, allowing for portable blueprint code that doesn't need to know its own registered name.