Added 'get_schema_view()' shortcut

This commit is contained in:
Tom Christie 2016-10-05 13:46:39 +01:00
parent a8501f72b7
commit cd826ce422
3 changed files with 94 additions and 56 deletions

View File

@ -102,15 +102,20 @@ REST framework includes functionality for auto-generating a schema,
or allows you to specify one explicitly. There are a few different ways to or allows you to specify one explicitly. There are a few different ways to
add a schema to your API, depending on exactly what you need. add a schema to your API, depending on exactly what you need.
## Using DefaultRouter ## The get_schema_view shortcut
If you're using `DefaultRouter` then you can include an auto-generated schema, The simplest way to include a schema in your project is to use the
simply by adding a `schema_title` argument to the router. `get_schema_view()` function.
router = DefaultRouter(schema_title='Server Monitoring API') schema_view = get_schema_view(title="Server Monitoring API")
The schema will be included at the root URL, `/`, and presented to clients urlpatterns = [
that include the Core JSON media type in their `Accept` header. url('^$', schema_view),
...
]
Once the view has been added, you'll be able to make API requests to retrieve
the auto-generated schema definition.
$ http http://127.0.0.1:8000/ Accept:application/vnd.coreapi+json $ http http://127.0.0.1:8000/ Accept:application/vnd.coreapi+json
HTTP/1.0 200 OK HTTP/1.0 200 OK
@ -125,48 +130,43 @@ that include the Core JSON media type in their `Accept` header.
... ...
} }
This is a great zero-configuration option for when you want to get up and The arguments to `get_schema_view()` are:
running really quickly.
The other available options to `DefaultRouter` are: #### `title`
#### schema_renderers May be used to provide a descriptive title for the schema definition.
May be used to pass the set of renderer classes that can be used to render schema output. #### `url`
May be used to pass a canonical URL for the schema.
schema_view = get_schema_view(
title='Server Monitoring API',
url='https://www.example.org/api/'
)
#### `renderer_classes`
May be used to pass the set of renderer classes that can be used to render the API root endpoint.
from rest_framework.renderers import CoreJSONRenderer from rest_framework.renderers import CoreJSONRenderer
from my_custom_package import APIBlueprintRenderer from my_custom_package import APIBlueprintRenderer
router = DefaultRouter(schema_title='Server Monitoring API', schema_renderers=[ schema_view = get_schema_view(
CoreJSONRenderer, APIBlueprintRenderer title='Server Monitoring API',
]) url='https://www.example.org/api/',
renderer_classes=[CoreJSONRenderer, APIBlueprintRenderer]
#### schema_url
May be used to pass the root URL for the schema. This can either be used to ensure that
the schema URLs include a canonical hostname and schema, or to ensure that all the
schema URLs include a path prefix.
router = DefaultRouter(
schema_title='Server Monitoring API',
schema_url='https://www.example.org/api/'
) )
If you want more flexibility over the schema output then you'll need to consider ## Using an explicit schema view
using `SchemaGenerator` instead.
#### root_renderers If you need a little more control than the `get_schema_view()` shortcut gives you,
then you can use the `SchemaGenerator` class directly to auto-generate the
May be used to pass the set of renderer classes that can be used to render the API root endpoint. `Document` instance, and to return that from a view.
## Using SchemaGenerator
The most common way to add a schema to your API is to use the `SchemaGenerator`
class to auto-generate the `Document` instance, and to return that from a view.
This option gives you the flexibility of setting up the schema endpoint This option gives you the flexibility of setting up the schema endpoint
with whatever behavior you want. For example, you can apply different with whatever behaviour you want. For example, you can apply different
permission, throttling or authentication policies to the schema endpoint. permission, throttling, or authentication policies to the schema endpoint.
Here's an example of using `SchemaGenerator` together with a view to Here's an example of using `SchemaGenerator` together with a view to
return the schema. return the schema.
@ -176,12 +176,13 @@ return the schema.
from rest_framework.decorators import api_view, renderer_classes from rest_framework.decorators import api_view, renderer_classes
from rest_framework import renderers, response, schemas from rest_framework import renderers, response, schemas
generator = schemas.SchemaGenerator(title='Bookings API')
@api_view() @api_view()
@renderer_classes([renderers.CoreJSONRenderer]) @renderer_classes([renderers.CoreJSONRenderer])
def schema_view(request): def schema_view(request):
generator = schemas.SchemaGenerator(title='Bookings API') schema = generator.get_schema(request)
return response.Response(generator.get_schema()) return response.Response(schema)
**urls.py:** **urls.py:**

View File

