Skip to content

Commit

Permalink
Support multiple versions swagger
Browse files Browse the repository at this point in the history
  • Loading branch information
enjoy2000 committed Apr 8, 2019
1 parent d8cb658 commit 341319a
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 11 deletions.
31 changes: 28 additions & 3 deletions flask_apispec/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,17 @@ def get_pet(pet_id):
:param Flask app: App associated with API documentation
:param APISpec spec: apispec specification associated with API documentation
:param bool support_multiple_version: support multiple version swaggers
by register doc to 'swagger-{api_version}' url
"""

def __init__(self, app=None):
def __init__(self, app=None, support_multiple_version=False):
self._deferred = []
self.app = app
self.view_converter = None
self.resource_converter = None
self.spec = None
self.support_multiple_version = support_multiple_version

if app:
self.init_app(app)
Expand All @@ -67,9 +70,13 @@ def _defer(self, callable, *args, **kwargs):
if self.app:
bound()

@property
def blueprint_name(self):
return 'flask-apispec-' + self.spec.version if self.support_multiple_version else 'flask-apispec'

def add_swagger_routes(self):
blueprint = flask.Blueprint(
'flask-apispec',
self.blueprint_name,
__name__,
static_folder='./static',
template_folder='./templates',
Expand All @@ -78,19 +85,37 @@ def add_swagger_routes(self):

json_url = self.app.config.get('APISPEC_SWAGGER_URL', '/swagger/')
if json_url:
if self.support_multiple_version:
json_url = self.make_url_with_suffix_version(json_url)

blueprint.add_url_rule(json_url, 'swagger-json', self.swagger_json)

ui_url = self.app.config.get('APISPEC_SWAGGER_UI_URL', '/swagger-ui/')
if ui_url:
if self.support_multiple_version:
ui_url = self.make_url_with_suffix_version(ui_url)
blueprint.add_url_rule(ui_url, 'swagger-ui', self.swagger_ui)

self.app.register_blueprint(blueprint)

def make_url_with_suffix_version(self, url):
# adding version suffix
if url.endswith('/'):
url = url[:-1] + '-' + self.spec.version + '/'
elif url.endswith('.json') or url.endswith('.html'):
# support extension url
url = url.replace('.json', '-' + self.spec.version + '.json') \
.replace('.html', '-' + self.spec.version + '.html')
else:
url += '-' + self.spec.version
return url

def swagger_json(self):
return flask.jsonify(self.spec.to_dict())

def swagger_ui(self):
return flask.render_template('swagger-ui.html')
return flask.render_template('swagger-ui.html',
blueprint_name=self.blueprint_name)

def register_existing_resources(self):
for name, rule in self.app.view_functions.items():
Expand Down
16 changes: 8 additions & 8 deletions flask_apispec/templates/swagger-ui.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="icon" type="image/png" href="{{ url_for('flask-apispec.static', filename='favicon-32x32.png') }}" sizes="32x32" />
<link rel="icon" type="image/png" href="{{ url_for('flask-apispec.static', filename='favicon-16x16.png') }}" sizes="16x16" />
<link href="{{ url_for('flask-apispec.static', filename='swagger-ui.css') }}" rel="stylesheet" type="text/css"/>
<link rel="icon" type="image/png" href="{{ url_for(blueprint_name + '.static', filename='favicon-32x32.png') }}" sizes="32x32" />
<link rel="icon" type="image/png" href="{{ url_for(blueprint_name + '.static', filename='favicon-16x16.png') }}" sizes="16x16" />
<link href="{{ url_for(blueprint_name + '.static', filename='swagger-ui.css') }}" rel="stylesheet" type="text/css"/>
</head>

<body class="swagger-section">
<div id="message-bar" class="swagger-ui-wrap" data-sw-translate>&nbsp;</div>
<div id="swagger-ui-container" class="swagger-ui-wrap"></div>
<script src="{{ url_for('flask-apispec.static', filename='swagger-ui-bundle.js') }}" type="text/javascript"></script>
<script src="{{ url_for('flask-apispec.static', filename='swagger-ui-standalone-preset.js') }}" type="text/javascript"></script>
<script src="{{ url_for(blueprint_name + '.static', filename='swagger-ui-bundle.js') }}" type="text/javascript"></script>
<script src="{{ url_for(blueprint_name + '.static', filename='swagger-ui-standalone-preset.js') }}" type="text/javascript"></script>
<script type="text/javascript">
var ui = SwaggerUIBundle({
url: "{{ url_for('flask-apispec.swagger-json') }}",
url: "{{ url_for(blueprint_name + '.swagger-json') }}",
dom_id: '#swagger-ui-container',
deepLinking: true,
presets: [
Expand All @@ -26,8 +26,8 @@
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "BaseLayout"
})
window.ui = ui
});
window.ui = ui;
</script>
</body>

Expand Down
27 changes: 27 additions & 0 deletions tests/test_extension.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
import random

import pytest
from flask import Blueprint
Expand Down Expand Up @@ -98,3 +99,29 @@ def test_apispec_config(self, app):
assert docs.spec.title == 'test-extension'
assert docs.spec.version == '2.1'
assert docs.spec.openapi_version == '2.0'

def test_make_url_with_suffix_version_with_version(self, app):
app.config['APISPEC_VERSION'] = 'v2'
docs = FlaskApiSpec(app, support_multiple_version=True)

assert docs.make_url_with_suffix_version('/swagger/') == '/swagger-v2/'
assert docs.make_url_with_suffix_version('/swagger-ui/') == '/swagger-ui-v2/'
assert docs.make_url_with_suffix_version('/swagger.json') == '/swagger-v2.json'
assert docs.make_url_with_suffix_version('/swagger.html') == '/swagger-v2.html'
assert docs.make_url_with_suffix_version('/swagger') == '/swagger-v2'

def test_urls_with_support_multiple_version(self, app, client):
app.config['APISPEC_VERSION'] = 'v2'
docs = FlaskApiSpec(app, support_multiple_version=True)
res = client.get('/swagger-v2/')
assert res.json == docs.spec.to_dict()
client.get('/swagger-ui-v2/')

def test_support_multiple_version_by_changing_blueprint_name(self, app):
version = 'v{}'.format(random.randint(1, 5))
app.config['APISPEC_VERSION'] = version
docs = FlaskApiSpec(app, support_multiple_version=True)
assert docs.blueprint_name == 'flask-apispec-' + version

docs_without_support_multiple_version = FlaskApiSpec(app)
assert docs_without_support_multiple_version.blueprint_name == 'flask-apispec'

0 comments on commit 341319a

Please sign in to comment.