diff --git a/.gitignore b/.gitignore index ebb3a6ce..b8f00fed 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,9 @@ doc/_build/ # Specifics flask_restx/static node_modules + +# pyenv +.python-version + +# Jet Brains +.idea diff --git a/flask_restx/api.py b/flask_restx/api.py index dd4d318d..f1f69664 100644 --- a/flask_restx/api.py +++ b/flask_restx/api.py @@ -94,6 +94,9 @@ class Api(object): :param FormatChecker format_checker: A jsonschema.FormatChecker object that is hooked into the Model validator. A default or a custom FormatChecker can be provided (e.g., with custom checkers), otherwise the default action is to not enforce any format validation. + :param url_scheme: If set to a string (e.g. http, https), then the specs_url and base_url will explicitly use this + scheme regardless of how the application is deployed. This is necessary for some deployments behind a reverse + proxy. """ def __init__( @@ -123,6 +126,7 @@ def __init__( catch_all_404s=False, serve_challenge_on_401=False, format_checker=None, + url_scheme=None, **kwargs ): self.version = version @@ -178,6 +182,7 @@ def __init__( api=self, path="/", ) + self.url_scheme = url_scheme if app is not None: self.app = app self.init_app(app) @@ -198,7 +203,9 @@ def init_app(self, app, **kwargs): :param str contact: A contact email for the API (used in Swagger documentation) :param str license: The license associated to the API (used in Swagger documentation) :param str license_url: The license page URL (used in Swagger documentation) - + :param url_scheme: If set to a string (e.g. http, https), then the specs_url and base_url will explicitly use + this scheme regardless of how the application is deployed. This is necessary for some deployments behind a + reverse proxy. """ self.app = app self.title = kwargs.get("title", self.title) @@ -209,6 +216,7 @@ def init_app(self, app, **kwargs): self.contact_email = kwargs.get("contact_email", self.contact_email) self.license = kwargs.get("license", self.license) self.license_url = kwargs.get("license_url", self.license_url) + self.url_scheme = kwargs.get("url_scheme", self.url_scheme) self._add_specs = kwargs.get("add_specs", True) # If app is a blueprint, defer the initialization @@ -220,7 +228,6 @@ def init_app(self, app, **kwargs): else: self.blueprint = app - def _init_app(self, app): """ Perform initialization actions with the given :class:`flask.Flask` object. @@ -261,7 +268,6 @@ def _init_app(self, app): DeprecationWarning ) - def __getattr__(self, name): try: return getattr(self.default_namespace, name) @@ -515,11 +521,16 @@ def endpoint(self, name): @property def specs_url(self): """ - The Swagger specifications relative url (ie. `swagger.json`) + The Swagger specifications relative url (ie. `swagger.json`). If + the spec_url_scheme attribute is set, then the full url is provided instead + (e.g. http://localhost/swaggger.json). :rtype: str """ - return url_for(self.endpoint("specs")) + external = None if self.url_scheme is None else True + return url_for( + self.endpoint("specs"), _scheme=self.url_scheme, _external=external + ) @property def base_url(self): @@ -528,7 +539,7 @@ def base_url(self): :rtype: str """ - return url_for(self.endpoint("root"), _external=True) + return url_for(self.endpoint("root"), _scheme=self.url_scheme, _external=True) @property def base_path(self): diff --git a/tests/test_api.py b/tests/test_api.py index fb0b9ada..1dd6452a 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -342,3 +342,13 @@ class TestResource(restx.Resource): assert decorator1.called is True assert decorator2.called is True assert decorator3.called is True + + def test_specs_url(self, app): + api = restx.Api(app) + specs_url = api.specs_url + assert specs_url == "/swagger.json" + + def test_url_scheme(self, app): + api = restx.Api(app, url_scheme="https") + assert api.specs_url == "https://localhost/swagger.json" + assert api.base_url == "https://localhost/"