Skip to content

Commit 70e6122

Browse files
author
Andrew Guenther
committed
Applying the fix for paginated responses from pull encode#7303
1 parent 0323d6f commit 70e6122

File tree

2 files changed

+67
-32
lines changed

2 files changed

+67
-32
lines changed

rest_framework/schemas/openapi.py

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ def get_components(self, path, method):
189189
Return components with their properties from the serializer.
190190
"""
191191

192+
components = {}
193+
192194
if method.lower() == 'delete':
193195
return {}
194196

@@ -197,10 +199,28 @@ def get_components(self, path, method):
197199
if not isinstance(serializer, serializers.Serializer):
198200
return {}
199201

200-
component_name = self.get_component_name(serializer)
202+
item_component_name = self.get_component_name(serializer)
203+
item_schema = self.map_serializer(serializer)
204+
components[item_component_name] = item_schema
205+
206+
response_component_name = self._get_response_component_name(
207+
self.get_operation_id(path, method)
208+
)
209+
210+
if is_list_view(path, method, self.view):
211+
response_component_schema = {
212+
'type': 'array',
213+
'items': self._get_serializer_reference(serializer),
214+
}
215+
paginator = self.get_paginator()
216+
if paginator:
217+
response_component_schema = paginator.get_paginated_response_schema(response_component_schema)
218+
else:
219+
response_component_schema = self._get_serializer_reference(serializer)
220+
221+
components[response_component_name] = response_component_schema
201222

202-
content = self.map_serializer(serializer)
203-
return {component_name: content}
223+
return components
204224

205225
def _to_camel_case(self, snake_str):
206226
components = snake_str.split('_')
@@ -615,9 +635,17 @@ def get_serializer(self, path, method):
615635
.format(view.__class__.__name__, method, path))
616636
return None
617637

618-
def _get_reference(self, serializer):
638+
def _get_serializer_reference(self, serializer):
619639
return {'$ref': '#/components/schemas/{}'.format(self.get_component_name(serializer))}
620640

641+
@staticmethod
642+
def _get_response_component_name(operation_id):
643+
operation_id = operation_id[0].upper() + operation_id[1:]
644+
return operation_id + 'Response'
645+
646+
def _get_response_reference(self, operation_id):
647+
return {'$ref': '#/components/schemas/{0}'.format(self._get_response_component_name(operation_id))}
648+
621649
def get_request_body(self, path, method):
622650
if method not in ('PUT', 'PATCH', 'POST'):
623651
return {}
@@ -629,7 +657,7 @@ def get_request_body(self, path, method):
629657
if not isinstance(serializer, serializers.Serializer):
630658
item_schema = {}
631659
else:
632-
item_schema = self._get_reference(serializer)
660+
item_schema = self._get_serializer_reference(serializer)
633661

634662
return {
635663
'content': {
@@ -651,20 +679,17 @@ def get_responses(self, path, method):
651679
serializer = self.get_serializer(path, method)
652680

653681
if not isinstance(serializer, serializers.Serializer):
654-
item_schema = {}
655-
else:
656-
item_schema = self._get_reference(serializer)
657-
658-
if is_list_view(path, method, self.view):
659-
response_schema = {
660-
'type': 'array',
661-
'items': item_schema,
662-
}
663-
paginator = self.get_paginator()
664-
if paginator:
665-
response_schema = paginator.get_paginated_response_schema(response_schema)
682+
if is_list_view(path, method, self.view):
683+
response_schema = {
684+
'type': 'array',
685+
'items': {}
686+
}
687+
else:
688+
response_schema = {}
666689
else:
667-
response_schema = item_schema
690+
response_schema = self._get_response_reference(
691+
self.get_operation_id(path, method)
692+
)
668693
status_code = '201' if method == 'POST' else '200'
669694
return {
670695
status_code: {

tests/schemas/test_openapi.py

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,8 @@ class View(generics.GenericAPIView):
311311
inspector.view = view
312312

313313
responses = inspector.get_responses(path, method)
314-
assert responses['201']['content']['application/json']['schema']['$ref'] == '#/components/schemas/Item'
314+
assert responses['201']['content']['application/json']['schema']['$ref'] == \
315+
'#/components/schemas/CreateItemResponse'
315316

316317
components = inspector.get_components(path, method)
317318
assert sorted(components['Item']['required']) == ['text', 'write_only']
@@ -341,7 +342,7 @@ class View(generics.GenericAPIView):
341342
inspector.view = view
342343

343344
responses = inspector.get_responses(path, method)
344-
assert responses['201']['content']['application/json']['schema']['$ref'] == '#/components/schemas/Item'
345+
assert responses['201']['content']['application/json']['schema']['$ref'] == '#/components/schemas/CreateItemResponse'
345346
components = inspector.get_components(path, method)
346347
assert components['Item']
347348

@@ -378,17 +379,20 @@ class View(generics.GenericAPIView):
378379
'content': {
379380
'application/json': {
380381
'schema': {
381-
'type': 'array',
382-
'items': {
383-
'$ref': '#/components/schemas/Item'
384-
},
382+
'$ref': '#/components/schemas/ListItemsResponse'
385383
},
386384
},
387385
},
388386
},
389387
}
390388
components = inspector.get_components(path, method)
391389
assert components == {
390+
'ListItemsResponse': {
391+
'type': 'array',
392+
'items': {
393+
'$ref': '#/components/schemas/Item',
394+
},
395+
},
392396
'Item': {
393397
'type': 'object',
394398
'properties': {
@@ -434,20 +438,23 @@ class View(generics.GenericAPIView):
434438
'content': {
435439
'application/json': {
436440
'schema': {
437-
'type': 'object',
438-
'item': {
439-
'type': 'array',
440-
'items': {
441-
'$ref': '#/components/schemas/Item'
442-
},
443-
},
441+
'$ref': '#/components/schemas/ListItemsResponse'
444442
},
445443
},
446444
},
447445
},
448446
}
449447
components = inspector.get_components(path, method)
450448
assert components == {
449+
'ListItemsResponse': {
450+
'type': 'object',
451+
'item': {
452+
'type': 'array',
453+
'items': {
454+
'$ref': '#/components/schemas/Item',
455+
},
456+
},
457+
},
451458
'Item': {
452459
'type': 'object',
453460
'properties': {
@@ -611,7 +618,7 @@ class View(generics.GenericAPIView):
611618
'content': {
612619
'application/json': {
613620
'schema': {
614-
'$ref': '#/components/schemas/Item'
621+
'$ref': '#/components/schemas/RetrieveItemResponse'
615622
},
616623
},
617624
},
@@ -620,6 +627,9 @@ class View(generics.GenericAPIView):
620627

621628
components = inspector.get_components(path, method)
622629
assert components == {
630+
'RetrieveItemResponse': {
631+
'$ref': '#/components/schemas/Item'
632+
},
623633
'Item': {
624634
'type': 'object',
625635
'properties': {

0 commit comments

Comments
 (0)