error-handling: add global exception handling, guard Bazaar API calls
This commit is contained in:
31
config/exceptions.py
Normal file
31
config/exceptions.py
Normal file
@@ -0,0 +1,31 @@
|
||||
"""
|
||||
هندلرِ سفارشیِ exception برای DRF: هندلرِ پیشفرض فقط APIException/Http404/
|
||||
PermissionDenied رو میشناسه؛ برای بقیه None برمیگردونه و exception خام تا
|
||||
مدیریتِ خطای جنگو بالا میره که (DEBUG=False) یه صفحهی HTML عمومی میده، نه
|
||||
JSON. این هندلر اون حالت رو با traceback کامل لاگ میکنه و یه پاسخِ JSON
|
||||
ژنریکِ ۵۰۰ برمیگردونه.
|
||||
"""
|
||||
import logging
|
||||
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import exception_handler as drf_exception_handler
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def custom_exception_handler(exc, context):
|
||||
response = drf_exception_handler(exc, context)
|
||||
if response is not None:
|
||||
return response
|
||||
|
||||
request = context.get('request')
|
||||
user = getattr(request, 'user', None)
|
||||
user_id = user.id if getattr(user, 'is_authenticated', False) else None
|
||||
logger.exception(
|
||||
'unhandled_exception path=%s user_id=%s',
|
||||
getattr(request, 'path', ''), user_id,
|
||||
)
|
||||
return Response(
|
||||
{'detail': 'خطای غیرمنتظرهای رخ داد؛ لطفاً بعداً دوباره تلاش کنید.'},
|
||||
status=500,
|
||||
)
|
||||
@@ -216,6 +216,10 @@ REST_FRAMEWORK = {
|
||||
'rest_framework.permissions.AllowAny',
|
||||
],
|
||||
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
|
||||
# ⚠️ افزوده شده: بدونِ این، exceptionِ ناشناخته (غیر از APIException/
|
||||
# Http404/PermissionDenied) بهجای پاسخِ JSON، صفحهی HTML عمومیِ ۵۰۰
|
||||
# جنگو رو برمیگردونه (نگاه کنید به config/exceptions.py).
|
||||
'EXCEPTION_HANDLER': 'config.exceptions.custom_exception_handler',
|
||||
'DEFAULT_RENDERER_CLASSES': [
|
||||
'rest_framework.renderers.JSONRenderer',
|
||||
'rest_framework.renderers.BrowsableAPIRenderer',
|
||||
|
||||
@@ -4,14 +4,40 @@
|
||||
هر اپ زیر پیشوند /api/ خودش mount شده. مسیرهای هر endpoint دقیقاً طبق
|
||||
سند «Endpointهای API» طراحیشده تا مقایسه با Swagger راحت باشه.
|
||||
"""
|
||||
import logging
|
||||
|
||||
from django.contrib import admin
|
||||
from django.http import JsonResponse
|
||||
from django.urls import include, path
|
||||
from django.views import defaults as django_default_views
|
||||
from drf_spectacular.views import (
|
||||
SpectacularAPIView,
|
||||
SpectacularRedocView,
|
||||
SpectacularSwaggerView,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def handler404(request, exception=None):
|
||||
"""برای مسیرهای /api/ همیشه JSON برمیگردونه؛ بقیه رفتارِ پیشفرضِ جنگو."""
|
||||
if request.path.startswith('/api/'):
|
||||
return JsonResponse({'detail': 'یافت نشد.'}, status=404)
|
||||
return django_default_views.page_not_found(request, exception)
|
||||
|
||||
|
||||
def handler500(request):
|
||||
"""شبکهی ایمنیِ نهایی برای exceptionی که حتی به config/exceptions.py هم
|
||||
نرسیده (مثلاً در خودِ middleware/URL resolution). traceback کامل رو
|
||||
config/middleware.py قبلاً لاگ کرده؛ اینجا فقط یه پاسخِ JSON میده."""
|
||||
logger.error('unhandled_500 path=%s', request.path)
|
||||
if request.path.startswith('/api/'):
|
||||
return JsonResponse(
|
||||
{'detail': 'خطای غیرمنتظرهای رخ داد؛ لطفاً بعداً دوباره تلاش کنید.'}, status=500,
|
||||
)
|
||||
return django_default_views.server_error(request)
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user