How to return customized JSON response for an error in graphene / django-graphene?
Asked Answered
F

2

11

I want to add status field to error response, so instead of this:

{
  "errors": [
    {
      "message": "Authentication credentials were not provided",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ]
    }
  ],
  "data": {
    "viewer": null
  }
}

It should be like this:

{
  "errors": [
    {
      "status": 401,  # or 400 or 403 or whatever error status suits
      "message": "Authentication credentials were not provided",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ]
    }
  ],
  "data": {
    "viewer": null
  }
}

I found out that I only can change message by raising Exception inside resolver: raise Error('custom error message'), but how to add field?

Code example:

class Query(UsersQuery, graphene.ObjectType):
    me = graphene.Field(SelfUserNode)

    def resolve_me(self, info: ResolveInfo):
        user = info.context.user
        if not user.is_authenticated:
            # but status attr doesn't exist...
            raise GraphQLError('Authentication credentials were not provided', status=401)  
        return user
Faircloth answered 18/3, 2018 at 15:31 Comment(2)
can you provide some code, is this a mutation?Swanee
@MauricioCortazar, addedFaircloth
H
11

Update the default GraphQLView with the following:

from graphene_django.views import GraphQLView as BaseGraphQLView


class GraphQLView(BaseGraphQLView):

    @staticmethod
    def format_error(error):
        formatted_error = super(GraphQLView, GraphQLView).format_error(error)

        try:
            formatted_error['context'] = error.original_error.context
        except AttributeError:
            pass

        return formatted_error


urlpatterns = [
    path('api', GraphQLView.as_view()),
]

This will look for the context attribute in any exceptions raised. If it exists, it'll populate the error with this data.

Now you can create exceptions for different use cases that populate the context attribute. In this case you want to add the status code to errors, here's an example of how you'd do that:

class APIException(Exception):

    def __init__(self, message, status=None):
        self.context = {}
        if status:
            self.context['status'] = status
        super().__init__(message)

You'd use it like this:

raise APIException('Something went wrong', status=400)
Hamrick answered 27/9, 2019 at 7:13 Comment(1)
I don't think this is working anymore with the latest django_graphene versionPhotopia
S
1

I didn't found a way to solve your problem int the way that you propose, otherwise i extend the LoginRequiredMixin class like this:

class LoginRequiredMixin:
    def dispatch(self, info, *args, **kwargs):
        if not info.user.is_authenticated:
            e =  HttpError(HttpResponse(status=401, content_type='application/json'), 'Please log in first')
            response = e.response
            response.content = self.json_encode(info, [{'errors': [self.format_error(e)]}])
            return response

            return super().dispatch(info, *args, **kwargs)

class PrivateGraphQLView(LoginRequiredMixin, GraphQLView):
    schema=schema

and in your url:

from django.views.decorators.csrf import csrf_exempt
from educor.schema import PrivateGraphQLView
url(r'^graphql', csrf_exempt(PrivateGraphQLView.as_view(batch=True)))

you can't see the status with the graphiql but in your client you can get it in the headers or you could modify this line to add in the response response.content = self.json_encode(info, [{'errors': [self.format_error(e)]}]) . Hope it helps anyway i'll leave you another possible solution https://github.com/graphql-python/graphene-django/issues/252

Swanee answered 22/3, 2018 at 4:5 Comment(2)
As far as I know (now) root error field is for server error and I need to introduce custom error field inside data. But it is not best practice, it's still opened question for graphql community how to handle user errors. Right now I just add additional fields inside data: success, status, errors. And also by specification graphql server should return only 500 and 200 status codes, so I can't accept your answer ):Faircloth
@Aiven i know, as I said I didn't found the so I don't expect to you accept the answer, but I leave you this solution that might work for you, I will add to favourite if someone can answer itSwanee

© 2022 - 2024 — McMap. All rights reserved.