I have implemented a GraphQL server in Python using Django and Graphene. I have mutations that use modelforms, which broadly look like this:
def mutate(self, info, **kwargs):
form = MyModelForm(kwargs)
if form.is_valid():
form.save()
return MyMutation(instance=form.instance)
raise GraphQLError(json.dumps(form.errors))
That is, if form validation fails, send the form errors as a JSON string, so that the frontend can neatly unpack the errors. This all works fine.
However, if there is some other error - say there's a problem with the database which throws an exception when the form tries to save, or there's a typo, then the default behaviour is for graphene to take the error message and transmit it in the GraphQL errors list to the client. Which means that anyone who inspects the response can see raw error messages from the server.This seems unwise - what if that error message contains information I don't want leaking? Obviously the solution is to create an application that doesn't throw exceptions, but I can't anticipate everything. Is there no way to tell graphene to be a bit more discrete, and provide a generic error message when an error isn't caused by me explicitly raising a GraphQLError, rather than just sending everything to the client?
An example of what is currently happening:
{"errors":[{"message":"name 'LogiForm' is not defined","locations":[{"line":2,"column":3}],"path":["login"]}],"data":{"login":null}}
This particular example isn't a security problem and would be easily caught before production, but it's just an example - and even when not a security threat, it seems a little unprofessional for my server to be making its internal error messages viewable by the client.
I am currently solving this with a decorator:
def hide_error(mutate):
def new_func(*args, **kwargs):
try:
return mutate(*args, **kwargs)
except Exception as e:
raise e if isinstance(e, GraphQLError) else Exception("Error.")
return new_func
But is there a better way? Is there a way you're 'supposed' to manage this problem?