diff --git a/README.rst b/README.rst index 44feaee83..b30344bfe 100644 --- a/README.rst +++ b/README.rst @@ -55,6 +55,8 @@ serve the queries. url(r'^graphql$', GraphQLView.as_view(graphiql=True)), ] + handler500 = 'graphene_django.views.server_error' + Examples -------- diff --git a/graphene_django/tests/test_views.py b/graphene_django/tests/test_views.py index db6cc4e80..a85e3b3f2 100644 --- a/graphene_django/tests/test_views.py +++ b/graphene_django/tests/test_views.py @@ -1,6 +1,8 @@ import json import pytest +from mock import patch +import django.http try: from urllib import urlencode @@ -558,3 +560,15 @@ def test_passes_request_into_context_request(client): assert response.status_code == 200 assert response_json(response) == {"data": {"request": "testing"}} + + +def test_response_500(client): + with pytest.raises(RuntimeError), patch('graphql.backend.core.execute_and_validate', side_effect=RuntimeError): + response = client.get(url_string(query="{request}", q="testing")) + + +def test_response_500_handler(client): + import graphene_django.views + response = graphene_django.views.server_error(django.http.HttpRequest()) + assert response.status_code == 500 + assert response_json(response) == {"errors": ["server error"]} diff --git a/graphene_django/tests/urls.py b/graphene_django/tests/urls.py index 66b3fc4d2..30286375a 100644 --- a/graphene_django/tests/urls.py +++ b/graphene_django/tests/urls.py @@ -6,3 +6,5 @@ url(r"^graphql/batch", GraphQLView.as_view(batch=True)), url(r"^graphql", GraphQLView.as_view(graphiql=True)), ] + +handler500 = 'graphene_django.views.server_error' diff --git a/graphene_django/views.py b/graphene_django/views.py index aefe1147a..5551cbf46 100644 --- a/graphene_django/views.py +++ b/graphene_django/views.py @@ -4,15 +4,15 @@ import six from django.http import HttpResponse, HttpResponseNotAllowed -from django.http.response import HttpResponseBadRequest +from django.http.response import HttpResponseBadRequest, HttpResponseServerError from django.shortcuts import render from django.utils.decorators import method_decorator from django.views.generic import View -from django.views.decorators.csrf import ensure_csrf_cookie +from django.views.decorators.csrf import ensure_csrf_cookie, requires_csrf_token from graphql import get_default_backend from graphql.error import format_error as format_graphql_error -from graphql.error import GraphQLError +from graphql.error import GraphQLError, GraphQLSyntaxError from graphql.execution import ExecutionResult from graphql.type.schema import GraphQLSchema @@ -245,10 +245,10 @@ def execute_graphql_request( return None raise HttpError(HttpResponseBadRequest("Must provide query string.")) + backend = self.get_backend(request) try: - backend = self.get_backend(request) document = backend.document_from_string(self.schema, query) - except Exception as e: + except GraphQLSyntaxError as e: return ExecutionResult(errors=[e], invalid=True) if request.method.lower() == "get": @@ -266,13 +266,13 @@ def execute_graphql_request( ) ) - try: - extra_options = {} - if self.executor: - # We only include it optionally since - # executor is not a valid argument in all backends - extra_options["executor"] = self.executor + extra_options = {} + if self.executor: + # We only include it optionally since + # executor is not a valid argument in all backends + extra_options["executor"] = self.executor + try: return document.execute( root=self.get_root_value(request), variables=variables, @@ -281,7 +281,7 @@ def execute_graphql_request( middleware=self.get_middleware(request), **extra_options ) - except Exception as e: + except GraphQLError as e: return ExecutionResult(errors=[e], invalid=True) @classmethod @@ -338,3 +338,8 @@ def get_content_type(request): meta = request.META content_type = meta.get("CONTENT_TYPE", meta.get("HTTP_CONTENT_TYPE", "")) return content_type.split(";", 1)[0].lower() + + +@requires_csrf_token +def server_error(request, template_name=None): + return HttpResponseServerError('{"errors":["server error"]}', content_type='application/json')