Beispiel #1
0
 def render_errors(self,
                   data,
                   accepted_media_type=None,
                   renderer_context=None):
     return super(JSONRenderer,
                  self).render(utils.format_errors(data),
                               accepted_media_type, renderer_context)
Beispiel #2
0
def exception_handler(exc, context):
    # Import this here to avoid potential edge-case circular imports, which
    # crashes with:
    # "ImportError: Could not import 'rest_framework_json_api.parsers.JSONParser' for API setting
    # 'DEFAULT_PARSER_CLASSES'. ImportError: cannot import name 'exceptions'.'"
    #
    # Also see: https://github.com/django-json-api/django-rest-framework-json-api/issues/158
    from rest_framework.views import exception_handler as drf_exception_handler

    # Render exception with DRF
    response = drf_exception_handler(exc, context)
    if not response:
        return response

    # Use regular DRF format if not rendered by DRF JSON API and not uniform
    is_json_api_view = rendered_with_json_api(context['view'])
    is_uniform = json_api_settings.UNIFORM_EXCEPTIONS
    if not is_json_api_view and not is_uniform:
        return response

    # Convert to DRF JSON API error format
    response = utils.format_drf_errors(response, context, exc)

    # Add top-level 'errors' object when not rendered by DRF JSON API
    if not is_json_api_view:
        response.data = utils.format_errors(response.data)

    return response
Beispiel #3
0
    def process_view(self, request, view_func, view_args, view_kwargs):
        try:
            schema = self.get_schema(request)
        except KeyError:
            return None
        encoding = self.get_encoding(request)
        json_data = json.loads(request.body.decode(encoding), encoding=encoding)
        errors = list(schema.iter_errors(json_data))
        if len(errors):
            errors = [
                {'detail': e.message, 'source': e.schema_path, 'status': '400'}
                for e in errors
            ]
            response = Response(errors, status='400')

            is_json_api_view = view_func and rendered_with_json_api(view_func.cls)
            if not is_json_api_view:
                response.data = utils.format_errors(response.data)

            return response
        return None
Beispiel #4
0
def exception_handler(exc, context):
    # Import this here to avoid potential edge-case circular imports, which
    # crashes with:
    # "ImportError: Could not import 'rest_framework_json_api.parsers.JSONParser' for API setting
    # 'DEFAULT_PARSER_CLASSES'. ImportError: cannot import name 'exceptions'.'"
    #
    # Also see: https://github.com/django-json-api/django-rest-framework-json-api/issues/158
    from rest_framework.views import exception_handler as drf_exception_handler

    # Render exception with DRF
    response = drf_exception_handler(exc, context)
    if not response:
        return unhandled_drf_exception_handler(exc, context)

    if response.status_code == status.HTTP_400_BAD_REQUEST:
        if isinstance(exc.detail, dict):
            for field, detail in list(exc.detail.items()):
                if isinstance(detail, dict):
                    for key in detail.keys():
                        exc.detail[f'{field}.{key}'] = detail[key]
                    exc.detail.pop(field)

    # Use regular DRF format if not rendered by DRF JSON API and not uniform
    is_json_api_view = rendered_with_json_api(context['view'])
    is_uniform = getattr(settings, 'JSON_API_UNIFORM_EXCEPTIONS', False)
    if not is_json_api_view and not is_uniform:
        return response

    # Convert to DRF JSON API error format
    response = utils.format_drf_errors(response, context, exc)

    # Add top-level 'errors' object when not rendered by DRF JSON API
    if not is_json_api_view:
        response.data = utils.format_errors(response.data)

    return response
Beispiel #5
0
def unhandled_drf_exception_handler(exc, context):
    """
    Deal with exceptions that DRF doesn't catch and return a JSON:API errors object.
    For model query parameters, attempt to identify the parameter that caused the exception:
    "Cannot resolve keyword 'xname' into field. Choices are: name, title, ...."
    Unfortunately there's no "clean" way to identify which field caused the exception other than
    parsing the error message. If the parse fails, a more generic error is reported.
    Even a 500 error for a jsonapi view should return a jsonapi error object, not an HTML response.
    """
    is_uniform = getattr(settings, 'JSON_API_UNIFORM_EXCEPTIONS', False)
    if not rendered_with_json_api(context['view']) and not is_uniform:
        return None

    errors = []

    if isinstance(exc, (FieldDoesNotExist, )):
        keymatch = re.compile(
            r"^Cannot resolve keyword '(?P<keyword>[\w_]+)' into field.")
        matched = keymatch.match(str(exc))
        bad_kw = matched.group("keyword") if matched else "?"

        status_code = 400
        errors.append({
            "detail": f"Missing Query Parameter: '{bad_kw}'",
            "source": {
                "parameter": bad_kw,
            },
            "status": str(status_code),
        })
    elif isinstance(exc, (FieldError, )):
        keymatch = re.compile(
            r"^Invalid field name\(s\) for model (?P<model>[\w_]+): '(?P<keyword>[\w_]+)'."
        )
        matched = keymatch.match(str(exc))

        bad_kw = matched.group("keyword") if matched else "?"
        bad_model = matched.group("model") if matched else "?"

        status_code = 400
        errors.append({
            "detail": f"No field {bad_kw} on model {bad_model}",
            "source": {
                "parameter": bad_kw,
            },
            "status": str(status_code),
        })
    elif isinstance(exc, (ValidationError, )):
        status_code = 400
        for error_key in exc.error_dict.keys():
            errors.append({
                "detail": exc.error_dict[error_key][0].message,
                "source": {
                    "pointer": f"data/attributes/{error_key}",
                },
                "status": str(status_code),
            })
    elif isinstance(exc, (ObjectDoesNotExist, )):
        status_code = 404
        errors.append({
            "detail": exc.args[0],
            "source": {
                "pointer": "/data",
            },
            "status": str(status_code),
        })
    else:
        LOG.error("HTTP 500 error: %s", exc)
        status_code = 500
        errors.append({
            "code": "server_error",
            "detail": str(exc),
            "status": str(status_code),
            "title": "Internal Server Error",
        })

    response = Response(errors, status=status_code)

    is_json_api_view = rendered_with_json_api(context['view'])
    if not is_json_api_view:
        response.data = utils.format_errors(response.data)

    return response
 def render_errors(self, data, accepted_media_type=None, renderer_context=None):
     return super(JSONRenderer, self).render(
         utils.format_errors(data), accepted_media_type, renderer_context
     )