django-json-api/django-rest-framework-json-api

OpenAPI Schema generation fails with generic APIViews

qianxuanyon opened this issue · 4 comments

Description of the Bug Report

class LogoutView(APIView):
     pass

Errors when accessing documents

AttributeError: 'LogoutView' object has no attribute 'get_serializer'

Is fault tolerance possible when the program has api in other formats

Checklist

  • Certain that this is a bug (if unsure or you have a question use discussions instead)
  • Code snippet or unit test added to reproduce bug

Could you provide the full stacktrace of the error? Thanks.

[01/Jun/2022 09:26:01] "GET /redoc/ HTTP/1.1" 200 625
Internal Server Error: /openapi
Traceback (most recent call last):
  File "/Users/lidaoran/opt/anaconda3/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/Users/lidaoran/opt/anaconda3/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/lidaoran/opt/anaconda3/lib/python3.9/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/Users/lidaoran/opt/anaconda3/lib/python3.9/site-packages/django/views/generic/base.py", line 70, in view
    return self.dispatch(request, *args, **kwargs)
  File "/Users/lidaoran/opt/anaconda3/lib/python3.9/site-packages/rest_framework/views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "/Users/lidaoran/opt/anaconda3/lib/python3.9/site-packages/rest_framework/schemas/views.py", line 48, in handle_exception
    return super().handle_exception(exc)
  File "/Users/lidaoran/opt/anaconda3/lib/python3.9/site-packages/rest_framework/views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/Users/lidaoran/opt/anaconda3/lib/python3.9/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
    raise exc
  File "/Users/lidaoran/opt/anaconda3/lib/python3.9/site-packages/rest_framework/views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "/Users/lidaoran/opt/anaconda3/lib/python3.9/site-packages/rest_framework/schemas/views.py", line 37, in get
    schema = self.schema_generator.get_schema(request, self.public)
  File "/Users/lidaoran/dev/django-rest-framework-json-api/rest_framework_json_api/schemas/openapi.py", line 266, in get_schema
    schema = super().get_schema(request, public)
  File "/Users/lidaoran/opt/anaconda3/lib/python3.9/site-packages/rest_framework/schemas/openapi.py", line 81, in get_schema
    operation = view.schema.get_operation(path, method)
  File "/Users/lidaoran/dev/django-rest-framework-json-api/rest_framework_json_api/schemas/openapi.py", line 429, in get_operation
    self._add_get_collection_response(operation)
  File "/Users/lidaoran/dev/django-rest-framework-json-api/rest_framework_json_api/schemas/openapi.py", line 494, in _add_get_collection_response
    "200": self._get_toplevel_200_response(operation, collection=True)
  File "/Users/lidaoran/dev/django-rest-framework-json-api/rest_framework_json_api/schemas/openapi.py", line 518, in _get_toplevel_200_response
    "items": self._get_reference(self.view.get_serializer()),
AttributeError: 'LogoutView' object has no attribute 'get_serializer'

This is my configuration

urls.py

urlpatterns = [
   path(
        "openapi",
        get_schema_view(
            title="Example API",
            description="API for all things …",
            version="1.0.0",
            generator_class=SchemaGenerator,
        ),
        name="openapi-schema",
    ),

   path('redoc/', TemplateView.as_view(
        template_name='redoc.html',
        extra_context={'schema_url':'openapi-schema'}
    ), name='redoc'),
    ]

This is the source code of the object reporting the error

class LogoutView(APIView):
    """
    Calls Django logout method and delete the Token object
    assigned to the current User object.

    Accepts/Returns nothing.
    """
    permission_classes = (AllowAny,)
    throttle_scope = 'dj_rest_auth'

    def get(self, request, *args, **kwargs):
        if getattr(settings, 'ACCOUNT_LOGOUT_ON_GET', False):
            response = self.logout(request)
        else:
            response = self.http_method_not_allowed(request, *args, **kwargs)

        return self.finalize_response(request, response, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.logout(request)

    def logout(self, request):
        try:
            request.user.auth_token.delete()
        except (AttributeError, ObjectDoesNotExist):
            pass

        if getattr(settings, 'REST_SESSION_LOGIN', True):
            django_logout(request)

        response = Response(
            {'detail': _('Successfully logged out.')},
            status=status.HTTP_200_OK,
        )


        return response

Thanks for the additional information. So this seems to be an issue with our openapi implementation. As far as I see does the DRF implementation skip views without serializers.

We need to go through our openapi.py and all view.get_serializer() call need to be changed to either self.get_request_serializer or self.get_response_serializer. If None is returned, that view will need to be ignored.

Any PR is welcome.

With version 7.1.0 we deprecated the OpenAPI schema support integrated in DJA following the decision in DRF which did the same. We encourage using drf-spectacular-json-api to generate OpenAPI schemas.

I am not sure whether drf-spectacular-json-api works with generic APIView, but best is to check it out and if not raise an issue there. As schema generation support is deprecated, in DJA we won't make any changes to the schema generation unless it is very critical. Therefore, closing this issue.

Let me know if there are any questions though about the decision or how to move forward.