-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathdrf_utils.py
46 lines (38 loc) · 1.87 KB
/
drf_utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from __future__ import annotations
from django.core.exceptions import (
PermissionDenied as DjangoPermissionDenied,
)
from django.core.exceptions import (
ValidationError as DjangoValidationError,
)
from django.http import Http404
from rest_framework import exceptions as drf_exceptions
from rest_framework import status
from rest_framework.response import Response
from rest_framework.serializers import as_serializer_error
from rest_framework.views import exception_handler
from dandiapi.api.services.exceptions import DandiError
def rewrap_django_core_exceptions(exc: Exception, ctx: dict) -> Response | None:
"""
Rewraps core Django exceptions and re-raises them as the DRF equivalent.
This is useful for allowing internal APIs to throw Django validation errors
and be used from DRF endpoints.
"""
if isinstance(exc, DjangoValidationError):
if len(exc.error_list) == 1:
# Dandi returns validation errors with 1 problem as a raw
# message. Support this for now, consider using the DRF enveloped format in the future.
return Response(exc.error_list[0].message, status=status.HTTP_400_BAD_REQUEST)
exc = drf_exceptions.ValidationError(as_serializer_error(exc))
elif isinstance(exc, DandiError):
return Response(exc.message, status=exc.http_status_code or status.HTTP_400_BAD_REQUEST)
if isinstance(exc, Http404):
exc = drf_exceptions.NotFound()
if isinstance(exc, DjangoPermissionDenied):
# Dandi currently returns 403 with messages that aren't in an envelope (see above
# for similarties with 400 errors). Prevent DRF from wrapping these messages and consider
# switching in the future.
if exc.args:
return Response(exc.args[0], status=status.HTTP_403_FORBIDDEN)
exc = drf_exceptions.PermissionDenied()
return exception_handler(exc, ctx)