Skip to content

Commit 1bfdce9

Browse files
committed
feat(openapi/operationId): Make camel-case
1 parent 2a5c2f3 commit 1bfdce9

File tree

3 files changed

+69
-8
lines changed

3 files changed

+69
-8
lines changed

rest_framework/schemas/openapi.py

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

8383
method_mapping = {
84-
'get': 'Retrieve',
85-
'post': 'Create',
86-
'put': 'Update',
87-
'patch': 'PartialUpdate',
88-
'delete': 'Destroy',
84+
'get': 'retrieve',
85+
'post': 'create',
86+
'put': 'update',
87+
'patch': 'partialUpdate',
88+
'delete': 'destroy',
8989
}
9090

9191
def get_operation(self, path, method):
@@ -108,6 +108,12 @@ def get_operation(self, path, method):
108108

109109
return operation
110110

111+
def _to_camel_case(self, snake_str):
112+
components = snake_str.split('_')
113+
# We capitalize the first letter of each component except the first one
114+
# with the 'title' method and join them together.
115+
return components[0] + ''.join(x.title() for x in components[1:])
116+
111117
def _get_operation_id(self, path, method):
112118
"""
113119
Compute an operation ID from the model, serializer or view name.
@@ -116,7 +122,7 @@ def _get_operation_id(self, path, method):
116122
if is_list_view(path, method, self.view):
117123
action = 'list'
118124
elif method_name not in self.method_mapping:
119-
action = method_name
125+
action = self._to_camel_case(method_name)
120126
else:
121127
action = self.method_mapping[method.lower()]
122128

tests/schemas/test_openapi.py

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

157157
operation = inspector.get_operation(path, method)
158158
assert operation == {
159-
'operationId': 'RetrieveDocStringExampleDetail',
159+
'operationId': 'retrieveDocStringExampleDetail',
160160
'description': 'A description of my GET operation.',
161161
'parameters': [{
162162
'description': '',
@@ -592,6 +592,23 @@ def test_repeat_operation_ids(self):
592592
assert schema_str.count("newExample") == 1
593593
assert schema_str.count("oldExample") == 1
594594

595+
def test_operation_id_viewset(self):
596+
router = routers.SimpleRouter()
597+
router.register('account', views.ExampleViewSet, basename="account")
598+
urlpatterns = router.urls
599+
600+
generator = SchemaGenerator(patterns=urlpatterns)
601+
602+
request = create_request('/')
603+
schema = generator.get_schema(request=request)
604+
print(schema)
605+
assert schema['paths']['/account/']['get']['operationId'] == 'listExampleViewSets'
606+
assert schema['paths']['/account/']['post']['operationId'] == 'createExampleViewSet'
607+
assert schema['paths']['/account/{id}/']['get']['operationId'] == 'retrieveExampleViewSet'
608+
assert schema['paths']['/account/{id}/']['put']['operationId'] == 'updateExampleViewSet'
609+
assert schema['paths']['/account/{id}/']['patch']['operationId'] == 'partialUpdateExampleViewSet'
610+
assert schema['paths']['/account/{id}/']['delete']['operationId'] == 'destroyExampleViewSet'
611+
595612
def test_serializer_datefield(self):
596613
path = '/'
597614
method = 'GET'

tests/schemas/views.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44
DecimalValidator, MaxLengthValidator, MaxValueValidator,
55
MinLengthValidator, MinValueValidator, RegexValidator
66
)
7+
from django.db import models
78

89
from rest_framework import generics, permissions, serializers
910
from rest_framework.decorators import action
1011
from rest_framework.response import Response
1112
from rest_framework.views import APIView
12-
from rest_framework.viewsets import GenericViewSet
13+
from rest_framework.viewsets import GenericViewSet, ViewSet
1314

1415

1516
class ExampleListView(APIView):
@@ -137,3 +138,40 @@ def get(self, *args, **kwargs):
137138
url='http://localhost', uuid=uuid.uuid4(), ip4='127.0.0.1', ip6='::1',
138139
ip='192.168.1.1')
139140
return Response(serializer.data)
141+
142+
143+
# Serializer with model.
144+
class OpenAPIExample(models.Model):
145+
first_name = models.CharField(max_length=30)
146+
147+
148+
class ExampleSerializerModel(serializers.Serializer):
149+
date = serializers.DateField()
150+
datetime = serializers.DateTimeField()
151+
hstore = serializers.HStoreField()
152+
uuid_field = serializers.UUIDField(default=uuid.uuid4)
153+
154+
class Meta:
155+
model = OpenAPIExample
156+
157+
158+
class ExampleViewSet(ViewSet):
159+
serializer_class = ExampleSerializerModel
160+
161+
def list(self, request):
162+
pass
163+
164+
def create(self, request):
165+
pass
166+
167+
def retrieve(self, request, pk=None):
168+
pass
169+
170+
def update(self, request, pk=None):
171+
pass
172+
173+
def partial_update(self, request, pk=None):
174+
pass
175+
176+
def destroy(self, request, pk=None):
177+
pass

0 commit comments

Comments
 (0)