django-rest-framework-json-api icon indicating copy to clipboard operation
django-rest-framework-json-api copied to clipboard

OpenAPI Schema generation fails with generic APIViews

Open qianxuanyon opened this issue 2 years ago • 3 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

  • [x] 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

qianxuanyon avatar Jun 01 '22 05:06 qianxuanyon

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

sliverc avatar Jun 01 '22 08:06 sliverc

[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

qianxuanyon avatar Jun 01 '22 09:06 qianxuanyon

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.

sliverc avatar Jun 29 '22 15:06 sliverc