Skip to content

Commit 9d91a27

Browse files
committed
Added OpenAPI Schema Generation.
1 parent d2d1888 commit 9d91a27

File tree

11 files changed

+738
-227
lines changed

11 files changed

+738
-227
lines changed

rest_framework/filters.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ def get_schema_fields(self, view):
4040
assert coreschema is not None, 'coreschema must be installed to use `get_schema_fields()`'
4141
return []
4242

43+
def get_schema_operation_parameters(self, view):
44+
return []
45+
4346

4447
class SearchFilter(BaseFilterBackend):
4548
# The URL query parameter used for the search.
@@ -159,6 +162,19 @@ def get_schema_fields(self, view):
159162
)
160163
]
161164

165+
def get_schema_operation_parameters(self, view):
166+
return [
167+
{
168+
'name': self.search_param,
169+
'required': False,
170+
'in': 'query',
171+
'description': force_text(self.search_description),
172+
'schema': {
173+
'type': 'string',
174+
},
175+
},
176+
]
177+
162178

163179
class OrderingFilter(BaseFilterBackend):
164180
# The URL query parameter used for the ordering.
@@ -290,6 +306,19 @@ def get_schema_fields(self, view):
290306
)
291307
]
292308

309+
def get_schema_operation_parameters(self, view):
310+
return [
311+
{
312+
'name': self.ordering_param,
313+
'required': False,
314+
'in': 'query',
315+
'description': force_text(self.ordering_description),
316+
'schema': {
317+
'type': 'string',
318+
},
319+
},
320+
]
321+
293322

294323
class DjangoObjectPermissionsFilter(BaseFilterBackend):
295324
"""
Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,32 @@
11
from django.core.management.base import BaseCommand
22

3-
from rest_framework.compat import coreapi
4-
from rest_framework.renderers import (
5-
CoreJSONRenderer, JSONOpenAPIRenderer, OpenAPIRenderer
6-
)
7-
from rest_framework.schemas.generators import SchemaGenerator
3+
from rest_framework.compat import yaml
4+
from rest_framework.schemas.generators import OpenAPISchemaGenerator
5+
from rest_framework.utils import json
86

97

108
class Command(BaseCommand):
119
help = "Generates configured API schema for project."
1210

1311
def add_arguments(self, parser):
14-
parser.add_argument('--title', dest="title", default=None, type=str)
12+
parser.add_argument('--title', dest="title", default='', type=str)
1513
parser.add_argument('--url', dest="url", default=None, type=str)
1614
parser.add_argument('--description', dest="description", default=None, type=str)
17-
parser.add_argument('--format', dest="format", choices=['openapi', 'openapi-json', 'corejson'], default='openapi', type=str)
15+
parser.add_argument('--format', dest="format", choices=['openapi', 'openapi-json'], default='openapi', type=str)
1816

1917
def handle(self, *args, **options):
20-
assert coreapi is not None, 'coreapi must be installed.'
21-
22-
generator = SchemaGenerator(
18+
generator = OpenAPISchemaGenerator(
2319
url=options['url'],
2420
title=options['title'],
2521
description=options['description']
2622
)
2723

2824
schema = generator.get_schema(request=None, public=True)
2925

30-
renderer = self.get_renderer(options['format'])
31-
output = renderer.render(schema, renderer_context={})
32-
self.stdout.write(output.decode('utf-8'))
33-
34-
def get_renderer(self, format):
35-
renderer_cls = {
36-
'corejson': CoreJSONRenderer,
37-
'openapi': OpenAPIRenderer,
38-
'openapi-json': JSONOpenAPIRenderer,
39-
}[format]
26+
# TODO: Handle via renderer? More options?
27+
if options['format'] == 'openapi':
28+
output = yaml.dump(schema, default_flow_style=False)
29+
else:
30+
output = json.dumps(schema, indent=2)
4031

41-
return renderer_cls()
32+
self.stdout.write(output)

rest_framework/pagination.py

Lines changed: 86 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ def get_schema_fields(self, view):
152152
assert coreapi is not None, 'coreapi must be installed to use `get_schema_fields()`'
153153
return []
154154

155+
def get_schema_operation_parameters(self, view):
156+
return []
157+
155158

156159
class PageNumberPagination(BasePagination):
157160
"""
@@ -305,6 +308,32 @@ def get_schema_fields(self, view):
305308
)
306309
return fields
307310

311+
def get_schema_operation_parameters(self, view):
312+
parameters = [
313+
{
314+
'name': self.page_query_param,
315+
'required': False,
316+
'in': 'query',
317+
'description': force_text(self.page_query_description),
318+
'schema': {
319+
'type': 'integer',
320+
},
321+
},
322+
]
323+
if self.page_size_query_param is not None:
324+
parameters.append(
325+
{
326+
'name': self.page_size_query_param,
327+
'required': False,
328+
'in': 'query',
329+
'description': force_text(self.page_size_query_description),
330+
'schema': {
331+
'type': 'integer',
332+
},
333+
},
334+
)
335+
return parameters
336+
308337

309338
class LimitOffsetPagination(BasePagination):
310339
"""
@@ -434,6 +463,15 @@ def to_html(self):
434463
context = self.get_html_context()
435464
return template.render(context)
436465

466+
def get_count(self, queryset):
467+
"""
468+
Determine an object count, supporting either querysets or regular lists.
469+
"""
470+
try:
471+
return queryset.count()
472+
except (AttributeError, TypeError):
473+
return len(queryset)
474+
437475
def get_schema_fields(self, view):
438476
assert coreapi is not None, 'coreapi must be installed to use `get_schema_fields()`'
439477
assert coreschema is not None, 'coreschema must be installed to use `get_schema_fields()`'
@@ -458,14 +496,28 @@ def get_schema_fields(self, view):
458496
)
459497
]
460498

461-
def get_count(self, queryset):
462-
"""
463-
Determine an object count, supporting either querysets or regular lists.
464-
"""
465-
try:
466-
return queryset.count()
467-
except (AttributeError, TypeError):
468-
return len(queryset)
499+
def get_schema_operation_parameters(self, view):
500+
parameters = [
501+
{
502+
'name': self.limit_query_param,
503+
'required': False,
504+
'in': 'query',
505+
'description': force_text(self.limit_query_description),
506+
'schema': {
507+
'type': 'integer',
508+
},
509+
},
510+
{
511+
'name': self.offset_query_param,
512+
'required': False,
513+
'in': 'query',
514+
'description': force_text(self.offset_query_description),
515+
'schema': {
516+
'type': 'integer',
517+
},
518+
},
519+
]
520+
return parameters
469521

470522

471523
class CursorPagination(BasePagination):
@@ -820,3 +872,29 @@ def get_schema_fields(self, view):
820872
)
821873
)
822874
return fields
875+
876+
def get_schema_operation_parameters(self, view):
877+
parameters = [
878+
{
879+
'name': self.cursor_query_param,
880+
'required': False,
881+
'in': 'query',
882+
'description': force_text(self.cursor_query_description),
883+
'schema': {
884+
'type': 'integer',
885+
},
886+
}
887+
]
888+
if self.page_size_query_param is not None:
889+
parameters.append(
890+
{
891+
'name': self.page_size_query_param,
892+
'required': False,
893+
'in': 'query',
894+
'description': force_text(self.page_size_query_description),
895+
'schema': {
896+
'type': 'integer',
897+
},
898+
}
899+
)
900+
return parameters

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy