Skip to content

Commit

Permalink
No default header, use prefix header instead of base path header
Browse files Browse the repository at this point in the history
  • Loading branch information
Julien Sagnard committed Dec 18, 2018
1 parent 606e137 commit 2718bdd
Show file tree
Hide file tree
Showing 8 changed files with 32 additions and 30 deletions.
10 changes: 5 additions & 5 deletions connexion/apis/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def __init__(self, specification, base_path=None, arguments=None,
extra={'swagger_ui': self.options.openapi_console_ui_available,
'swagger_path': self.options.openapi_console_ui_from_dir,
'swagger_url': self.options.openapi_console_ui_path,
'original_uri_header': self.options.original_uri_header
'proxy_uri_prefix_header': self.options.proxy_uri_prefix_header
})

self._set_base_path(base_path)
Expand Down Expand Up @@ -137,17 +137,17 @@ def add_swagger_ui(self):
Adds swagger ui to {base_path}/ui/
"""

def _get_specs_behind_proxy(self, original_uri):
def _get_specs_behind_proxy(self, prefix_uri):
"""
Update OpenAPI base path using specified original_uri. (from X-Original-URI when API is behind a proxy).
:param original_uri: uri to use to replace base_path
:param prefix_uri: uri to use to prefix base_path
:return: Updated raw specifications
"""

if not original_uri:
if not prefix_uri:
return self.specification.raw
specs = copy.copy(self.specification.raw)
self.specification.set_base_path(specs, original_uri)
self.specification.set_base_path(specs, prefix_uri + self.base_path)
return specs

@abc.abstractmethod
Expand Down
4 changes: 2 additions & 2 deletions connexion/apis/aiohttp_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def add_openapi_json(self):

@asyncio.coroutine
def _get_openapi_json(self, req):
specs = self._get_specs_behind_proxy(req.headers.get(self.options.original_uri_header))
specs = self._get_specs_behind_proxy(req.headers.get(self.options.proxy_uri_prefix_header))
return web.Response(
status=200,
content_type='application/json',
Expand Down Expand Up @@ -115,7 +115,7 @@ def add_swagger_ui(self):
@aiohttp_jinja2.template('index.j2')
@asyncio.coroutine
def _get_swagger_ui_home(self, req):
base_path = req.headers.get(self.options.original_uri_header, self.base_path)
base_path = req.headers.get(self.options.proxy_uri_prefix_header, '') + self.base_path
return {'openapi_spec_url': (base_path +
self.options.openapi_spec_path)}

Expand Down
6 changes: 4 additions & 2 deletions connexion/apis/flask_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ def add_openapi_json(self):
self.blueprint.add_url_rule(self.options.openapi_spec_path,
endpoint_name,
lambda: flask.jsonify(
self._get_specs_behind_proxy(flask.request.headers.get(self.options.original_uri_header))
self._get_specs_behind_proxy(
flask.request.headers.get(self.options.proxy_uri_prefix_header)
)
)
)

Expand Down Expand Up @@ -281,7 +283,7 @@ def console_ui_home(self):
:return:
"""
base_path = flask.request.headers.get(self.options.original_uri_header, self.base_path)
base_path = flask.request.headers.get(self.options.proxy_uri_prefix_header, '') + self.base_path
return flask.render_template(
'index.j2',
openapi_spec_url=(base_path + self.options.openapi_spec_path)
Expand Down
6 changes: 3 additions & 3 deletions connexion/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,13 @@ def uri_parser_class(self):
return self._options.get('uri_parser_class', None)

@property
def original_uri_header(self):
def proxy_uri_prefix_header(self):
# type: () -> str
"""
The header to use to dynamically adapt spec base_path.
The header to use to dynamically prefix spec base_path.
Default: None
"""
return self._options.get('original_uri_header', 'X-Original-URI')
return self._options.get('proxy_uri_prefix_header', '')


def filter_values(dictionary):
Expand Down
26 changes: 12 additions & 14 deletions docs/cookbook.rst
Original file line number Diff line number Diff line change
Expand Up @@ -132,25 +132,23 @@ Access application under subpath through NGINX

Sometimes, it's interesting to setup your application
behind a reverse proxy with a rewrite rule.
By default, Connexion will have a look to X-Original-URI header.
If present, base_path will be dynamically adapted
For example with NGINX:
In this case, you can use `proxy_uri_prefix_header` option to specify a
header name which will contains prefix to prepend to specifications base path.

.. code-block:: python
import connexion
app = connexion.FlaskApp(__name__, options={'proxy_uri_prefix_header': 'X-Forwarded-Prefix'})
app.add_api('swagger.yaml')
app.run(port=8080)
Corresponding NGINX configuration:

.. code-block:: NGINX
location /api {
# Define the location of the proxy server to send the request to
proxy_pass http://web:8000;
# Add original URI header
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Forwarded-Prefix /api;
}
You can customize header name using `original_uri_header` option:

.. code-block:: python
import connexion
app = connexion.FlaskApp(__name__, options={'original_uri_header': 'My-URI-Header'})
app.add_api('swagger.yaml')
app.run(port=8080)
7 changes: 4 additions & 3 deletions tests/aiohttp/test_aiohttp_simple_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,12 @@ def test_swagger_json_behind_proxy(simple_api_spec_dir, aiohttp_client):
""" Verify the swagger.json file is returned with base_path updated according to X-Original-URI header. """
app = AioHttpApp(__name__, port=5001,
specification_dir=simple_api_spec_dir,
options={'proxy_uri_prefix_header': 'X-Forwarded-Prefix'},
debug=True)
api = app.add_api('swagger.yaml')

app_client = yield from aiohttp_client(app.app)
headers = {'X-Original-URI': '/behind/proxy/v1.0'}
headers = {'X-Forwarded-Prefix': '/behind/proxy'}

swagger_ui = yield from app_client.get('/v1.0/ui/', headers=headers)
assert swagger_ui.status == 200
Expand All @@ -171,12 +172,12 @@ def test_openapi_json_behind_proxy(simple_api_spec_dir, aiohttp_client):
""" Verify the swagger.json file is returned with base_path updated according to X-Original-URI header. """
app = AioHttpApp(__name__, port=5001,
specification_dir=simple_api_spec_dir,
options={'original_uri_header': 'My-URI-Header'},
options={'proxy_uri_prefix_header': 'My-URI-Header'},
debug=True)
api = app.add_api('openapi.yaml')

app_client = yield from aiohttp_client(app.app)
headers = {'My-URI-Header': '/behind/proxy/v1.0'}
headers = {'My-URI-Header': '/behind/proxy'}

swagger_ui = yield from app_client.get('/v1.0/ui/', headers=headers)
assert swagger_ui.status == 200
Expand Down
2 changes: 1 addition & 1 deletion tests/api/test_responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def test_app(simple_app):
def test_openapi_json_behind_proxy(simple_app):
""" Verify the swagger.json file is returned with base_path updated according to X-Original-URI header. """
app_client = simple_app.app.test_client()
headers = {'X-Original-URI': '/behind/proxy/v1.0'}
headers = {'X-Forwarded-Prefix': '/behind/proxy'}

swagger_ui = app_client.get('/v1.0/ui/', headers=headers)
assert swagger_ui.status_code == 200
Expand Down
1 change: 1 addition & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ def build_app_from_fixture(api_spec_folder, spec_file='openapi.yaml', **kwargs):
cnx_app = App(__name__,
port=5001,
specification_dir=FIXTURES_FOLDER / api_spec_folder,
options={'proxy_uri_prefix_header': 'X-Forwarded-Prefix'},
debug=debug)

cnx_app.add_api(spec_file, **kwargs)
Expand Down

0 comments on commit 2718bdd

Please sign in to comment.