axnsan12 / drf-yasg

Automated generation of real Swagger/OpenAPI 2.0 schemas from Django REST Framework code.
https://drf-yasg.readthedocs.io/en/stable/
Other
3.42k stars 439 forks source link

Cache feature breaks when using the Redis cache backend #168

Closed thomasjiangcy closed 6 years ago

thomasjiangcy commented 6 years ago

I followed the docs to set up drf-yasg but i kept getting this error. I even tried removing all my paths to leave only the schema paths and I'm still getting the error.

Here are my deps:

celery[redis]==4.2.1
channels==2.1.2
channels_redis==2.2.1
django[argon2]==2.0.7
django-cors-headers==2.2.0
django-debug-toolbar==1.9.1
django-filter==2.0.0
django-redis==4.9.0
djangorestframework==3.8.2
djangorestframework_simplejwt==3.2.3
drf-yasg[validation]==1.9.1
gunicorn==19.9.0
Markdown==2.6.11
pika==0.12.0
psycopg2==2.7.5
Pygments==2.2.0
rethinkdb==2.3.0.post6
uvicorn==0.2.17

And here is the error log:

Environment:

Request Method: GET
Request URL: http://localhost/docs

Django Version: 2.0.7
Python Version: 3.6.5
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'channels',
 'django_filters',
 'drf_yasg',
 'rest_framework',
 'windspeed.taskapp.celery.CeleryConfig',
 'windspeed.common.apps.CommonConfig',
 'windspeed.accounts.apps.AccountsConfig',
 'windspeed.authentication.apps.AuthenticationConfig',
 'debug_toolbar']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'debug_toolbar.middleware.DebugToolbarMiddleware']

Traceback:

File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
  35.             response = get_response(request)

File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  158.                 response = self.process_exception_by_middleware(e, request)

File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  156.                 response = response.render()

File "/usr/local/lib/python3.6/site-packages/django/template/response.py" in render
  108.                 newretval = post_callback(retval)

File "/usr/local/lib/python3.6/site-packages/django/utils/decorators.py" in callback
  156.                             return middleware.process_response(request, response)

File "/usr/local/lib/python3.6/site-packages/django/middleware/cache.py" in process_response
  102.                     lambda r: self.cache.set(cache_key, r, timeout)

File "/usr/local/lib/python3.6/site-packages/django/template/response.py" in add_post_render_callback
  93.             callback(self)

File "/usr/local/lib/python3.6/site-packages/django/middleware/cache.py" in <lambda>
  102.                     lambda r: self.cache.set(cache_key, r, timeout)

File "/usr/local/lib/python3.6/site-packages/debug_toolbar/panels/cache.py" in wrapped
  33.         value = method(self, *args, **kwargs)

File "/usr/local/lib/python3.6/site-packages/debug_toolbar/panels/cache.py" in set
  79.         return self.cache.set(*args, **kwargs)

File "/usr/local/lib/python3.6/site-packages/django_redis/cache.py" in _decorator
  32.             return method(self, *args, **kwargs)

File "/usr/local/lib/python3.6/site-packages/django_redis/cache.py" in set
  67.         return self.client.set(*args, **kwargs)

File "/usr/local/lib/python3.6/site-packages/django_redis/client/default.py" in set
  114.         nvalue = self.encode(value)

File "/usr/local/lib/python3.6/site-packages/django_redis/client/default.py" in encode
  326.             value = self._serializer.dumps(value)

File "/usr/local/lib/python3.6/site-packages/django_redis/serializers/json.py" in dumps
  14.         return json.dumps(value, cls=DjangoJSONEncoder).encode()

File "/usr/local/lib/python3.6/json/__init__.py" in dumps
  238.         **kw).encode(obj)

File "/usr/local/lib/python3.6/json/encoder.py" in encode
  199.         chunks = self.iterencode(o, _one_shot=True)

File "/usr/local/lib/python3.6/json/encoder.py" in iterencode
  257.         return _iterencode(o, 0)

File "/usr/local/lib/python3.6/site-packages/django/core/serializers/json.py" in default
  104.             return super().default(o)

File "/usr/local/lib/python3.6/json/encoder.py" in default
  180.                         o.__class__.__name__)

Exception Type: TypeError at /docs
Exception Value: Object of type 'Response' is not JSON serializable

Would appreciate any help! :)

axnsan12 commented 6 years ago

Uhhh...

This seems to be caused by your use of Redis as a cache backend. Disabling caching for the drf-yasg view or setting it up to use the in-memory cache should fix it temporarily.

thomasjiangcy commented 6 years ago

I found a workaround which was to set cache_timeout=0 to disable to cache but not sure if this is an intended behavior

thomasjiangcy commented 6 years ago

@axnsan12 Ah yes ok :)

axnsan12 commented 6 years ago

Alright so I'm starting to think this is caused by the usage of the JSON serializer in django-redis as opposed to the default pickle mode. As far as I can tell this won't work with any DRF views that return Response objects, which includes our case here.

I'd say setting up a separate cache location using a different backend for the drf-yasg view would be your best bet here.