Explorar o código

Closes #5304: Return server error messages as JSON when handling REST API requests

Jeremy Stretch %!s(int64=5) %!d(string=hai) anos
pai
achega
f845eeb117

+ 4 - 0
docs/release-notes/version-2.9.md

@@ -2,6 +2,10 @@
 
 
 ## v2.9.9 (FUTURE)
 ## v2.9.9 (FUTURE)
 
 
+### Enhancements
+
+* [#5304](https://github.com/netbox-community/netbox/issues/5304) - Return server error messages as JSON when handling REST API requests
+
 ### Bug Fixes
 ### Bug Fixes
 
 
 * [#5271](https://github.com/netbox-community/netbox/issues/5271) - Fix auto-population of region field when editing a device
 * [#5271](https://github.com/netbox-community/netbox/issues/5271) - Fix auto-population of region field when editing a device

+ 5 - 1
netbox/utilities/middleware.py

@@ -7,7 +7,7 @@ from django.http import Http404, HttpResponseRedirect
 from django.urls import reverse
 from django.urls import reverse
 
 
 from .api import is_api_request
 from .api import is_api_request
-from .views import server_error
+from .views import server_error, rest_api_server_error
 
 
 
 
 class LoginRequiredMiddleware(object):
 class LoginRequiredMiddleware(object):
@@ -86,6 +86,10 @@ class ExceptionHandlingMiddleware(object):
         if isinstance(exception, Http404):
         if isinstance(exception, Http404):
             return
             return
 
 
+        # Handle exceptions that occur from REST API requests
+        if is_api_request(request):
+            return rest_api_server_error(request)
+
         # Determine the type of exception. If it's a common issue, return a custom error page with instructions.
         # Determine the type of exception. If it's a common issue, return a custom error page with instructions.
         custom_template = None
         custom_template = None
         if isinstance(exception, ProgrammingError):
         if isinstance(exception, ProgrammingError):

+ 19 - 4
netbox/utilities/views.py

@@ -13,7 +13,7 @@ from django.core.exceptions import FieldDoesNotExist, ImproperlyConfigured, Obje
 from django.db import transaction, IntegrityError
 from django.db import transaction, IntegrityError
 from django.db.models import ManyToManyField, ProtectedError
 from django.db.models import ManyToManyField, ProtectedError
 from django.forms import Form, ModelMultipleChoiceField, MultipleHiddenInput, Textarea
 from django.forms import Form, ModelMultipleChoiceField, MultipleHiddenInput, Textarea
-from django.http import HttpResponse, HttpResponseServerError
+from django.http import HttpResponse, HttpResponseServerError, JsonResponse
 from django.shortcuts import get_object_or_404, redirect, render
 from django.shortcuts import get_object_or_404, redirect, render
 from django.template import loader
 from django.template import loader
 from django.template.exceptions import TemplateDoesNotExist
 from django.template.exceptions import TemplateDoesNotExist
@@ -27,6 +27,7 @@ from django.views.decorators.csrf import requires_csrf_token
 from django.views.defaults import ERROR_500_TEMPLATE_NAME
 from django.views.defaults import ERROR_500_TEMPLATE_NAME
 from django.views.generic import View
 from django.views.generic import View
 from django_tables2 import RequestConfig
 from django_tables2 import RequestConfig
+from rest_framework import status
 
 
 from extras.models import CustomField, CustomFieldValue, ExportTemplate
 from extras.models import CustomField, CustomFieldValue, ExportTemplate
 from extras.querysets import CustomFieldQueryset
 from extras.querysets import CustomFieldQueryset
@@ -1423,8 +1424,22 @@ def server_error(request, template_name=ERROR_500_TEMPLATE_NAME):
     type_, error, traceback = sys.exc_info()
     type_, error, traceback = sys.exc_info()
 
 
     return HttpResponseServerError(template.render({
     return HttpResponseServerError(template.render({
-        'python_version': platform.python_version(),
-        'netbox_version': settings.VERSION,
-        'exception': str(type_),
         'error': error,
         'error': error,
+        'exception': str(type_),
+        'netbox_version': settings.VERSION,
+        'python_version': platform.python_version(),
     }))
     }))
+
+
+def rest_api_server_error(request, *args, **kwargs):
+    """
+    Handle exceptions and return a useful error message for REST API requests.
+    """
+    type_, error, traceback = sys.exc_info()
+    data = {
+        'error': str(error),
+        'exception': type_.__name__,
+        'netbox_version': settings.VERSION,
+        'python_version': platform.python_version(),
+    }
+    return JsonResponse(data, status=status.HTTP_500_INTERNAL_SERVER_ERROR)