Skip to content

Commit 3e085f0

Browse files
committed
feat(openapi/operationId): Make camel-case
1 parent 609f708 commit 3e085f0

File tree

3 files changed

+53
-8
lines changed

3 files changed

+53
-8
lines changed

rest_framework/schemas/openapi.py

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

133133
method_mapping = {
134-
'get': 'Retrieve',
135-
'post': 'Create',
136-
'put': 'Update',
137-
'patch': 'PartialUpdate',
138-
'delete': 'Destroy',
134+
'get': 'retrieve',
135+
'post': 'create',
136+
'put': 'update',
137+
'patch': 'partialUpdate',
138+
'delete': 'destroy',
139139
}
140140

141141
def get_operation(self, path, method):
@@ -195,6 +195,12 @@ def get_components(self, path, method):
195195
content = self._map_serializer(serializer)
196196
return {component_name: content}
197197

198+
def _to_camel_case(self, snake_str):
199+
components = snake_str.split('_')
200+
# We capitalize the first letter of each component except the first one
201+
# with the 'title' method and join them together.
202+
return components[0] + ''.join(x.title() for x in components[1:])
203+
198204
def get_operation_id_base(self, path, method, action):
199205
"""
200206
Compute the base part for operation ID from the model, serializer or view name.
@@ -240,7 +246,7 @@ def get_operation_id(self, path, method):
240246
if is_list_view(path, method, self.view):
241247
action = 'list'
242248
elif method_name not in self.method_mapping:
243-
action = method_name
249+
action = self._to_camel_case(method_name)
244250
else:
245251
action = self.method_mapping[method.lower()]
246252

tests/schemas/test_openapi.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ def test_path_with_id_parameter(self):
158158

159159
operation = inspector.get_operation(path, method)
160160
assert operation == {
161-
'operationId': 'RetrieveDocStringExampleDetail',
161+
'operationId': 'retrieveDocStringExampleDetail',
162162
'description': 'A description of my GET operation.',
163163
'parameters': [{
164164
'description': '',
@@ -735,6 +735,23 @@ def test_duplicate_operation_id(self):
735735
print(str(w[-1].message))
736736
assert 'You have a duplicated operationId' in str(w[-1].message)
737737

738+
def test_operation_id_viewset(self):
739+
router = routers.SimpleRouter()
740+
router.register('account', views.ExampleViewSet, basename="account")
741+
urlpatterns = router.urls
742+
743+
generator = SchemaGenerator(patterns=urlpatterns)
744+
745+
request = create_request('/')
746+
schema = generator.get_schema(request=request)
747+
print(schema)
748+
assert schema['paths']['/account/']['get']['operationId'] == 'listExampleViewSets'
749+
assert schema['paths']['/account/']['post']['operationId'] == 'createExampleViewSet'
750+
assert schema['paths']['/account/{id}/']['get']['operationId'] == 'retrieveExampleViewSet'
751+
assert schema['paths']['/account/{id}/']['put']['operationId'] == 'updateExampleViewSet'
752+
assert schema['paths']['/account/{id}/']['patch']['operationId'] == 'partialUpdateExampleViewSet'
753+
assert schema['paths']['/account/{id}/']['delete']['operationId'] == 'destroyExampleViewSet'
754+
738755
def test_serializer_datefield(self):
739756
path = '/'
740757
method = 'GET'

tests/schemas/views.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from rest_framework.response import Response
1212
from rest_framework.schemas.openapi import AutoSchema
1313
from rest_framework.views import APIView
14-
from rest_framework.viewsets import GenericViewSet
14+
from rest_framework.viewsets import GenericViewSet, ViewSet
1515

1616

1717
class ExampleListView(APIView):
@@ -215,3 +215,25 @@ def get(self, *args, **kwargs):
215215

216216
serializer = self.get_serializer(data=now.date(), datetime=now)
217217
return Response(serializer.data)
218+
219+
220+
class ExampleViewSet(ViewSet):
221+
serializer_class = ExampleSerializerModel
222+
223+
def list(self, request):
224+
pass
225+
226+
def create(self, request):
227+
pass
228+
229+
def retrieve(self, request, pk=None):
230+
pass
231+
232+
def update(self, request, pk=None):
233+
pass
234+
235+
def partial_update(self, request, pk=None):
236+
pass
237+
238+
def destroy(self, request, pk=None):
239+
pass

0 commit comments

Comments
 (0)