class Login(generics.CreateAPIView): """ An endpoint to login a user. """ permission_classes = [] authentication_classes = [ CsrfExemptSessionAuthentication, BasicAuthentication ] serializer_class = LoginSerializer queryset = User.objects.all() schema = AutoSchema(operation_id_base='LoginUser', tags=['Auth']) def post(self, request, *args, **kwargs): email = request.data.get('email') password = request.data.get('password') user = authenticate(email=email, password=password) if user is not None: try: login(request, user) user_type = user.get_user_type() data = { 'status': 200, 'message': 'User authenticated', 'data': { 'id': user.id, 'user_type': user_type, }, } return Response(data=data, status=200) except Exception as e: return Response(data=AUTH_FAILED_RESPONSE, status=401) return Response(data=AUTH_FAILED_RESPONSE, status=401)
def test_path_with_id_parameter(self): path = '/example/{id}/' method = 'GET' view = create_view(views.DocStringExampleDetailView, method, create_request(path)) inspector = AutoSchema() inspector.view = view operation = inspector.get_operation(path, method) assert operation == { 'operationId': 'RetrieveDocStringExampleDetail', 'description': 'A description of my GET operation.', 'parameters': [{ 'description': '', 'in': 'path', 'name': 'id', 'required': True, 'schema': { 'type': 'string', }, }], 'responses': { '200': { 'description': '', 'content': { 'application/json': { 'schema': {}, }, }, }, }, }
def get_field_info(self, field): field_info = super().get_field_info(field) # Add extra validators using the OpenAPI schema generator validators = {} AutoSchema()._map_field_validators(field, validators) extra_validators = ['format', 'pattern'] for validator in extra_validators: if validators.get(validator, None): field_info[validator] = validators[validator] # Add additional data from serializer field_info['initial'] = field.initial field_info['field_name'] = field.field_name field_info['write_only'] = field.write_only return field_info # >> > import json # >> > from your_app.serializers import UserSerializer # >> > metadata_generator = APIMetadata() # >> > metadata = metadata_generator.get_serializer_info(UserSerializer()) # >> > with open('User.json', 'w') as json_file: # ... # json.dump(metadata, json_file, indent=2, sort_keys=True)
def test_renderer_mapping(self): """Test that view's renderers are mapped to OA media types""" path = '/{id}/' method = 'GET' class CustomBrowsableAPIRenderer(BrowsableAPIRenderer): media_type = 'image/jpeg' # that's a wild API renderer class TextRenderer(BaseRenderer): media_type = 'text/plain' format = 'text' class View(generics.CreateAPIView): serializer_class = views.ExampleSerializer renderer_classes = [ JSONRenderer, TextRenderer, BrowsableAPIRenderer, CustomBrowsableAPIRenderer ] view = create_view( View, method, create_request(path), ) inspector = AutoSchema() inspector.view = view responses = inspector.get_responses(path, method) # TODO this should be changed once the multiple response # schema support is there success_response = responses['200'] # Check that the API renderers aren't included, but custom renderers are assert set( success_response['content']) == {'application/json', 'text/plain'}
def test_empty_required_with_patch_method(self): path = '/' method = 'PATCH' class ItemSerializer(serializers.Serializer): read_only = serializers.CharField(read_only=True) write_only = serializers.CharField(write_only=True, required=False) class View(generics.GenericAPIView): serializer_class = ItemSerializer view = create_view( View, method, create_request(path) ) inspector = AutoSchema() inspector.view = view components = inspector.get_components(path, method) component = components['Item'] # there should be no empty 'required' property, see #6834 assert 'required' not in component for response in inspector.get_responses(path, method).values(): assert 'required' not in component
def test_response_body_nested_serializer(self): path = '/' method = 'POST' class NestedSerializer(serializers.Serializer): number = serializers.IntegerField() class Serializer(serializers.Serializer): text = serializers.CharField() nested = NestedSerializer() class View(generics.GenericAPIView): serializer_class = Serializer view = create_view( View, method, create_request(path), ) inspector = AutoSchema() inspector.view = view responses = inspector._get_responses(path, method) schema = responses['200']['content']['application/json']['schema'] assert sorted(schema['required']) == ['nested', 'text'] assert sorted(list(schema['properties'].keys())) == ['nested', 'text'] assert schema['properties']['nested']['type'] == 'object' assert list( schema['properties']['nested']['properties'].keys()) == ['number'] assert schema['properties']['nested']['required'] == ['number']
def test_path_without_parameters(self): path = '/example/' method = 'GET' view = create_view(views.DocStringExampleListView, method, create_request(path)) inspector = AutoSchema() inspector.view = view operation = inspector.get_operation(path, method) assert operation == { 'operationId': 'listDocStringExamples', 'description': 'A description of my GET operation.', 'parameters': [], 'responses': { '200': { 'description': '', 'content': { 'application/json': { 'schema': { 'type': 'array', 'items': {}, }, }, }, }, }, }
def test_list_field_mapping(self): inspector = AutoSchema() cases = [ (serializers.ListField(), { 'items': {}, 'type': 'array' }), (serializers.ListField(child=serializers.BooleanField()), { 'items': { 'type': 'boolean' }, 'type': 'array' }), (serializers.ListField(child=serializers.FloatField()), { 'items': { 'type': 'number' }, 'type': 'array' }), (serializers.ListField(child=serializers.CharField()), { 'items': { 'type': 'string' }, 'type': 'array' }), ] for field, mapping in cases: with self.subTest(field=field): assert inspector._map_field(field) == mapping
def test_response_body_generation(self): path = '/' method = 'POST' class ItemSerializer(serializers.Serializer): text = serializers.CharField() write_only = serializers.CharField(write_only=True) class View(generics.GenericAPIView): serializer_class = ItemSerializer view = create_view(View, method, create_request(path)) inspector = AutoSchema() inspector.view = view responses = inspector.get_responses(path, method) assert responses['201']['content']['application/json']['schema'][ '$ref'] == '#/components/schemas/Item' components = inspector.get_components(path, method) assert sorted(components['Item']['required']) == ['text', 'write_only'] assert sorted(list(components['Item']['properties'].keys())) == [ 'text', 'write_only' ] assert 'description' in responses['201']
class Tugasharian_list(generics.ListCreateAPIView): queryset = Ms_tugas_harian.objects.all() serializer_class = TugasHarianSerializer schema = AutoSchema( tags=['API Tugas Harian'], component_name='tgs_harian', operation_id_base='tgs_harian', )
class TaskSummary(generics.RetrieveAPIView): schema = AutoSchema( component_name="TaskSummary", operation_id_base="TaskSummary", ) queryset = models.Task.objects.all() serializer_class = serializers.TaskSummarySerializer permission_classes = (HasTaskAccess, )
class Absensi_Detail(generics.RetrieveUpdateAPIView): queryset = Absensi.objects.all() serializer_class = AbsensiSerializer schema = AutoSchema( tags=['API Daftar Absensi Pegawai Detail'], component_name='absensi_dtl', operation_id_base='absensi_dtl', )
class Tugasharian_Detail(generics.RetrieveUpdateAPIView): queryset = Ms_tugas_harian.objects.all() serializer_class = TugasHarianSerializer schema = AutoSchema( tags=['API Tugas Harian Detail'], component_name='tgs_harian_dtl', operation_id_base='tgs_harian_dtl', )
def test_lazy_string_field(self): class Serializer(serializers.Serializer): text = serializers.CharField(help_text=_('lazy string')) inspector = AutoSchema() data = inspector._map_serializer(Serializer()) assert isinstance(data['properties']['text']['description'], str), "description must be str"
def test_paginated_list_response_body_generation(self): """Test that pagination properties are added for a paginated list view.""" path = '/' method = 'GET' class Pagination(pagination.BasePagination): def get_paginated_response_schema(self, schema): return { 'type': 'object', 'item': schema, } class ItemSerializer(serializers.Serializer): text = serializers.CharField() class View(generics.GenericAPIView): serializer_class = ItemSerializer pagination_class = Pagination view = create_view( View, method, create_request(path), ) inspector = AutoSchema() inspector.view = view responses = inspector._get_responses(path, method) assert responses == { '200': { 'description': '', 'content': { 'application/json': { 'schema': { 'type': 'object', 'item': { 'type': 'array', 'items': { '$ref': '#/components/schemas/Item' }, }, }, }, }, }, } components = inspector.get_components(path, method) assert components == { 'Item': { 'type': 'object', 'properties': { 'text': { 'type': 'string', }, }, 'required': ['text'], } }
def test_serializer_validators(self): path = '/' method = 'GET' view = create_view( views.ExampleValidatedAPIView, method, create_request(path), ) inspector = AutoSchema() inspector.view = view responses = inspector._get_responses(path, method) response_schema = responses['200']['content']['application/json'][ 'schema'] properties = response_schema['items']['properties'] assert properties['integer']['type'] == 'integer' assert properties['integer']['maximum'] == 99 assert properties['integer']['minimum'] == -11 assert properties['string']['minLength'] == 2 assert properties['string']['maxLength'] == 10 assert properties['lst']['minItems'] == 2 assert properties['lst']['maxItems'] == 10 assert properties['regex']['pattern'] == r'[ABC]12{3}' assert properties['regex'][ 'description'] == 'must have an A, B, or C followed by 1222' assert properties['decimal1']['type'] == 'number' assert properties['decimal1']['multipleOf'] == .01 assert properties['decimal1']['maximum'] == 10000 assert properties['decimal1']['minimum'] == -10000 assert properties['decimal2']['type'] == 'number' assert properties['decimal2']['multipleOf'] == .0001 assert properties['email']['type'] == 'string' assert properties['email']['format'] == 'email' assert properties['email']['default'] == '*****@*****.**' assert properties['url']['type'] == 'string' assert properties['url']['nullable'] is True assert properties['url']['default'] == 'http://www.example.com' assert properties['uuid']['type'] == 'string' assert properties['uuid']['format'] == 'uuid' assert properties['ip4']['type'] == 'string' assert properties['ip4']['format'] == 'ipv4' assert properties['ip6']['type'] == 'string' assert properties['ip6']['format'] == 'ipv6' assert properties['ip']['type'] == 'string' assert 'format' not in properties['ip']
class Absensi_list(generics.ListCreateAPIView): queryset = Absensi.objects.all() serializer_class = AbsensiSerializer name = "Daftar Absensi" schema = AutoSchema( tags=['API Daftar Absensi Pegawai'], component_name='absensi_list', operation_id_base='absensi_list', )
class ExampleAutoSchemaDuplicate2(generics.GenericAPIView): serializer_class = ExampleSerializerModel schema = AutoSchema(component_name="Duplicate") def get(self, *args, **kwargs): from datetime import datetime now = datetime.now() serializer = self.get_serializer(data=now.date(), datetime=now) return Response(serializer.data)
class CommentViewSet(CreateModelMixin, GenericViewSet): schema = AutoSchema(tags=['comment']) throttle_classes = [UserRateThrottle] if not DEBUG else [] serializer_class = CommentSerializer queryset = Comment.objects.all() def create(self, request, *args, **kwargs): try: return super().create(request, *args, **kwargs) except RestFrameworkValidationError as e: return Response(e.detail, status.HTTP_400_BAD_REQUEST)
def test_boolean_default_field(self): class Serializer(serializers.Serializer): default_true = serializers.BooleanField(default=True) default_false = serializers.BooleanField(default=False) without_default = serializers.BooleanField() inspector = AutoSchema() data = inspector._map_serializer(Serializer()) assert data['properties']['default_true']['default'] is True, "default must be true" assert data['properties']['default_false']['default'] is False, "default must be false" assert 'default' not in data['properties']['without_default'], "default must not be defined"
def test_min_and_max_validators(self): inspector = AutoSchema() positive_cases = [ ({}, serializers.DecimalField( validators=[MinValueValidator(limit_value=1)], decimal_places=2, max_digits=5), { 'minimum': 1 }), ({}, serializers.DecimalField( validators=[MaxValueValidator(limit_value=1)], decimal_places=2, max_digits=5), { 'maximum': 1 }), ({ 'COERCE_DECIMAL_TO_STRING': False }, serializers.DecimalField( validators=[MinValueValidator(limit_value=Decimal('1'))], decimal_places=2, max_digits=5), { 'minimum': 1.0 }), ({ 'COERCE_DECIMAL_TO_STRING': False }, serializers.DecimalField( validators=[MaxValueValidator(limit_value=Decimal('1'))], decimal_places=2, max_digits=5), { 'maximum': 1.0 }), ({}, serializers.DecimalField( validators=[MinValueValidator(limit_value=Decimal('1'))], decimal_places=2, max_digits=5), {}), ({}, serializers.DecimalField( validators=[MaxValueValidator(limit_value=Decimal('1'))], decimal_places=2, max_digits=5), {}), ] for overriden_settings, field, mapping in positive_cases: with override_settings(REST_FRAMEWORK=overriden_settings): with self.subTest(field=field): schema = {} inspector.map_field_validators(field, schema) assert schema == mapping
class CreateReportFlag(generics.CreateAPIView): """Create 'removal suggestion' flags.""" serializer_class = serializers.FlagSerializer permission_classes = (permissions.IsAuthenticatedOrReadOnly, ) schema = AutoSchema(operation_id_base="ReportFlag") def post(self, request, *args, **kwargs): return super(CreateReportFlag, self).post(request, *args, **kwargs) def perform_create(self, serializer): perform_flag(self.request, serializer.validated_data['comment'])
def test_operation_id_custom_name(self): path = '/' method = 'GET' view = create_view( views.ExampleGenericAPIView, method, create_request(path), ) inspector = AutoSchema(operation_id_base='Ulysse') inspector.view = view operationId = inspector.get_operation_id(path, method) assert operationId == 'listUlysses'
class UserDetail(generics.RetrieveAPIView): """Detalhes do usuário.""" schema = AutoSchema(tags=["Usuários"]) authentication_classes = [SessionAuthentication, BasicAuthentication] permission_classes = [IsAuthenticated] queryset = User.objects.all() serializer_class = UserSerializer def dispatch(self, request, *args, **kwargs): logger.info(f"UserDetail {request.method} ({request.user.username})") return super().dispatch(request, *args, **kwargs)
def test_retrieve_response_body_generation(self): """ Test that a list of properties is returned for retrieve item views. Pagination properties should not be added as the view represents a single item. """ path = '/{id}/' method = 'GET' class Pagination(pagination.BasePagination): def get_paginated_response_schema(self, schema): return { 'type': 'object', 'item': schema, } class ItemSerializer(serializers.Serializer): text = serializers.CharField() class View(generics.GenericAPIView): serializer_class = ItemSerializer pagination_class = Pagination view = create_view( View, method, create_request(path), ) inspector = AutoSchema() inspector.view = view responses = inspector._get_responses(path, method) assert responses == { '200': { 'description': '', 'content': { 'application/json': { 'schema': { 'type': 'object', 'properties': { 'text': { 'type': 'string', }, }, 'required': ['text'], }, }, }, }, }
def test_operation_id_generation(self): path = '/' method = 'GET' view = create_view( views.ExampleGenericAPIView, method, create_request(path), ) inspector = AutoSchema() inspector.view = view operationId = inspector._get_operation_id(path, method) assert operationId == 'ListExamples'
def test_list_field_mapping(self): inspector = AutoSchema() cases = [ (serializers.ListField(), { 'items': {}, 'type': 'array' }), (serializers.ListField(child=serializers.BooleanField()), { 'items': { 'type': 'boolean' }, 'type': 'array' }), (serializers.ListField(child=serializers.FloatField()), { 'items': { 'type': 'number' }, 'type': 'array' }), (serializers.ListField(child=serializers.CharField()), { 'items': { 'type': 'string' }, 'type': 'array' }), (serializers.ListField(child=serializers.IntegerField( max_value=4294967295)), { 'items': { 'type': 'integer', 'maximum': 4294967295, 'format': 'int64' }, 'type': 'array' }), (serializers.ListField(child=serializers.ChoiceField( choices=[('a', 'Choice A'), ('b', 'Choice B')])), { 'items': { 'enum': ['a', 'b'] }, 'type': 'array' }), (serializers.IntegerField(min_value=2147483648), { 'type': 'integer', 'minimum': 2147483648, 'format': 'int64' }), ] for field, mapping in cases: with self.subTest(field=field): assert inspector._map_field(field) == mapping
class MembershipApprovalViewSet(ModelViewSet): permission_classes = (IsAuthenticated, ) schema = AutoSchema(tags=["Membership Applications"]) serializer_class = MembershipApprovalSerializer def get_queryset(self): if not self.request.user: queryset = MembershipApproval.objects.none() else: queryset = MembershipApproval.objects.filter( applicant=self.request.user.id) return queryset
def test_serializer_hstorefield(self): path = '/' method = 'GET' view = create_view( views.ExampleGenericAPIView, method, create_request(path), ) inspector = AutoSchema() inspector.view = view responses = inspector._get_responses(path, method) response_schema = responses['200']['content']['application/json']['schema'] properties = response_schema['items']['properties'] assert properties['hstore']['type'] == 'object'
def test_serializer_callable_default(self): path = '/' method = 'GET' view = create_view( views.ExampleGenericAPIView, method, create_request(path), ) inspector = AutoSchema() inspector.view = view responses = inspector._get_responses(path, method) response_schema = responses['200']['content']['application/json']['schema'] properties = response_schema['items']['properties'] assert 'default' not in properties['uuid_field']