UPDATE
Flask 2 was released with support for nested blueprints.
[ START: Part from the docs ]
Nesting Blueprints
It is possible to register a blueprint on another blueprint.
parent = Blueprint('parent', __name__, url_prefix='/parent')
child = Blueprint('child', __name__, url_prefix='/child')
parent.register_blueprint(child)
app.register_blueprint(parent)
The child blueprint will gain the parent’s name as a prefix to its name, and child URLs will be prefixed with the parent’s URL prefix.
url_for('parent.child.create')
/parent/child/create
Blueprint-specific before request functions, etc. registered with the parent will trigger for the child. If a child does not have an error handler that can handle a given exception, the parent’s will be tried.
[ END: Part from the docs ]
Source: https://flask.palletsprojects.com/en/2.0.x/blueprints/#nesting-blueprints
OLD ANSWER
My hacky work around is that I made a class called ParentBP that has the following code
from typing import List
from flask import Blueprint
class ParentBP(object):
name: str
url_prefix: str
subdomain: str
blueprints: List[Blueprint]
def __init__(self, name="", url_prefix="", subdomain="") -> None:
self.name = name
self.url_prefix = url_prefix
self.subdomain = subdomain
self.blueprints = []
def register_blueprint(self, bp: Blueprint) -> None:
bp.name = self.name + "-" + bp.name
bp.url_prefix = self.url_prefix + (bp.url_prefix or "")
if self.subdomain:
bp.subdomain = self.subdomain
self.blueprints.append(bp)
so you can call it similar to a blueprint like below
blueprint1 = Blueprint("blueprint1", __name__)
blueprint2 = Blueprint("blueprint2", __name__, url_prefix="/bp2")
api_v1 = ParentBP("api-v1", url_prefix="/api/v1")
api_v1.register_blueprint(blueprint1)
api_v1.register_blueprint(blueprint)
to make the interface similar to normal registering of blueprints to the flask app, I extended the Flask class as follows
class ExtendedFlask(Flask):
def register_blueprint(self, blueprint: Union[Blueprint, ParentBP], **options: Any) -> None:
if isinstance(blueprint, ParentBP):
for bp in blueprint.blueprints:
super().register_blueprint(bp, **options)
else:
return super().register_blueprint(blueprint, **options)
now you can normally do the following
app = ExtendedFlask(__name__)
app.register_blueprint(api_v1)