Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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
like image 575
aiven Avatar asked Mar 18 '18 15:03

aiven


1 Answers

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)
like image 136
dspacejs Avatar answered Sep 21 '22 00:09

dspacejs