diff --git a/docs/release-notes/version-2.9.md b/docs/release-notes/version-2.9.md index 977cb08e0..3d6ad5b81 100644 --- a/docs/release-notes/version-2.9.md +++ b/docs/release-notes/version-2.9.md @@ -2,6 +2,10 @@ ## 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 * [#5271](https://github.com/netbox-community/netbox/issues/5271) - Fix auto-population of region field when editing a device diff --git a/netbox/utilities/middleware.py b/netbox/utilities/middleware.py index d86be752b..605f10e42 100644 --- a/netbox/utilities/middleware.py +++ b/netbox/utilities/middleware.py @@ -7,7 +7,7 @@ from django.http import Http404, HttpResponseRedirect from django.urls import reverse from .api import is_api_request -from .views import server_error +from .views import server_error, rest_api_server_error class LoginRequiredMiddleware(object): @@ -86,6 +86,10 @@ class ExceptionHandlingMiddleware(object): if isinstance(exception, Http404): 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. custom_template = None if isinstance(exception, ProgrammingError): diff --git a/netbox/utilities/views.py b/netbox/utilities/views.py index 1dae60107..df8982755 100644 --- a/netbox/utilities/views.py +++ b/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.models import ManyToManyField, ProtectedError 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.template import loader 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.generic import View from django_tables2 import RequestConfig +from rest_framework import status from extras.models import CustomField, CustomFieldValue, ExportTemplate 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() return HttpResponseServerError(template.render({ - 'python_version': platform.python_version(), - 'netbox_version': settings.VERSION, - 'exception': str(type_), '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)