OpenAPI: Warn user about duplicate operationIds. (#7207)

This commit is contained in:
Martin Desrumaux 2020-03-02 16:44:06 +01:00 committed by GitHub
parent 5b16a17242
commit 797518af6d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 77 additions and 0 deletions

View File

@ -34,6 +34,32 @@ class SchemaGenerator(BaseSchemaGenerator):
return info
def check_duplicate_operation_id(self, paths):
ids = {}
for route in paths:
for method in paths[route]:
if 'operationId' not in paths[route][method]:
continue
operation_id = paths[route][method]['operationId']
if operation_id in ids:
warnings.warn(
'You have a duplicated operationId in your OpenAPI schema: {operation_id}\n'
'\tRoute: {route1}, Method: {method1}\n'
'\tRoute: {route2}, Method: {method2}\n'
'\tAn operationId has to be unique accros your schema. Your schema may not work in other tools.'
.format(
route1=ids[operation_id]['route'],
method1=ids[operation_id]['method'],
route2=route,
method2=method,
operation_id=operation_id
)
)
ids[operation_id] = {
'route': route,
'method': method
}
def get_schema(self, request=None, public=False):
"""
Generate a OpenAPI schema.
@ -57,6 +83,8 @@ class SchemaGenerator(BaseSchemaGenerator):
paths.setdefault(path, {})
paths[path][method.lower()] = operation
self.check_duplicate_operation_id(paths)
# Compile final schema.
schema = {
'openapi': '3.0.2',

View File

@ -1,4 +1,5 @@
import uuid
import warnings
import pytest
from django.conf.urls import url
@ -659,6 +660,24 @@ class TestOperationIntrospection(TestCase):
assert schema_str.count("newExample") == 1
assert schema_str.count("oldExample") == 1
def test_duplicate_operation_id(self):
patterns = [
url(r'^duplicate1/?$', views.ExampleOperationIdDuplicate1.as_view()),
url(r'^duplicate2/?$', views.ExampleOperationIdDuplicate2.as_view()),
]
generator = SchemaGenerator(patterns=patterns)
request = create_request('/')
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
generator.get_schema(request=request)
assert len(w) == 1
assert issubclass(w[-1].category, UserWarning)
print(str(w[-1].message))
assert 'You have a duplicated operationId' in str(w[-1].message)
def test_serializer_datefield(self):
path = '/'
method = 'GET'

View File

@ -4,6 +4,7 @@ from django.core.validators import (
DecimalValidator, MaxLengthValidator, MaxValueValidator,
MinLengthValidator, MinValueValidator, RegexValidator
)
from django.db import models
from rest_framework import generics, permissions, serializers
from rest_framework.decorators import action
@ -137,3 +138,32 @@ class ExampleValidatedAPIView(generics.GenericAPIView):
url='http://localhost', uuid=uuid.uuid4(), ip4='127.0.0.1', ip6='::1',
ip='192.168.1.1')
return Response(serializer.data)
# Serializer with model.
class OpenAPIExample(models.Model):
first_name = models.CharField(max_length=30)
class ExampleSerializerModel(serializers.Serializer):
date = serializers.DateField()
datetime = serializers.DateTimeField()
hstore = serializers.HStoreField()
uuid_field = serializers.UUIDField(default=uuid.uuid4)
class Meta:
model = OpenAPIExample
class ExampleOperationIdDuplicate1(generics.GenericAPIView):
serializer_class = ExampleSerializerModel
def get(self, *args, **kwargs):
pass
class ExampleOperationIdDuplicate2(generics.GenericAPIView):
serializer_class = ExampleSerializerModel
def get(self, *args, **kwargs):
pass