diff --git a/flask_apispec/extension.py b/flask_apispec/extension.py
index 68636b1..3430ec1 100644
--- a/flask_apispec/extension.py
+++ b/flask_apispec/extension.py
@@ -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)
@@ -67,9 +70,15 @@ def _defer(self, callable, *args, **kwargs):
if self.app:
bound()
+ @property
+ def blueprint_name(self):
+ if self.support_multiple_version:
+ return 'flask-apispec-' + self.spec.version
+ return 'flask-apispec'
+
def add_swagger_routes(self):
blueprint = flask.Blueprint(
- 'flask-apispec',
+ self.blueprint_name,
__name__,
static_folder='./static',
template_folder='./templates',
@@ -78,19 +87,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():
diff --git a/flask_apispec/templates/swagger-ui.html b/flask_apispec/templates/swagger-ui.html
index 3752e62..7a89942 100644
--- a/flask_apispec/templates/swagger-ui.html
+++ b/flask_apispec/templates/swagger-ui.html
@@ -3,19 +3,19 @@
Swagger UI
-
-
-
+
+
+
-
-
+
+
diff --git a/tests/test_extension.py b/tests/test_extension.py
index f1f5a7a..2243cc9 100644
--- a/tests/test_extension.py
+++ b/tests/test_extension.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
+import random
import pytest
from flask import Blueprint
@@ -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'
diff --git a/tests/test_openapi.py b/tests/test_openapi.py
index 11752b6..afa00fa 100644
--- a/tests/test_openapi.py
+++ b/tests/test_openapi.py
@@ -154,7 +154,7 @@ def path(self, app, spec, function_view):
return spec._paths['/bands/{band_id}/']
def test_responses(self, schemas, path):
- response = path['delete']['responses'][204]
+ response = path['delete']['responses']['204']
assert response['description'] == 'a deleted band'
assert response['schema'] == {}
diff --git a/tests/test_views.py b/tests/test_views.py
index 23e8365..cc12a1f 100644
--- a/tests/test_views.py
+++ b/tests/test_views.py
@@ -271,8 +271,15 @@ def test_schemas_none(self, app, client, models, schemas):
class ConcreteResource(MethodResource):
@marshal_with(None, code=204)
def delete(self, **kwargs):
- return make_response('', 204)
+ from flask import Response
+ response = Response(None, 204)
+
+ # remove content-type as webtest raises error for this
+ # https://github.com/Pylons/webtest/blob/master/webtest/lint.py#L543
+ response.headers.pop('Content-Type', None)
+ return response
app.add_url_rule('//', view_func=ConcreteResource.as_view('concrete'))
res = client.delete('/5/')
+ assert res.status_code == 204
assert res.body == b''