From 6522d4ae2058c6de39c9818d53cc5c45fec70762 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 4 Oct 2018 14:05:55 +0100 Subject: [PATCH] Add OpenAPIRenderer by default, and add schema docs. (#6233) * Add OpenAPIRenderer as a default for get_schema_view, and start adding schema docs * Add optional pyyaml * Updating schema docs --- docs/api-guide/schemas.md | 106 +++++++++++++----------- requirements/requirements-optionals.txt | 1 + rest_framework/schemas/views.py | 11 ++- 3 files changed, 62 insertions(+), 56 deletions(-) diff --git a/docs/api-guide/schemas.md b/docs/api-guide/schemas.md index b1b6ae63ee..8a66883783 100644 --- a/docs/api-guide/schemas.md +++ b/docs/api-guide/schemas.md @@ -10,12 +10,50 @@ API schemas are a useful tool that allow for a range of use cases, including generating reference documentation, or driving dynamic client libraries that can interact with your API. -## Install Core API +## Install Core API & PyYAML You'll need to install the `coreapi` package in order to add schema support -for REST framework. +for REST framework. You probably also want to install `pyyaml`, so that you +can render the schema into the commonly used YAML-based OpenAPI format. - pip install coreapi + pip install coreapi pyyaml + +## Quickstart + +There are two different ways you can serve a schema description for you API. + +### Generating a schema with the `generateschema` management command + +To generate a static API schema, use the `generateschema` management command. + +```shell +$ python manage.py generateschema > schema.yml +``` + +Once you've generated a schema in this way you can annotate it with any +additional information that cannot be automatically inferred by the schema +generator. + +You might want to check your API schema into version control and update it +with each new release, or serve the API schema from your site's static media. + +### Adding a view with `get_schema_view` + +To add a dynamically generated schema view to your API, use `get_schema_view`. + +```python +from rest_framework.schemas import get_schema_view + +schema_view = get_schema_view(title="Example API") + +urlpatterns = [ + url('^schema$', schema_view), + ... +] +``` + +See below [for more details](#the-get_schema_view-shortcut) on customizing a +dynamically generated schema view. ## Internal schema representation @@ -71,37 +109,18 @@ endpoint: In order to be presented in an HTTP response, the internal representation has to be rendered into the actual bytes that are used in the response. -[Core JSON][corejson] is designed as a canonical format for use with Core API. -REST framework includes a renderer class for handling this media type, which -is available as `renderers.CoreJSONRenderer`. - -### Alternate schema formats - -Other schema formats such as [Open API][open-api] ("Swagger"), -[JSON HyperSchema][json-hyperschema], or [API Blueprint][api-blueprint] can also -be supported by implementing a custom renderer class that handles converting a -`Document` instance into a bytestring representation. - -If there is a Core API codec package that supports encoding into the format you -want to use then implementing the renderer class can be done by using the codec. - -#### Example - -For example, the `openapi_codec` package provides support for encoding or decoding -to the Open API ("Swagger") format: - - from rest_framework import renderers - from openapi_codec import OpenAPICodec - - class SwaggerRenderer(renderers.BaseRenderer): - media_type = 'application/openapi+json' - format = 'swagger' +REST framework includes a few different renderers that you can use for +encoding the API schema. - def render(self, data, media_type=None, renderer_context=None): - codec = OpenAPICodec() - return codec.dump(data) +* `renderers.OpenAPIRenderer` - Renders into YAML-based [OpenAPI][openapi], the most widely used API schema format. +* `renderers.JSONOpenAPIRenderer` - Renders into JSON-based [OpenAPI][openapi]. +* `renderers.CoreJSONRenderer` - Renders into [Core JSON][corejson], a format designed for +use with the `coreapi` client library. +[Core JSON][corejson] is designed as a canonical format for use with Core API. +REST framework includes a renderer class for handling this media type, which +is available as `renderers.CoreJSONRenderer`. ## Schemas vs Hypermedia @@ -325,13 +344,12 @@ ROOT_URLCONF setting. May be used to pass the set of renderer classes that can be used to render the API root endpoint. from rest_framework.schemas import get_schema_view - from rest_framework.renderers import CoreJSONRenderer - from my_custom_package import APIBlueprintRenderer + from rest_framework.renderers import JSONOpenAPIRenderer schema_view = get_schema_view( title='Server Monitoring API', url='https://www.example.org/api/', - renderer_classes=[CoreJSONRenderer, APIBlueprintRenderer] + renderer_classes=[JSONOpenAPIRenderer] ) #### `patterns` @@ -364,7 +382,6 @@ Defaults to `settings.DEFAULT_AUTHENTICATION_CLASSES` May be used to specify the list of permission classes that will apply to the schema endpoint. Defaults to `settings.DEFAULT_PERMISSION_CLASSES` - ## Using an explicit schema view If you need a little more control than the `get_schema_view()` shortcut gives you, @@ -386,7 +403,7 @@ return the schema. generator = schemas.SchemaGenerator(title='Bookings API') @api_view() - @renderer_classes([renderers.CoreJSONRenderer]) + @renderer_classes([renderers.OpenAPIRenderer]) def schema_view(request): schema = generator.get_schema(request) return response.Response(schema) @@ -408,7 +425,7 @@ In order to present a schema with endpoints filtered by user permissions, you need to pass the `request` argument to the `get_schema()` method, like so: @api_view() - @renderer_classes([renderers.CoreJSONRenderer]) + @renderer_classes([renderers.OpenAPIRenderer]) def schema_view(request): generator = schemas.SchemaGenerator(title='Bookings API') return response.Response(generator.get_schema(request=request)) @@ -432,21 +449,10 @@ representation. ) @api_view() - @renderer_classes([renderers.CoreJSONRenderer]) + @renderer_classes([renderers.OpenAPIRenderer]) def schema_view(request): return response.Response(schema) -## Static schema file - -A final option is to write your API schema as a static file, using one -of the available formats, such as Core JSON or Open API. - -You could then either: - -* Write a schema definition as a static file, and [serve the static file directly][static-files]. -* Write a schema definition that is loaded using `Core API`, and then - rendered to one of many available formats, depending on the client request. - --- # Schemas as documentation @@ -535,7 +541,7 @@ Arguments: Returns a `coreapi.Document` instance that represents the API schema. @api_view - @renderer_classes([renderers.CoreJSONRenderer]) + @renderer_classes([renderers.OpenAPIRenderer]) def schema_view(request): generator = schemas.SchemaGenerator(title='Bookings API') return Response(generator.get_schema()) diff --git a/requirements/requirements-optionals.txt b/requirements/requirements-optionals.txt index 87cdb82da5..cd0f1f62bd 100644 --- a/requirements/requirements-optionals.txt +++ b/requirements/requirements-optionals.txt @@ -5,3 +5,4 @@ django-guardian==1.4.9 django-filter==1.1.0 coreapi==2.3.1 coreschema==0.0.4 +pyyaml diff --git a/rest_framework/schemas/views.py b/rest_framework/schemas/views.py index b13eadea9c..845b68ea6d 100644 --- a/rest_framework/schemas/views.py +++ b/rest_framework/schemas/views.py @@ -19,13 +19,12 @@ class SchemaView(APIView): def __init__(self, *args, **kwargs): super(SchemaView, self).__init__(*args, **kwargs) if self.renderer_classes is None: + self.renderer_classes = [ + renderers.OpenAPIRenderer, + renderers.CoreJSONRenderer + ] if renderers.BrowsableAPIRenderer in api_settings.DEFAULT_RENDERER_CLASSES: - self.renderer_classes = [ - renderers.CoreJSONRenderer, - renderers.BrowsableAPIRenderer, - ] - else: - self.renderer_classes = [renderers.CoreJSONRenderer] + self.renderer_classes += [renderers.BrowsableAPIRenderer] def get(self, request, *args, **kwargs): schema = self.schema_generator.get_schema(request, self.public)