Open ca-wobeng opened 6 days ago
was able to get it working by monkey-patching with code below but I think this issue falls in the same line of #56 and https://github.com/marshmallow-code/flask-smorest/issues/55
from flask import request, Flask, jsonify
from copy import deepcopy
from flask_smorest.utils import deepupdate
def register_blueprint(self, blp, *, parameters=None, **options):
"""Register a blueprint in the application
Also registers documentation for the blueprint/resource
:param Blueprint blp: Blueprint to register
:param list parameters: List of parameter descriptions for the path parameters
in the ``url_prefix`` of the Blueprint. Only used to document the resource.
:param options: Keyword arguments overriding
:class:`Blueprint <flask.Blueprint>` defaults
Must be called after app is initialized.
"""
blp_name = options.get("name", blp.name)
blp_subdomain = options.get("subdomain", blp.subdomain)
self._app.extensions["flask-smorest"]["blp_name_to_api"][blp_name] = self
self._app.register_blueprint(blp, **options)
# Register views in API documentation for this resource
blp.register_views_in_doc(
self,
self._app,
self.spec,
name=blp_name,
parameters=parameters,
subdomain=blp_subdomain,
)
# Add tag relative to this resource to the global tag list
self.spec.tag({"name": blp_name, "description": blp.description})
def register_views_in_doc(self, api, app, spec, *, name, parameters, subdomain):
"""Register views information in documentation
If a schema in a parameter or a response appears in the spec
`schemas` section, it is replaced by a reference in the parameter or
response documentation:
"schema":{"$ref": "#/components/schemas/MySchema"}
"""
url_prefix_parameters = parameters or []
# This method uses the documentation information associated with each
# endpoint in self._docs to provide documentation for corresponding
# route to the spec object.
# Deepcopy to avoid mutating the source. Allows registering blueprint
# multiple times (e.g. when creating multiple apps during tests).
for endpoint, endpoint_doc_info in deepcopy(self._docs).items():
endpoint_route_parameters = endpoint_doc_info.pop("parameters") or []
endpoint_parameters = url_prefix_parameters + endpoint_route_parameters
doc = {}
# Use doc info stored by decorators to generate doc
for method_l, operation_doc_info in endpoint_doc_info.items():
tags = operation_doc_info.pop("tags")
operation_doc = {}
for func in self._prepare_doc_cbks:
operation_doc = func(
operation_doc,
operation_doc_info,
api=api,
app=app,
spec=spec,
method=method_l,
)
operation_doc.update(operation_doc_info["docstring"])
# Tag all operations with Blueprint name unless tags specified
operation_doc["tags"] = (
tags
if tags is not None
else [
name,
]
)
# Complete doc with manual doc info
manual_doc = operation_doc_info.get("manual_doc", {})
# Add servers information dynamically
if subdomain:
with app.app_context():
with app.test_request_context():
server_url = f"//{subdomain}.{request.host}"
operation_doc["servers"] = [
{
"url": server_url,
}
]
doc[method_l] = deepupdate(operation_doc, manual_doc)
# Thanks to self.route, there can only be one rule per endpoint
full_endpoint = ".".join((name, endpoint))
rule = next(app.url_map.iter_rules(full_endpoint))
spec.path(rule=rule, operations=doc, parameters=endpoint_parameters)
import flask_smorest.blueprint
flask_smorest.Api.register_blueprint = register_blueprint
flask_smorest.blueprint.Blueprint.register_views_in_doc = register_views_in_doc
from flask_smorest import Api, Blueprint as SmorestBlueprint
# Initialize Flask app
app = Flask(__name__, subdomain_matching=True)
app.url_map.default_subdomain = "docs"
app.config["API_TITLE"] = "My API"
app.config["API_VERSION"] = "v1"
app.config["OPENAPI_VERSION"] = "3.0.2"
app.config["OPENAPI_URL_PREFIX"] = "/"
app.config["OPENAPI_REDOC_PATH"] = "/redoc"
app.config[
"OPENAPI_REDOC_URL"
] = "https://cdn.jsdelivr.net/npm/redoc/bundles/redoc.standalone.js"
app.config[
"SERVER_NAME"
] = "example.com:5000" # Configure the server name to handle subdomains
# Initialize API
api = Api(app)
# Create 'account' and 'manage' blueprint
account_blp = SmorestBlueprint("account", "account", subdomain="account")
manage_blp = SmorestBlueprint("manage", "manage", subdomain="manage")
@account_blp.route("/info", subdomain="account")
def account_info():
return jsonify({"message": "Account Info"})
@manage_blp.route("/settings", subdomain="manage")
def manage_settings():
return jsonify({"message": "Manage Settings"})
# Register blueprints with API
api.register_blueprint(account_blp, subdomain="account")
api.register_blueprint(manage_blp, subdomain="manage")
if __name__ == "__main__":
# Run the app on all interfaces to accept requests from subdomains
app.run(debug=True, host="0.0.0.0", port=5000)
tagging @lafrech and @revmischa on thoughts
I have this sample app
I added the entry below in
/etc/hosts
http://account.example.com:5000/info
workshttp://manage.example.com:5000/settings
workshttp://docs.example.com:5000/redoc
works but server URL for each endpoint is missing. Both endpoints starts withhttp://docs.example.com:5000