Skip to content

Commit 3300936

Browse files
committed
feat(openapi/operationId): Make camel-case
1 parent 797518a commit 3300936

File tree

3 files changed

+54
-8
lines changed

3 files changed

+54
-8
lines changed

rest_framework/schemas/openapi.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,11 @@ def __init__(self, operation_id_base=None, tags=None):
113113
response_media_types = []
114114

115115
method_mapping = {
116-
'get': 'Retrieve',
117-
'post': 'Create',
118-
'put': 'Update',
119-
'patch': 'PartialUpdate',
120-
'delete': 'Destroy',
116+
'get': 'retrieve',
117+
'post': 'create',
118+
'put': 'update',
119+
'patch': 'partialUpdate',
120+
'delete': 'destroy',
121121
}
122122

123123
def get_operation(self, path, method):
@@ -140,6 +140,12 @@ def get_operation(self, path, method):
140140

141141
return operation
142142

143+
def _to_camel_case(self, snake_str):
144+
components = snake_str.split('_')
145+
# We capitalize the first letter of each component except the first one
146+
# with the 'title' method and join them together.
147+
return components[0] + ''.join(x.title() for x in components[1:])
148+
143149
def get_operation_id_base(self, path, method, action):
144150
"""
145151
Compute the base part for operation ID from the model, serializer or view name.
@@ -185,7 +191,7 @@ def get_operation_id(self, path, method):
185191
if is_list_view(path, method, self.view):
186192
action = 'list'
187193
elif method_name not in self.method_mapping:
188-
action = method_name
194+
action = self._to_camel_case(method_name)
189195
else:
190196
action = self.method_mapping[method.lower()]
191197

tests/schemas/test_openapi.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def test_path_with_id_parameter(self):
157157

158158
operation = inspector.get_operation(path, method)
159159
assert operation == {
160-
'operationId': 'RetrieveDocStringExampleDetail',
160+
'operationId': 'retrieveDocStringExampleDetail',
161161
'description': 'A description of my GET operation.',
162162
'parameters': [{
163163
'description': '',
@@ -678,6 +678,23 @@ def test_duplicate_operation_id(self):
678678
print(str(w[-1].message))
679679
assert 'You have a duplicated operationId' in str(w[-1].message)
680680

681+
def test_operation_id_viewset(self):
682+
router = routers.SimpleRouter()
683+
router.register('account', views.ExampleViewSet, basename="account")
684+
urlpatterns = router.urls
685+
686+
generator = SchemaGenerator(patterns=urlpatterns)
687+
688+
request = create_request('/')
689+
schema = generator.get_schema(request=request)
690+
print(schema)
691+
assert schema['paths']['/account/']['get']['operationId'] == 'listExampleViewSets'
692+
assert schema['paths']['/account/']['post']['operationId'] == 'createExampleViewSet'
693+
assert schema['paths']['/account/{id}/']['get']['operationId'] == 'retrieveExampleViewSet'
694+
assert schema['paths']['/account/{id}/']['put']['operationId'] == 'updateExampleViewSet'
695+
assert schema['paths']['/account/{id}/']['patch']['operationId'] == 'partialUpdateExampleViewSet'
696+
assert schema['paths']['/account/{id}/']['delete']['operationId'] == 'destroyExampleViewSet'
697+
681698
def test_serializer_datefield(self):
682699
path = '/'
683700
method = 'GET'
@@ -819,6 +836,7 @@ class ExampleStringTagsViewSet(views.ExampleGenericViewSet):
819836

820837
def test_auto_generated_apiview_tags(self):
821838
class RestaurantAPIView(views.ExampleGenericAPIView):
839+
schema = AutoSchema(operation_id_base="restaurant")
822840
pass
823841

824842
class BranchAPIView(views.ExampleGenericAPIView):

tests/schemas/views.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from rest_framework.decorators import action
1111
from rest_framework.response import Response
1212
from rest_framework.views import APIView
13-
from rest_framework.viewsets import GenericViewSet
13+
from rest_framework.viewsets import GenericViewSet, ViewSet
1414

1515

1616
class ExampleListView(APIView):
@@ -167,3 +167,25 @@ class ExampleOperationIdDuplicate2(generics.GenericAPIView):
167167

168168
def get(self, *args, **kwargs):
169169
pass
170+
171+
172+
class ExampleViewSet(ViewSet):
173+
serializer_class = ExampleSerializerModel
174+
175+
def list(self, request):
176+
pass
177+
178+
def create(self, request):
179+
pass
180+
181+
def retrieve(self, request, pk=None):
182+
pass
183+
184+
def update(self, request, pk=None):
185+
pass
186+
187+
def partial_update(self, request, pk=None):
188+
pass
189+
190+
def destroy(self, request, pk=None):
191+
pass

0 commit comments

Comments
 (0)