From bb17dbd6b1777b34451d6659a16f6593b9ed2513 Mon Sep 17 00:00:00 2001 From: phzhik Date: Tue, 21 May 2024 01:19:10 +0400 Subject: [PATCH] + API schema as Redoc + Django & DRF API exceptions in one format --- poizonstore/__init__.py | 1 + poizonstore/exceptions.py | 18 ++++++++++++++++++ poizonstore/settings.py | 6 +++++- poizonstore/urls.py | 7 +++++++ requirements.txt | 1 + 5 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 poizonstore/exceptions.py diff --git a/poizonstore/__init__.py b/poizonstore/__init__.py index fb989c4..66b4684 100644 --- a/poizonstore/__init__.py +++ b/poizonstore/__init__.py @@ -1,3 +1,4 @@ from .celery import app as celery_app +import poizonstore.schema __all__ = ('celery_app',) diff --git a/poizonstore/exceptions.py b/poizonstore/exceptions.py new file mode 100644 index 0000000..2baf5fa --- /dev/null +++ b/poizonstore/exceptions.py @@ -0,0 +1,18 @@ +from django.core.exceptions import ValidationError as DjangoValidationError + +from rest_framework.exceptions import ValidationError as DRFValidationError +from rest_framework.views import exception_handler as drf_exception_handler + + +def exception_handler(exc, context): + """ Handle Django ValidationError as an accepted exception """ + + if isinstance(exc, DjangoValidationError): + if hasattr(exc, 'message_dict'): + exc = DRFValidationError(detail={'error': exc.message_dict}) + elif hasattr(exc, 'message'): + exc = DRFValidationError(detail={'error': exc.message}) + elif hasattr(exc, 'messages'): + exc = DRFValidationError(detail={'error': exc.messages}) + + return drf_exception_handler(exc, context) diff --git a/poizonstore/settings.py b/poizonstore/settings.py index c11572c..c3d25f3 100644 --- a/poizonstore/settings.py +++ b/poizonstore/settings.py @@ -98,6 +98,7 @@ INSTALLED_APPS = [ 'debug_toolbar', 'django_filters', 'mptt', + 'drf_spectacular', 'account', 'store', @@ -185,7 +186,10 @@ REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ['rest_framework.authentication.TokenAuthentication'], 'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'], - 'DEFAULT_PAGINATION_CLASS': 'utils.drf.StandardResultsSetPagination' + 'DEFAULT_PAGINATION_CLASS': 'utils.drf.StandardResultsSetPagination', + + 'EXCEPTION_HANDLER': 'poizonstore.exceptions.exception_handler', + 'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema', } DJOSER = { diff --git a/poizonstore/urls.py b/poizonstore/urls.py index 2cf3d1f..b4d5f95 100644 --- a/poizonstore/urls.py +++ b/poizonstore/urls.py @@ -18,6 +18,7 @@ from django.conf import settings from django.conf.urls.static import static from django.contrib import admin from django.urls import path, include +from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView urlpatterns = [ @@ -28,3 +29,9 @@ urlpatterns = [ ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \ + static(settings.STATIC_URL) +# API schema +if settings.DEBUG: + urlpatterns += [ + path('api/schema/', SpectacularAPIView.as_view(), name='schema'), + path('api/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'), + ] diff --git a/requirements.txt b/requirements.txt index 17aff03..bbc517d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -24,6 +24,7 @@ tqdm==4.65.0 django-debug-toolbar==4.1.0 requests==2.31.0 python-dotenv==1.0.1 +drf-spectacular==0.27.2 # Logging sentry-sdk==1.34.0