Open Midnighter opened 6 years ago
Hi,
you can try
status.py
from flask_restplus import Namespace
api = Namespace('status', description='Status related stuff')
@api.route("/<string:uuid>")
@api.doc(...)
class Status(Resource):
...
api.py
from flask import Blueprint
from flask_restplus import Api
blueprint = Blueprint('api', __name__, url_prefix='/myapi')
api = Api(blueprint,
title='API',
description='API'
)
from status import api as ns1
api.add_namespace(ns1)
app.py
from flask import Flask
app = Flask(__name__)
from api import blueprint as blueprint1
app.register_blueprint(blueprint1)
So if you add more namepsaces to the api, they will be added to the same doc. URL/myapi shows the doc URL/myapi/status ==> status routes URL/myapi/namespace2 ==> namespace2 routes
As @Fearxpc 's advice, we get a single blueprint app with multiple namespace. But if there are already multiple blueprints exist, how can we solve this problem?
@ethe
You should be able to reigster multiple blueprints with app.register_blueprint()
- that's why I used the var name blueprint1.
@Fearxpc
blueprint1 's endpoint is '\myapi' so I can '/myapi' to show the blueprint1 swagger, that's right. If I register another blueprint (maybe call the blueprint2 and it's endpoint is '/myapi2'), I can find the doc in '/myapi2'. But there are not a aggregation of blueprint1 and blueprint2, I can not find a page list all of the api from all blueprints. And the issue title is 'How to aggregate Swagger docs from multiple Blueprints?'.
Hope for your reply, thank you.
Okay got it - but I think this is not possible or I don't know how to at the moment.
My way around this was to use Namespaces
instead of Blueprint
.
https://flask-restplus.readthedocs.io/en/stable/scaling.html#multiple-apis-with-reusable-namespaces
In summary, we can only use it like this:
from flask import Flask, Blueprint
from flask_restplus import Api, Namespace, Resource
app = Flask(__name__)
cat_ns = Namespace('cat_ns')
@cat_ns.route('/cat')
class Cat(Resource):
def get(self):
return 'hello cat'
cat_bp = Blueprint('cat_bp', __name__, url_prefix='/cat_api')
cat_api = Api(cat_bp, version='0.1')
cat_api.add_namespace(cat_ns)
dog_ns = Namespace('dog_ns')
@dog_ns.route('/dog')
class Dog(Resource):
def get(self):
return 'dog'
dog_bp = Blueprint('dog_bp', __name__, url_prefix='/dog_api')
dog_api = Api(dog_bp, version='2')
dog_api.add_namespace(dog_ns)
app.register_blueprint(cat_bp)
app.register_blueprint(dog_bp)
app.run(debug=True)
Route: http://host:port/cat_api
Swagger in browser:
Route: http://host:port/dog_api
Swagger in browser:
Hope for the aggregation of all my blueprints.
Hope for the aggregation of all my blueprints.
+1
I ended up being able to accomplish the original goal of two blueprints with only one namespace the following way:
In my_project.routes.ui
api = Namespace('ui', description='User Interface API')
In my_project.routes.service
service = Blueprint('service', __name__)
api = Namespace('service', description='Service API')
In my_project.__init__.py
, where I am using the application factory pattern
def create_app():
...
from my_project.routes.ui import api as ui_ns
from my_project.routes.service import service, api as service_ns
blueprint = Blueprint('api', __name__)
api = Api(blueprint)
app.register_blueprint(blueprint, url_prefix='/api')
app.register_blueprint(service)
api.add_namespace(service_ns)
api.add_namespace(ui_ns)
...
This results in the following app.url_map
output:
...
<Rule '/api/service/endpoint1' (POST, OPTIONS) -> api.service_endpoint1>,
<Rule '/api/ui/endpoint1' (GET, HEAD, OPTIONS) -> api.ui_endpoint1>,
<Rule '/api/swagger.json' (GET, HEAD, OPTIONS) -> api.specs>,
<Rule '/api/' (GET, HEAD, OPTIONS) -> api.doc>,
<Rule '/api/' (GET, HEAD, OPTIONS) -> api.root>,
... # etc
Both /ui
and /service
are under the same url prefix/base path /api
.
I had a significant difficulty figuring out how to how to accomplish this, using the information provided by other users and the lack of an example in the docs which was explicit.
The piece of information I was missing was here: https://github.com/noirbizarre/flask-restplus/blob/master/examples/zoo/cat.py
In short every blueprint needs the following:
from flask_restplus import Api
api = Namespace('cats', description='Cats related operations')
@api.route('/')
class Cats(Resource):
def get(self):
return {}
then that is imported and added as a namespace:
from zoo.cat import api as cat
from zoo.dog import api as dog
app = Flask(__name__)
blueprint = Blueprint('api', __name__, url_prefix='/api/1')
api = Api(blueprint,
title="My API",
description="My Cool API")
api.add_namespace(cat)
api.add_namespace(dog)
app.register_blueprint(blueprint)
app.run(debug=True)
Hopefully, this provides the missing pieces I had a hard time finding. I will see about getting a PR to improve the documentation.
@james-powis I would suggest opening up your PR in https://github.com/python-restx/flask-restx instead, which is where all the updates for this code base have moved to.
@yesthesoup well that is embarrassing, thanks for the pointer... https://github.com/python-restx/flask-restx/pull/78 for posterity sake.
Not at all! Thanks for making this change to make it clearer for everyone.
I ended up being able to accomplish the original goal of two blueprints with only one namespace the following way:
In
my_project.routes.ui
api = Namespace('ui', description='User Interface API')
In
my_project.routes.service
service = Blueprint('service', __name__) api = Namespace('service', description='Service API')
In
my_project.__init__.py
, where I am using the application factory patterndef create_app(): ... from my_project.routes.ui import api as ui_ns from my_project.routes.service import service, api as service_ns blueprint = Blueprint('api', __name__) api = Api(blueprint) app.register_blueprint(blueprint, url_prefix='/api') app.register_blueprint(service) api.add_namespace(service_ns) api.add_namespace(ui_ns) ...
This results in the following
app.url_map
output:... <Rule '/api/service/endpoint1' (POST, OPTIONS) -> api.service_endpoint1>, <Rule '/api/ui/endpoint1' (GET, HEAD, OPTIONS) -> api.ui_endpoint1>, <Rule '/api/swagger.json' (GET, HEAD, OPTIONS) -> api.specs>, <Rule '/api/' (GET, HEAD, OPTIONS) -> api.doc>, <Rule '/api/' (GET, HEAD, OPTIONS) -> api.root>, ... # etc
Both
/ui
and/service
are under the same url prefix/base path/api
.
good method
I ended up being able to accomplish the original goal of two blueprints with only one namespace the following way:
In
my_project.routes.ui
api = Namespace('ui', description='User Interface API')
In
my_project.routes.service
service = Blueprint('service', __name__) api = Namespace('service', description='Service API')
In
my_project.__init__.py
, where I am using the application factory patterndef create_app(): ... from my_project.routes.ui import api as ui_ns from my_project.routes.service import service, api as service_ns blueprint = Blueprint('api', __name__) api = Api(blueprint) app.register_blueprint(blueprint, url_prefix='/api') app.register_blueprint(service) api.add_namespace(service_ns) api.add_namespace(ui_ns) ...
This results in the following
app.url_map
output:... <Rule '/api/service/endpoint1' (POST, OPTIONS) -> api.service_endpoint1>, <Rule '/api/ui/endpoint1' (GET, HEAD, OPTIONS) -> api.ui_endpoint1>, <Rule '/api/swagger.json' (GET, HEAD, OPTIONS) -> api.specs>, <Rule '/api/' (GET, HEAD, OPTIONS) -> api.doc>, <Rule '/api/' (GET, HEAD, OPTIONS) -> api.root>, ... # etc
Both
/ui
and/service
are under the same url prefix/base path/api
.
Cool, thanks, it works for me!
Maybe my design choices are flawed so feel free to correct me. My goal was to be able to assign URLs to several resources while keeping them in the same namespace. Thus I used blueprints which work great for me. My only problem is that now the docs are served at each individual blueprint URL rather than having an aggregated one. Pseudocode for my setup:
Resource
status.py
:In the main
app.py
:I have multiple such blueprints and would like to see all of their docs under one endpoint.