@ -33,10 +33,17 @@ API schema.
$ pip install coreapi $ pip install coreapi
We can now include a schema for our API, by adding a `schema_title` argument to We can now include a schema for our API, by including an autogenerated schema
the router instantiation. view in our URL configuration.
router = DefaultRouter(schema_title='Pastebin API') from rest_framework.schemas import get_schema_view
schema_view = get_schema_view(title='Pastebin API')
urlpatterns = [
url('^schema/$', schema_view),
...
]
If you visit the API root endpoint in a browser you should now see `corejson` If you visit the API root endpoint in a browser you should now see `corejson`
representation become available as an option. representation become available as an option.
@ -46,7 +53,7 @@ representation become available as an option.
We can also request the schema from the command line, by specifying the desired We can also request the schema from the command line, by specifying the desired
content type in the `Accept` header. content type in the `Accept` header.
$ http http://127.0.0.1:8000/ Accept:application/vnd.coreapi+json $ http http://127.0.0.1:8000/schema/ Accept:application/vnd.coreapi+json
HTTP/1.0 200 OK HTTP/1.0 200 OK
Allow: GET, HEAD, OPTIONS Allow: GET, HEAD, OPTIONS
Content-Type: application/vnd.coreapi+json Content-Type: application/vnd.coreapi+json
@ -91,8 +98,8 @@ Now check that it is available on the command line...
First we'll load the API schema using the command line client. First we'll load the API schema using the command line client.
$ coreapi get http://127.0.0.1:8000/ $ coreapi get http://127.0.0.1:8000/schema/
<Pastebin API "http://127.0.0.1:8000/"> <Pastebin API "http://127.0.0.1:8000/schema/">
snippets: { snippets: {
highlight(pk) highlight(pk)
list() list()
@ -150,7 +157,7 @@ Now if we fetch the schema again, we should be able to see the full
set of available interactions. set of available interactions.
$ coreapi reload $ coreapi reload
Pastebin API "http://127.0.0.1:8000/"> Pastebin API "http://127.0.0.1:8000/schema/">
snippets: { snippets: {
create(code, [title], [linenos], [language], [style]) create(code, [title], [linenos], [language], [style])
destroy(pk) destroy(pk)

View File

@ -6,11 +6,13 @@ from django.contrib.admindocs.views import simplify_regex
from django.utils import six from django.utils import six
from django.utils.encoding import force_text from django.utils.encoding import force_text
from rest_framework import exceptions, serializers from rest_framework import exceptions, renderers, serializers
from rest_framework.compat import ( from rest_framework.compat import (
RegexURLPattern, RegexURLResolver, coreapi, uritemplate, urlparse RegexURLPattern, RegexURLResolver, coreapi, uritemplate, urlparse
) )
from rest_framework.request import clone_request from rest_framework.request import clone_request
from rest_framework.response import Response
from rest_framework.settings import api_settings
from rest_framework.views import APIView from rest_framework.views import APIView
@ -92,15 +94,14 @@ class EndpointInspector(object):
if patterns is None: if patterns is None:
if urlconf is None: if urlconf is None:
# Use the default Django URL conf # Use the default Django URL conf
urls = import_module(settings.ROOT_URLCONF) urlconf = settings.ROOT_URLCONF
patterns = urls.urlpatterns
# Load the given URLconf module
if isinstance(urlconf, six.string_types):
urls = import_module(urlconf)
else: else:
# Load the given URLconf module urls = urlconf
if isinstance(urlconf, six.string_types): patterns = urls.urlpatterns
urls = import_module(urlconf)
else:
urls = urlconf
patterns = urls.urlpatterns
self.patterns = patterns self.patterns = patterns
@ -189,7 +190,8 @@ class SchemaGenerator(object):
if url and not url.endswith('/'): if url and not url.endswith('/'):
url += '/' url += '/'
self.endpoint_inspector = self.endpoint_inspector_cls(patterns, urlconf) self.patterns = patterns
self.urlconf = urlconf
self.title = title self.title = title
self.url = url self.url = url
self.endpoints = None self.endpoints = None
@ -199,7 +201,8 @@ class SchemaGenerator(object):
Generate a `coreapi.Document` representing the API schema. Generate a `coreapi.Document` representing the API schema.
""" """
if self.endpoints is None: if self.endpoints is None:
self.endpoints = self.endpoint_inspector.get_api_endpoints() inspector = self.endpoint_inspector_cls(self.patterns, self.urlconf)
self.endpoints = inspector.get_api_endpoints()
links = self.get_links(request) links = self.get_links(request)
if not links: if not links:
@ -425,3 +428,30 @@ class SchemaGenerator(object):
# Default action, eg "/users/", "/users/{pk}/" # Default action, eg "/users/", "/users/{pk}/"
return named_path_components + [action] return named_path_components + [action]
def get_schema_view(title=None, url=None, renderer_classes=None):
"""
Return a schema view.
"""
generator = SchemaGenerator(title=title, url=url)
if renderer_classes is None:
if renderers.BrowsableAPIRenderer in api_settings.DEFAULT_RENDERER_CLASSES:
rclasses = [renderers.CoreJSONRenderer, renderers.BrowsableAPIRenderer]
else:
rclasses = [renderers.CoreJSONRenderer]
else:
rclasses = renderer_classes
class SchemaView(APIView):
_ignore_model_permissions = True
exclude_from_schema = True
renderer_classes = rclasses
def get(self, request, *args, **kwargs):
schema = generator.get_schema(request)
if schema is None:
raise exceptions.PermissionDenied()
return Response(schema)
return SchemaView.as_view()