From cd4bd4a18e3d148dc491e976b179ec9b66717bf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristi=20V=C3=AEjdea?= Date: Thu, 9 Aug 2018 03:32:04 +0300 Subject: [PATCH] Add SPEC_URL setting --- docs/settings.rst | 43 +++++++++-- src/drf_yasg/app_settings.py | 2 + src/drf_yasg/renderers.py | 85 ++++++++++++++-------- src/drf_yasg/static/drf-yasg/redoc-init.js | 6 +- testproj/testproj/settings/base.py | 4 + 5 files changed, 102 insertions(+), 38 deletions(-) diff --git a/docs/settings.rst b/docs/settings.rst index a9dc30d..311df1b 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -31,12 +31,23 @@ Example: ... } +.. _url-settings: + +All settings which configure URLs (``LOGIN_URL``, ``SPEC_URL``, ``VALIDATOR_URL``, etc.) can accept several forms of +input: + +* A view name: `urls.reverse()` will be used to reverse-resolve the name +* A 2-tuple of ``(view_name, kwargs)```: `urls.reverse()` will be used to reverse-resolve the name using the given + `kwargs`; `kwargs` must be a dict +* A 3-tuple of ``(view_name, args, kwargs)```: `urls.reverse()` will be used to reverse-resolve the name using the given + `args` and `kwargs`; `args`, `kwargs` must be a tuple/list and a dict respectively +* A URL, which will be used as-is + The possible settings and their default values are as follows: -******************** -``SWAGGER_SETTINGS`` -******************** - +**************** +SWAGGER_SETTINGS +**************** .. _default-class-settings: @@ -192,6 +203,15 @@ Swagger UI settings Swagger UI configuration settings. |br| See https://github.com/swagger-api/swagger-ui/blob/112bca906553a937ac67adc2e500bdeed96d067b/docs/usage/configuration.md#parameters. +SPEC_URL +-------- + +URL pointing to a swagger document for use by swagger-ui. The default behaviour is to append ``?format=openapi`` to the +URL which serves the UI; see :ref:`note on URL settings ` above. + +**Default**: :python:`None` |br| +*Maps to parameter*: ``url`` + VALIDATOR_URL ------------- @@ -312,9 +332,9 @@ This does not filter the operations from the display. **Default**: :python:`['get','put','post','delete','options','head','patch','trace']` |br| *Maps to parameter*: ``supportedSubmitMethods`` -****************** -``REDOC_SETTINGS`` -****************** +************** +REDOC_SETTINGS +************** .. _redoc-ui-settings: @@ -324,6 +344,15 @@ ReDoc UI settings ReDoc UI configuration settings. |br| See https://github.com/Rebilly/ReDoc#configuration. +SPEC_URL +-------- + +URL pointing to a swagger document for use by ReDoc. The default behaviour is to append ``?format=openapi`` to the +URL which serves the UI; see :ref:`note on URL settings ` above. + +**Default**: :python:`None` |br| +*Maps to attribute*: ``spec-url`` + LAZY_RENDERING -------------- diff --git a/src/drf_yasg/app_settings.py b/src/drf_yasg/app_settings.py index baaea56..69e6262 100644 --- a/src/drf_yasg/app_settings.py +++ b/src/drf_yasg/app_settings.py @@ -40,6 +40,7 @@ SWAGGER_DEFAULTS = { 'SECURITY_REQUIREMENTS': None, 'LOGIN_URL': getattr(settings, 'LOGIN_URL', None), 'LOGOUT_URL': getattr(settings, 'LOGOUT_URL', None), + 'SPEC_URL': None, 'VALIDATOR_URL': '', 'OPERATIONS_SORTER': None, @@ -65,6 +66,7 @@ SWAGGER_DEFAULTS = { } REDOC_DEFAULTS = { + 'SPEC_URL': None, 'LAZY_RENDERING': True, 'HIDE_HOSTNAME': False, 'EXPAND_RESPONSES': 'all', diff --git a/src/drf_yasg/renderers.py b/src/drf_yasg/renderers.py index 1b00105..5fb3d4c 100644 --- a/src/drf_yasg/renderers.py +++ b/src/drf_yasg/renderers.py @@ -1,8 +1,11 @@ +import six + from django.shortcuts import render, resolve_url from rest_framework.renderers import BaseRenderer, JSONRenderer, TemplateHTMLRenderer from rest_framework.utils import json from drf_yasg.openapi import Swagger +from drf_yasg.utils import filter_none from .app_settings import redoc_settings, swagger_settings from .codecs import VALIDATORS, OpenAPICodecJson, OpenAPICodecYaml @@ -74,23 +77,52 @@ class _UIRenderer(BaseRenderer): def set_context(self, renderer_context, swagger): renderer_context['title'] = swagger.info.title renderer_context['version'] = swagger.info.version - renderer_context['swagger_settings'] = json.dumps(self.get_swagger_ui_settings()) - renderer_context['redoc_settings'] = json.dumps(self.get_redoc_settings()) renderer_context['oauth2_config'] = json.dumps(self.get_oauth2_config()) renderer_context['USE_SESSION_AUTH'] = swagger_settings.USE_SESSION_AUTH renderer_context.update(self.get_auth_urls()) - def get_auth_urls(self): - urls = {} - if swagger_settings.LOGIN_URL is not None: - urls['LOGIN_URL'] = resolve_url(swagger_settings.LOGIN_URL) - if swagger_settings.LOGOUT_URL is not None: - urls['LOGOUT_URL'] = resolve_url(swagger_settings.LOGOUT_URL) + def resolve_url(self, to): + if to is None: + return None - return urls + args, kwargs = None, None + if not isinstance(to, six.string_types): + if len(to) > 2: + to, args, kwargs = to + elif len(to) == 2: + to, kwargs = to + + args = args or () + kwargs = kwargs or {} + + return resolve_url(to, *args, **kwargs) + + def get_auth_urls(self): + urls = { + 'LOGIN_URL': self.resolve_url(swagger_settings.LOGIN_URL), + 'LOGOUT_URL': self.resolve_url(swagger_settings.LOGOUT_URL), + } + + return filter_none(urls) + + def get_oauth2_config(self): + data = swagger_settings.OAUTH2_CONFIG + assert isinstance(data, dict), "OAUTH2_CONFIG must be a dict" + return data + + +class SwaggerUIRenderer(_UIRenderer): + """Renders a swagger-ui web interface for schema browisng.""" + template = 'drf-yasg/swagger-ui.html' + format = 'swagger' + + def set_context(self, renderer_context, swagger): + super(SwaggerUIRenderer, self).set_context(renderer_context, swagger) + renderer_context['swagger_settings'] = json.dumps(self.get_swagger_ui_settings()) def get_swagger_ui_settings(self): data = { + 'url': self.resolve_url(swagger_settings.SPEC_URL), 'operationsSorter': swagger_settings.OPERATIONS_SORTER, 'tagsSorter': swagger_settings.TAGS_SORTER, 'docExpansion': swagger_settings.DOC_EXPANSION, @@ -103,42 +135,35 @@ class _UIRenderer(BaseRenderer): 'oauth2RedirectUrl': swagger_settings.OAUTH2_REDIRECT_URL, 'supportedSubmitMethods': swagger_settings.SUPPORTED_SUBMIT_METHODS, } - data = {k: v for k, v in data.items() if v is not None} + data = filter_none(data) if swagger_settings.VALIDATOR_URL != '': - data['validatorUrl'] = swagger_settings.VALIDATOR_URL + data['validatorUrl'] = self.resolve_url(swagger_settings.VALIDATOR_URL) return data + +class ReDocRenderer(_UIRenderer): + """Renders a ReDoc web interface for schema browisng.""" + template = 'drf-yasg/redoc.html' + format = 'redoc' + + def set_context(self, renderer_context, swagger): + super(ReDocRenderer, self).set_context(renderer_context, swagger) + renderer_context['redoc_settings'] = json.dumps(self.get_redoc_settings()) + def get_redoc_settings(self): data = { + 'url': self.resolve_url(redoc_settings.SPEC_URL), 'lazyRendering': redoc_settings.LAZY_RENDERING, 'hideHostname': redoc_settings.HIDE_HOSTNAME, 'expandResponses': redoc_settings.EXPAND_RESPONSES, 'pathInMiddle': redoc_settings.PATH_IN_MIDDLE, } + data = filter_none(data) return data - def get_oauth2_config(self): - data = swagger_settings.OAUTH2_CONFIG - assert isinstance(data, dict), "OAUTH2_CONFIG must be a dict" - return data - -class SwaggerUIRenderer(_UIRenderer): - """Renders a swagger-ui web interface for schema browisng. - Also requires :class:`.OpenAPIRenderer` as an available renderer on the same view. - """ - template = 'drf-yasg/swagger-ui.html' - format = 'swagger' - - -class ReDocRenderer(_UIRenderer): - """Renders a ReDoc web interface for schema browisng. - Also requires :class:`.OpenAPIRenderer` as an available renderer on the same view. - """ - template = 'drf-yasg/redoc.html' - format = 'redoc' class ReDocOldRenderer(ReDocRenderer): """Renders a ReDoc 1.x.x web interface for schema browisng.""" template = 'drf-yasg/redoc-old.html' diff --git a/src/drf_yasg/static/drf-yasg/redoc-init.js b/src/drf_yasg/static/drf-yasg/redoc-init.js index fd1c788..70f6f1b 100644 --- a/src/drf_yasg/static/drf-yasg/redoc-init.js +++ b/src/drf_yasg/static/drf-yasg/redoc-init.js @@ -3,9 +3,13 @@ var currentPath = window.location.protocol + "//" + window.location.host + window.location.pathname; var specURL = currentPath + '?format=openapi'; var redoc = document.createElement("redoc"); -redoc.setAttribute("spec-url", specURL); var redocSettings = JSON.parse(document.getElementById('redoc-settings').innerHTML); +if (redocSettings.url) { + specURL = redocSettings.url; +} +redoc.setAttribute("spec-url", specURL); + if (redocSettings.lazyRendering) { redoc.setAttribute("lazy-rendering", ''); } diff --git a/testproj/testproj/settings/base.py b/testproj/testproj/settings/base.py index 953b861..5e43fea 100644 --- a/testproj/testproj/settings/base.py +++ b/testproj/testproj/settings/base.py @@ -108,6 +108,10 @@ SWAGGER_SETTINGS = { } } +REDOC_SETTINGS = { + 'SPEC_URL': ('schema-json', {'format': '.json'}), +} + # Internationalization # https://docs.djangoproject.com/en/1.11/topics/i18n/