Skip to content

Commit 1c0a430

Browse files
Lucidiotcarltongibson
authored andcommitted
Add operationId on OpenAPI operations (#6549)
1 parent 61c0c8f commit 1c0a430

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

rest_framework/schemas/inspectors.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,10 +511,19 @@ def __get__(self, instance, owner):
511511
class OpenAPIAutoSchema(ViewInspector):
512512

513513
content_types = ['application/json']
514+
method_mapping = {
515+
'get': 'Retrieve',
516+
'post': 'Create',
517+
'put': 'Update',
518+
'patch': 'PartialUpdate',
519+
'delete': 'Destroy',
520+
}
514521

515522
def get_operation(self, path, method):
516523
operation = {}
517524

525+
operation['operationId'] = self._get_operation_id(path, method)
526+
518527
parameters = []
519528
parameters += self._get_path_parameters(path, method)
520529
parameters += self._get_pagination_parameters(path, method)
@@ -528,6 +537,45 @@ def get_operation(self, path, method):
528537

529538
return operation
530539

540+
def _get_operation_id(self, path, method):
541+
"""
542+
Compute an operation ID from the model, serializer or view name.
543+
"""
544+
# TODO: Allow an attribute/method on the view to change that ID?
545+
# Avoid cyclic imports
546+
from rest_framework.generics import GenericAPIView
547+
548+
if is_list_view(path, method, self.view):
549+
action = 'List'
550+
else:
551+
action = self.method_mapping[method.lower()]
552+
553+
# Try to deduce the ID from the view's model
554+
model = getattr(getattr(self.view, 'queryset', None), 'model', None)
555+
if model is not None:
556+
name = model.__name__
557+
558+
# Try with the serializer class name
559+
elif isinstance(self.view, GenericAPIView):
560+
name = self.view.get_serializer_class().__name__
561+
if name.endswith('Serializer'):
562+
name = name[:-10]
563+
564+
# Fallback to the view name
565+
else:
566+
name = self.view.__class__.__name__
567+
if name.endswith('APIView'):
568+
name = name[:-7]
569+
elif name.endswith('View'):
570+
name = name[:-4]
571+
if name.endswith(action): # ListView, UpdateAPIView, ThingDelete ...
572+
name = name[:-len(action)]
573+
574+
if action == 'List' and not name.endswith('s'): # ListThings instead of ListThing
575+
name += 's'
576+
577+
return action + name
578+
531579
def _get_path_parameters(self, path, method):
532580
"""
533581
Return a list of parameters from templated path variables.

tests/schemas/test_openapi.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def test_path_without_parameters(self):
5757

5858
operation = inspector.get_operation(path, method)
5959
assert operation == {
60+
'operationId': 'ListExamples',
6061
'parameters': [],
6162
'responses': {'200': {'content': {'application/json': {}}}},
6263
}

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