From 5ccdded2a8beeff7aa35c973298f107bb05e61c1 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Wed, 3 Oct 2018 13:43:04 +0100 Subject: [PATCH] Add both OpenAPIRenderer and JSONOpenAPIRenderer --- rest_framework/compat.py | 7 ++++ .../management/commands/generate_schema.py | 7 ++-- rest_framework/renderers.py | 40 +++++++++++++++---- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/rest_framework/compat.py b/rest_framework/compat.py index 8b4481524..1d34828bd 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -143,6 +143,13 @@ except ImportError: coreschema = None +# pyyaml is optional +try: + import yaml +except ImportError: + yaml = None + + # django-crispy-forms is optional try: import crispy_forms diff --git a/rest_framework/management/commands/generate_schema.py b/rest_framework/management/commands/generate_schema.py index 9ac17ec9c..1e3d83fb8 100644 --- a/rest_framework/management/commands/generate_schema.py +++ b/rest_framework/management/commands/generate_schema.py @@ -1,7 +1,7 @@ from django.core.management.base import BaseCommand from rest_framework.compat import coreapi -from rest_framework.renderers import CoreJSONRenderer, OpenAPIRenderer +from rest_framework.renderers import CoreJSONRenderer, OpenAPIRenderer, JSONOpenAPIRenderer from rest_framework.settings import api_settings @@ -15,8 +15,6 @@ class Command(BaseCommand): # - title # - url # - description - # - urlconf - # - patterns # # Don't particularly want to pass these on the command-line. # conf file? @@ -42,5 +40,6 @@ class Command(BaseCommand): def get_renderer(self, format): return { 'corejson': CoreJSONRenderer(), - 'openapi': OpenAPIRenderer() + 'openapi': OpenAPIRenderer(), + 'openapi-json': JSONOpenAPIRenderer() } diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 6ced8e1a0..93f69acfa 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -25,7 +25,7 @@ from django.utils.html import mark_safe from rest_framework import VERSION, exceptions, serializers, status from rest_framework.compat import ( INDENT_SEPARATORS, LONG_SEPARATORS, SHORT_SEPARATORS, coreapi, coreschema, - pygments_css, urlparse + pygments_css, urlparse, yaml ) from rest_framework.exceptions import ParseError from rest_framework.request import is_form_media_type, override_method @@ -934,7 +934,7 @@ class CoreJSONRenderer(BaseRenderer): return codec.dump(data, indent=indent) -class OpenAPIRenderer: +class _BaseOpenAPIRenderer: CLASS_TO_TYPENAME = { coreschema.Object: 'object', coreschema.Array: 'array', @@ -944,9 +944,6 @@ class OpenAPIRenderer: coreschema.Boolean: 'boolean', } - def __init__(self): - assert coreapi, 'Using OpenAPIRenderer, but `coreapi` is not installed.' - def get_schema(self, instance): schema = {} if instance.__class__ in self.CLASS_TO_TYPENAME: @@ -1011,8 +1008,8 @@ class OpenAPIRenderer: return paths - def render(self, data, media_type=None, renderer_context=None): - return json.dumps({ + def get_structure(self, data): + return { 'openapi': '3.0.0', 'info': { 'version': '', @@ -1023,4 +1020,31 @@ class OpenAPIRenderer: 'url': data.url }], 'paths': self.get_paths(data) - }, indent=4) + } + + +class OpenAPIRenderer(_BaseOpenAPIRenderer): + media_type = 'application/vnd.oai.openapi' + charset = None + format = 'openapi' + + def __init__(self): + assert coreapi, 'Using OpenAPIRenderer, but `coreapi` is not installed.' + assert yaml, 'Using OpenAPIRenderer, but `pyyaml` is not installed.' + + def render(self, data, media_type=None, renderer_context=None): + structure = self.get_structure(data) + return yaml.dumps(structure, default_flow_style=False) + + +class JSONOpenAPIRenderer(_BaseOpenAPIRenderer): + media_type = 'application/vnd.oai.openapi+json' + charset = None + format = 'openapi-json' + + def __init__(self): + assert coreapi, 'Using JSONOpenAPIRenderer, but `coreapi` is not installed.' + + def render(self, data, media_type=None, renderer_context=None): + structure = self.get_structure(data) + return json.dumps(structure, indent=4)