Added schema descriptions

This commit is contained in:
Tom Christie 2016-10-05 15:37:25 +01:00
parent cd826ce422
commit 7e3a3a4081
3 changed files with 52 additions and 19 deletions

View File

@ -242,6 +242,14 @@ You could then either:
---
# Schemas as documentation
One common usage of API schemas is to use them to build documentation pages.
The schema generation in REST framework uses docstrings to automatically
---
# Alternate schema formats
In order to support an alternate schema format, you need to implement a custom renderer

View File

@ -1,3 +1,4 @@
import re
from collections import OrderedDict
from importlib import import_module
@ -15,6 +16,8 @@ from rest_framework.response import Response
from rest_framework.settings import api_settings
from rest_framework.views import APIView
header_regex = re.compile('^[a-zA-Z][0-9A-Za-z_]*:')
def as_query_fields(items):
"""
@ -53,8 +56,7 @@ def insert_into(target, keys, value):
def is_custom_action(action):
return action not in set([
'read', 'retrieve', 'list',
'create', 'update', 'partial_update', 'delete', 'destroy'
'retrieve', 'list', 'create', 'update', 'partial_update', 'destroy'
])
@ -171,17 +173,12 @@ class EndpointInspector(object):
class SchemaGenerator(object):
# Map methods onto 'actions' that are the names used in the link layout.
default_mapping = {
'get': 'read',
'get': 'retrieve',
'post': 'create',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy',
}
# Coerce the following viewset actions into different names.
coerce_actions = {
'retrieve': 'read',
'destroy': 'delete'
}
endpoint_inspector_cls = EndpointInspector
def __init__(self, title=None, url=None, patterns=None, urlconf=None):
@ -283,6 +280,8 @@ class SchemaGenerator(object):
else:
encoding = None
description = self.get_description(path, method, view)
if self.url and path.startswith('/'):
path = path[1:]
@ -290,9 +289,38 @@ class SchemaGenerator(object):
url=urlparse.urljoin(self.url, path),
action=method.lower(),
encoding=encoding,
fields=fields
fields=fields,
description=description
)
def get_description(self, path, method, view):
"""
Determine a link description.
This with either be the class docstring, or a specific section for it.
For views, use method names, eg `get:` to introduce a section.
For viewsets, use action names, eg `retrieve:` to introduce a section.
The section names will correspond to the methods on the class.
"""
view_description = view.get_view_description()
lines = [line.strip() for line in view_description.splitlines()]
current_section = ''
sections = {'': ''}
for line in lines:
if header_regex.match(line):
current_section, seperator, lead = line.partition(':')
sections[current_section] = lead.strip()
else:
sections[current_section] += line + '\n'
header = getattr(view, 'action', method.lower())
if header in sections:
return sections[header].strip()
return sections[''].strip()
def get_encoding(self, path, method, view):
"""
Return the 'encoding' parameter to use for a given endpoint.
@ -401,10 +429,7 @@ class SchemaGenerator(object):
"""
if hasattr(view, 'action'):
# Viewsets have explicitly named actions.
if view.action in self.coerce_actions:
action = self.coerce_actions[view.action]
else:
action = view.action
action = view.action
else:
# Views have no associated action, so we determine one from the method.
if is_list_view(path, method, view):

View File

@ -94,12 +94,12 @@ class TestRouterGeneratedSchema(TestCase):
action='get'
),
'custom_list_action_multiple_methods': {
'read': coreapi.Link(
'retrieve': coreapi.Link(
url='/example/custom_list_action_multiple_methods/',
action='get'
)
},
'read': coreapi.Link(
'retrieve': coreapi.Link(
url='/example/{pk}/',
action='get',
fields=[
@ -138,7 +138,7 @@ class TestRouterGeneratedSchema(TestCase):
coreapi.Field('b', required=False, location='form')
]
),
'read': coreapi.Link(
'retrieve': coreapi.Link(
url='/example/{pk}/',
action='get',
fields=[
@ -160,7 +160,7 @@ class TestRouterGeneratedSchema(TestCase):
action='get'
),
'custom_list_action_multiple_methods': {
'read': coreapi.Link(
'retrieve': coreapi.Link(
url='/example/custom_list_action_multiple_methods/',
action='get'
),
@ -189,7 +189,7 @@ class TestRouterGeneratedSchema(TestCase):
coreapi.Field('b', required=False, location='form')
]
),
'delete': coreapi.Link(
'destroy': coreapi.Link(
url='/example/{pk}/',
action='delete',
fields=[
@ -249,7 +249,7 @@ class TestSchemaGenerator(TestCase):
action='get',
fields=[]
),
'read': coreapi.Link(
'retrieve': coreapi.Link(
url='/example/{pk}/',
action='get',
fields=[