"Could not build url for endpoint" when using nested blueprints
Code
from myapi import api_v1
# Create the blueprints
api_blueprint = Blueprint("api", __name__, url_prefix="/api")
api_v1_blueprint = Blueprint("api_v1", __name__, url_prefix="/v1")
# Register the nested blueprint
api_blueprint.register_blueprint(api_v1_blueprint)
# Add the API to the nested blueprint
api_v1.init_app(api_v1_blueprint)
# Finally, register the parent blueprint to the app
app.register_blueprint(api_blueprint)
Repro Steps (if applicable)
- Go to the
/api/v1page
Expected Behavior
The interactive swagger documentation for api_v1 is shown
Actual Behavior
The exception Could not build url for endpoint 'api_v1.specs'. Did you mean 'api.api_v1.specs' instead? is raised
Error Messages/Stack Trace
127.0.0.1 - - [12/Feb/2023 20:20:32] "GET /api/v1/ HTTP/1.1" 500 -
Traceback (most recent call last):
File "/usr/lib/python3.10/site-packages/flask/app.py", line 2548, in __call__
return self.wsgi_app(environ, start_response)
File "/usr/lib/python3.10/site-packages/flask/app.py", line 2528, in wsgi_app
response = self.handle_exception(e)
File "/home/matthieu/.local/lib/python3.10/site-packages/flask_restx/api.py", line 674, in error_router
return original_handler(e)
File "/usr/lib/python3.10/site-packages/flask/app.py", line 2525, in wsgi_app
response = self.full_dispatch_request()
File "/usr/lib/python3.10/site-packages/flask/app.py", line 1822, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/matthieu/.local/lib/python3.10/site-packages/flask_restx/api.py", line 674, in error_router
return original_handler(e)
File "/usr/lib/python3.10/site-packages/flask/app.py", line 1820, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/lib/python3.10/site-packages/flask/app.py", line 1796, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
File "/home/matthieu/.local/lib/python3.10/site-packages/flask_restx/api.py", line 456, in render_doc
return apidoc.ui_for(self)
File "/home/matthieu/.local/lib/python3.10/site-packages/flask_restx/apidoc.py", line 35, in ui_for
return render_template("swagger-ui.html", title=api.title, specs_url=api.specs_url)
File "/home/matthieu/.local/lib/python3.10/site-packages/flask_restx/api.py", line 542, in specs_url
return url_for(
File "/usr/lib/python3.10/site-packages/flask/helpers.py", line 256, in url_for
return current_app.url_for(
File "/usr/lib/python3.10/site-packages/flask/app.py", line 2031, in url_for
return self.handle_url_build_error(error, endpoint, values)
File "/usr/lib/python3.10/site-packages/flask/app.py", line 2020, in url_for
rv = url_adapter.build( # type: ignore[union-attr]
File "/usr/lib/python3.10/site-packages/werkzeug/routing/map.py", line 917, in build
raise BuildError(endpoint, values, method, self)
werkzeug.routing.exceptions.BuildError: Could not build url for endpoint 'api_v1.specs'. Did you mean 'api.api_v1.specs' instead?
Environment
- Python version: 3.10.9
- Flask version: 2.2.2
- Flask-RESTX version: 1.0.6
- Other installed Flask extensions:
- Flask-SQLAlchemy==2.5.1
- flask-marshmallow==0.14.0
- Flask-Login==0.6.2
Additional Context
This is the code used to define api_v1
api_v1 = Api(
version="1.0",
title="Test API",
description="An API to test flask_restx",
endpoint="/api/v1",
)
Flask-restx was written before Flask >2.0.0 introduced nested blueprints and therefore the Api class makes assumptions about the URLs and endpoints inside a Blueprint. I can't see any easy work around either.
Can I ask why you are interested in using nested blueprints rather than just registering another top level blueprint or using namespaces?
I'm interested in using nested blueprints since it seemed like the easiest way (mostly easy to register, as well as easy to add a redirect from /api to the latest API version).
As for namespaces, i am using them already to register various things to api_v1, but i don't really see how i could use it to have multiple different versions on the API with different prefix.
But if there isn't an easy way to fix it to work with nested blueprints, i'll follow your suggestion and use multiple top-level blueprints instead