Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion flask_restplus/__about__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-
__version__ = '0.12.2.dev'
__version__ = '0.12.4.dev'
__description__ = 'Fully featured framework for fast, easy and documented API development with Flask'
13 changes: 12 additions & 1 deletion flask_restplus/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ 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 bool behind_proxy: Set to True to discover Swagger "host" behind a proxy
'''

def __init__(self, app=None, version='1.0', title=None, description=None,
Expand All @@ -97,6 +98,7 @@ def __init__(self, app=None, version='1.0', title=None, description=None,
tags=None, prefix='', ordered=False,
default_mediatype='application/json', decorators=None,
catch_all_404s=False, serve_challenge_on_401=False, format_checker=None,
behind_proxy=False,
**kwargs):
self.version = version
self.title = title or 'API'
Expand Down Expand Up @@ -125,6 +127,7 @@ def __init__(self, app=None, version='1.0', title=None, description=None,
self.models = {}
self._refresolver = None
self.format_checker = format_checker
self.behind_proxy = behind_proxy
self.namespaces = []
self.default_namespace = self.namespace(default, default_label,
endpoint='{0}-declaration'.format(default),
Expand Down Expand Up @@ -448,10 +451,16 @@ def endpoint(self, name):
def specs_url(self):
'''
The Swagger specifications absolute url (ie. `swagger.json`)
Use a relative url when behind a proxy.

:rtype: str
'''
return url_for(self.endpoint('specs'), _external=True)
if self.behind_proxy:
# Use relative URL.
external = False
else:
external = True
return url_for(self.endpoint('specs'), _external=external)

@property
def base_url(self):
Expand Down Expand Up @@ -481,6 +490,8 @@ def __schema__(self):
if not self._schema:
try:
self._schema = Swagger(self).as_dict()
if self.behind_proxy and "host" in self._schema:
del self._schema["host"]
except Exception:
# Log the source exception for debugging purpose
# and return an error message
Expand Down
23 changes: 23 additions & 0 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

import copy

import pytest

from flask import url_for, Blueprint

import flask_restplus as restplus
Expand Down Expand Up @@ -95,6 +97,27 @@ def test_specs_endpoint_not_found_if_not_added(self, app, client):
resp = client.get('/swagger.json')
assert resp.status_code == 404

@pytest.mark.options(server_name='api.restplus.org')
def test_specs_endpoint_added(self, app, client):
api = restplus.Api()
api.init_app(app, add_specs=True)
assert app.config.get('SERVER_NAME') == 'api.restplus.org'
assert "host" in api.__schema__
resp = client.get('/swagger.json')
assert resp.status_code == 200

@pytest.mark.options(server_name='api.restplus.org')
def test_specs_endpoint_added_behind_proxy(self, app, client):
api = restplus.Api(behind_proxy=True)
api.init_app(app, add_specs=True)
# Behind a proxy, the specs URL must be relative.
assert api.specs_url == '/swagger.json'
# ...and the "host" field must not be present.
assert app.config.get('SERVER_NAME') == 'api.restplus.org'
assert "host" not in api.__schema__
resp = client.get('/swagger.json')
assert resp.status_code == 200

def test_default_endpoint(self, app):
api = restplus.Api(app)

Expand Down