We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Async executor issue / Event loop is closed
Hi!

I'm testing asynchronous GraphQL resolvers using the approach described here: https://www.starlette.io/graphql/

When I run the example as is with a simple uvicorn setup, I get the following error:

```
ERROR: Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/graphql/execution/executor.py", line 447, in resolve_or_error
    return executor.execute(resolve_fn, source, info, **args)
  File "/usr/local/lib/python3.7/site-packages/graphql/execution/executors/asyncio.py", line 71, in execute
    future = ensure_future(result, loop=self.loop)
  File "/usr/local/lib/python3.7/asyncio/tasks.py", line 581, in ensure_future
    task = loop.create_task(coro_or_future)
  File "/usr/local/lib/python3.7/asyncio/base_events.py", line 392, in create_task
    self._check_closed()
  File "/usr/local/lib/python3.7/asyncio/base_events.py", line 469, in _check_closed
    raise RuntimeError('Event loop is closed')
```

My understanding is that `uvicorn.run()` calls `uvloop_setup()`, which closes the default asyncio event loop before recreating one with the uvloop policy. Meanwhile, the `AsyncioExecutor` instance passed to the GraphQL app has already called `asyncio.get_event_loop()`, and stores the default asyncio event loop that is about to be closed.

See the problematic code below, as well as my workaround in the commented code: if I create the loop myself, pass it to the `AsyncioExecutor` instance, and to `uvicorn.run()`, my async resolver works.

Not sure if this is a bug, a documentation issue, or if I am missing something ;)

Let me know if I can help!

```python
from starlette.applications import Starlette
from uvicorn.loops.uvloop import uvloop_setup
from starlette.graphql import GraphQLApp
from graphql.execution.executors.asyncio import AsyncioExecutor
import graphene
import uvicorn

app = Starlette()


# loop = uvloop_setup()


class Query(graphene.ObjectType):
    hello = graphene.String(name=graphene.String(default_value="stranger"))

    async def resolve_hello(self, info, name):
        # We can make asynchronous network calls here.
        return "Hello " + name


# app.add_route('/', GraphQLApp(schema=graphene.Schema(query=Query), executor=AsyncioExecutor(loop)))
app.add_route('/', GraphQLApp(schema=graphene.Schema(query=Query), executor=AsyncioExecutor()))

if __name__ == '__main__':
    # uvicorn.run(app, loop=loop, host='0.0.0.0', port=8000)
    uvicorn.run(app, host='0.0.0.0', port=8000)
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `starlette/graphql.py`
Content:
```
1 import functools
2 import json
3 import typing
4 
5 from starlette import status
6 from starlette.background import BackgroundTasks
7 from starlette.concurrency import run_in_threadpool
8 from starlette.requests import Request
9 from starlette.responses import HTMLResponse, JSONResponse, PlainTextResponse, Response
10 from starlette.types import ASGIInstance, Receive, Scope, Send
11 
12 try:
13     import graphene
14     from graphql.execution.executors.asyncio import AsyncioExecutor
15     from graphql.error import format_error as format_graphql_error
16     from graphql.error import GraphQLError
17 except ImportError:  # pragma: nocover
18     graphene = None  # type: ignore
19     AsyncioExecutor = None  # type: ignore
20     format_graphql_error = None  # type: ignore
21     GraphQLError = None  # type: ignore
22 
23 
24 class GraphQLApp:
25     def __init__(self, schema: "graphene.Schema", executor: typing.Any = None) -> None:
26         self.schema = schema
27         self.executor = executor
28         self.is_async = isinstance(executor, AsyncioExecutor)
29 
30     def __call__(self, scope: Scope) -> ASGIInstance:
31         return functools.partial(self.asgi, scope=scope)
32 
33     async def asgi(self, receive: Receive, send: Send, scope: Scope) -> None:
34         request = Request(scope, receive=receive)
35         response = await self.handle_graphql(request)
36         await response(receive, send)
37 
38     async def handle_graphql(self, request: Request) -> Response:
39         if request.method in ("GET", "HEAD"):
40             if "text/html" in request.headers.get("Accept", ""):
41                 return await self.handle_graphiql(request)
42 
43             data = request.query_params  # type: typing.Mapping[str, typing.Any]
44 
45         elif request.method == "POST":
46             content_type = request.headers.get("Content-Type", "")
47 
48             if "application/json" in content_type:
49                 data = await request.json()
50             elif "application/graphql" in content_type:
51                 body = await request.body()
52                 text = body.decode()
53                 data = {"query": text}
54             elif "query" in request.query_params:
55                 data = request.query_params
56             else:
57                 return PlainTextResponse(
58                     "Unsupported Media Type",
59                     status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE,
60                 )
61 
62         else:
63             return PlainTextResponse(
64                 "Method Not Allowed", status_code=status.HTTP_405_METHOD_NOT_ALLOWED
65             )
66 
67         try:
68             query = data["query"]
69             variables = data.get("variables")
70             operation_name = data.get("operationName")
71         except KeyError:
72             return PlainTextResponse(
73                 "No GraphQL query found in the request",
74                 status_code=status.HTTP_400_BAD_REQUEST,
75             )
76 
77         background = BackgroundTasks()
78         context = {"request": request, "background": background}
79 
80         result = await self.execute(
81             query, variables=variables, context=context, operation_name=operation_name
82         )
83         error_data = (
84             [format_graphql_error(err) for err in result.errors]
85             if result.errors
86             else None
87         )
88         response_data = {"data": result.data, "errors": error_data}
89         status_code = (
90             status.HTTP_400_BAD_REQUEST if result.errors else status.HTTP_200_OK
91         )
92 
93         return JSONResponse(
94             response_data, status_code=status_code, background=background
95         )
96 
97     async def execute(  # type: ignore
98         self, query, variables=None, context=None, operation_name=None
99     ):
100         if self.is_async:
101             return await self.schema.execute(
102                 query,
103                 variables=variables,
104                 operation_name=operation_name,
105                 executor=self.executor,
106                 return_promise=True,
107                 context=context,
108             )
109         else:
110             return await run_in_threadpool(
111                 self.schema.execute,
112                 query,
113                 variables=variables,
114                 operation_name=operation_name,
115                 context=context,
116             )
117 
118     async def handle_graphiql(self, request: Request) -> Response:
119         text = GRAPHIQL.replace("{{REQUEST_PATH}}", json.dumps(request.url.path))
120         return HTMLResponse(text)
121 
122 
123 GRAPHIQL = """
124 <!--
125  *  Copyright (c) Facebook, Inc.
126  *  All rights reserved.
127  *
128  *  This source code is licensed under the license found in the
129  *  LICENSE file in the root directory of this source tree.
130 -->
131 <!DOCTYPE html>
132 <html>
133   <head>
134     <style>
135       body {
136         height: 100%;
137         margin: 0;
138         width: 100%;
139         overflow: hidden;
140       }
141       #graphiql {
142         height: 100vh;
143       }
144     </style>
145     <!--
146       This GraphiQL example depends on Promise and fetch, which are available in
147       modern browsers, but can be "polyfilled" for older browsers.
148       GraphiQL itself depends on React DOM.
149       If you do not want to rely on a CDN, you can host these files locally or
150       include them directly in your favored resource bunder.
151     -->
152     <link href="//cdn.jsdelivr.net/npm/graphiql@0.12.0/graphiql.css" rel="stylesheet"/>
153     <script src="//cdn.jsdelivr.net/npm/whatwg-fetch@2.0.3/fetch.min.js"></script>
154     <script src="//cdn.jsdelivr.net/npm/react@16.2.0/umd/react.production.min.js"></script>
155     <script src="//cdn.jsdelivr.net/npm/react-dom@16.2.0/umd/react-dom.production.min.js"></script>
156     <script src="//cdn.jsdelivr.net/npm/graphiql@0.12.0/graphiql.min.js"></script>
157   </head>
158   <body>
159     <div id="graphiql">Loading...</div>
160     <script>
161       /**
162        * This GraphiQL example illustrates how to use some of GraphiQL's props
163        * in order to enable reading and updating the URL parameters, making
164        * link sharing of queries a little bit easier.
165        *
166        * This is only one example of this kind of feature, GraphiQL exposes
167        * various React params to enable interesting integrations.
168        */
169       // Parse the search string to get url parameters.
170       var search = window.location.search;
171       var parameters = {};
172       search.substr(1).split('&').forEach(function (entry) {
173         var eq = entry.indexOf('=');
174         if (eq >= 0) {
175           parameters[decodeURIComponent(entry.slice(0, eq))] =
176             decodeURIComponent(entry.slice(eq + 1));
177         }
178       });
179       // if variables was provided, try to format it.
180       if (parameters.variables) {
181         try {
182           parameters.variables =
183             JSON.stringify(JSON.parse(parameters.variables), null, 2);
184         } catch (e) {
185           // Do nothing, we want to display the invalid JSON as a string, rather
186           // than present an error.
187         }
188       }
189       // When the query and variables string is edited, update the URL bar so
190       // that it can be easily shared
191       function onEditQuery(newQuery) {
192         parameters.query = newQuery;
193         updateURL();
194       }
195       function onEditVariables(newVariables) {
196         parameters.variables = newVariables;
197         updateURL();
198       }
199       function onEditOperationName(newOperationName) {
200         parameters.operationName = newOperationName;
201         updateURL();
202       }
203       function updateURL() {
204         var newSearch = '?' + Object.keys(parameters).filter(function (key) {
205           return Boolean(parameters[key]);
206         }).map(function (key) {
207           return encodeURIComponent(key) + '=' +
208             encodeURIComponent(parameters[key]);
209         }).join('&');
210         history.replaceState(null, null, newSearch);
211       }
212       // Defines a GraphQL fetcher using the fetch API. You're not required to
213       // use fetch, and could instead implement graphQLFetcher however you like,
214       // as long as it returns a Promise or Observable.
215       function graphQLFetcher(graphQLParams) {
216         // This example expects a GraphQL server at the path /graphql.
217         // Change this to point wherever you host your GraphQL server.
218         return fetch({{REQUEST_PATH}}, {
219           method: 'post',
220           headers: {
221             'Accept': 'application/json',
222             'Content-Type': 'application/json',
223           },
224           body: JSON.stringify(graphQLParams),
225           credentials: 'include',
226         }).then(function (response) {
227           return response.text();
228         }).then(function (responseBody) {
229           try {
230             return JSON.parse(responseBody);
231           } catch (error) {
232             return responseBody;
233           }
234         });
235       }
236       // Render <GraphiQL /> into the body.
237       // See the README in the top level of this module to learn more about
238       // how you can customize GraphiQL by providing different values or
239       // additional child elements.
240       ReactDOM.render(
241         React.createElement(GraphiQL, {
242           fetcher: graphQLFetcher,
243           query: parameters.query,
244           variables: parameters.variables,
245           operationName: parameters.operationName,
246           onEditQuery: onEditQuery,
247           onEditVariables: onEditVariables,
248           onEditOperationName: onEditOperationName
249         }),
250         document.getElementById('graphiql')
251       );
252     </script>
253   </body>
254 </html>
255 """
256
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/starlette/graphql.py b/starlette/graphql.py
--- a/starlette/graphql.py
+++ b/starlette/graphql.py
@@ -22,15 +22,35 @@
 
 
 class GraphQLApp:
-    def __init__(self, schema: "graphene.Schema", executor: typing.Any = None) -> None:
+    def __init__(
+        self,
+        schema: "graphene.Schema",
+        executor: typing.Any = None,
+        executor_class: type = None,
+    ) -> None:
         self.schema = schema
-        self.executor = executor
-        self.is_async = isinstance(executor, AsyncioExecutor)
+        if executor is None:
+            # New style in 0.10.0. Use 'executor_class'.
+            # See issue https://github.com/encode/starlette/issues/242
+            self.executor = executor
+            self.executor_class = executor_class
+            self.is_async = executor_class is not None and issubclass(
+                executor_class, AsyncioExecutor
+            )
+        else:
+            # Old style. Use 'executor'.
+            # We should remove this in the next median/major version bump.
+            self.executor = executor
+            self.executor_class = None
+            self.is_async = isinstance(executor, AsyncioExecutor)
 
     def __call__(self, scope: Scope) -> ASGIInstance:
         return functools.partial(self.asgi, scope=scope)
 
     async def asgi(self, receive: Receive, send: Send, scope: Scope) -> None:
+        if self.executor is None and self.executor_class is not None:
+            self.executor = self.executor_class()
+
         request = Request(scope, receive=receive)
         response = await self.handle_graphql(request)
         await response(receive, send)

{"golden_diff": "diff --git a/starlette/graphql.py b/starlette/graphql.py\n--- a/starlette/graphql.py\n+++ b/starlette/graphql.py\n@@ -22,15 +22,35 @@\n \n \n class GraphQLApp:\n-    def __init__(self, schema: \"graphene.Schema\", executor: typing.Any = None) -> None:\n+    def __init__(\n+        self,\n+        schema: \"graphene.Schema\",\n+        executor: typing.Any = None,\n+        executor_class: type = None,\n+    ) -> None:\n         self.schema = schema\n-        self.executor = executor\n-        self.is_async = isinstance(executor, AsyncioExecutor)\n+        if executor is None:\n+            # New style in 0.10.0. Use 'executor_class'.\n+            # See issue https://github.com/encode/starlette/issues/242\n+            self.executor = executor\n+            self.executor_class = executor_class\n+            self.is_async = executor_class is not None and issubclass(\n+                executor_class, AsyncioExecutor\n+            )\n+        else:\n+            # Old style. Use 'executor'.\n+            # We should remove this in the next median/major version bump.\n+            self.executor = executor\n+            self.executor_class = None\n+            self.is_async = isinstance(executor, AsyncioExecutor)\n \n     def __call__(self, scope: Scope) -> ASGIInstance:\n         return functools.partial(self.asgi, scope=scope)\n \n     async def asgi(self, receive: Receive, send: Send, scope: Scope) -> None:\n+        if self.executor is None and self.executor_class is not None:\n+            self.executor = self.executor_class()\n+\n         request = Request(scope, receive=receive)\n         response = await self.handle_graphql(request)\n         await response(receive, send)\n", "issue": "Async executor issue / Event loop is closed\nHi!\r\n\r\nI'm testing asynchronous GraphQL resolvers using the approach described here: https://www.starlette.io/graphql/\r\n\r\nWhen I run the example as is with a simple uvicorn setup, I get the following error:\r\n\r\n```\r\nERROR: Traceback (most recent call last):\r\n  File \"/usr/local/lib/python3.7/site-packages/graphql/execution/executor.py\", line 447, in resolve_or_error\r\n    return executor.execute(resolve_fn, source, info, **args)\r\n  File \"/usr/local/lib/python3.7/site-packages/graphql/execution/executors/asyncio.py\", line 71, in execute\r\n    future = ensure_future(result, loop=self.loop)\r\n  File \"/usr/local/lib/python3.7/asyncio/tasks.py\", line 581, in ensure_future\r\n    task = loop.create_task(coro_or_future)\r\n  File \"/usr/local/lib/python3.7/asyncio/base_events.py\", line 392, in create_task\r\n    self._check_closed()\r\n  File \"/usr/local/lib/python3.7/asyncio/base_events.py\", line 469, in _check_closed\r\n    raise RuntimeError('Event loop is closed')\r\n```\r\n\r\nMy understanding is that `uvicorn.run()` calls `uvloop_setup()`, which closes the default asyncio event loop before recreating one with the uvloop policy. Meanwhile, the `AsyncioExecutor` instance passed to the GraphQL app has already called `asyncio.get_event_loop()`, and stores the default asyncio event loop that is about to be closed.\r\n\r\nSee the problematic code below, as well as my workaround in the commented code: if I create the loop myself, pass it to the `AsyncioExecutor` instance, and to `uvicorn.run()`, my async resolver works.\r\n\r\nNot sure if this is a bug, a documentation issue, or if I am missing something ;)\r\n\r\nLet me know if I can help!\r\n\r\n```python\r\nfrom starlette.applications import Starlette\r\nfrom uvicorn.loops.uvloop import uvloop_setup\r\nfrom starlette.graphql import GraphQLApp\r\nfrom graphql.execution.executors.asyncio import AsyncioExecutor\r\nimport graphene\r\nimport uvicorn\r\n\r\napp = Starlette()\r\n\r\n\r\n# loop = uvloop_setup()\r\n\r\n\r\nclass Query(graphene.ObjectType):\r\n    hello = graphene.String(name=graphene.String(default_value=\"stranger\"))\r\n\r\n    async def resolve_hello(self, info, name):\r\n        # We can make asynchronous network calls here.\r\n        return \"Hello \" + name\r\n\r\n\r\n# app.add_route('/', GraphQLApp(schema=graphene.Schema(query=Query), executor=AsyncioExecutor(loop)))\r\napp.add_route('/', GraphQLApp(schema=graphene.Schema(query=Query), executor=AsyncioExecutor()))\r\n\r\nif __name__ == '__main__':\r\n    # uvicorn.run(app, loop=loop, host='0.0.0.0', port=8000)\r\n    uvicorn.run(app, host='0.0.0.0', port=8000)\r\n```\n", "before_files": [{"content": "import functools\nimport json\nimport typing\n\nfrom starlette import status\nfrom starlette.background import BackgroundTasks\nfrom starlette.concurrency import run_in_threadpool\nfrom starlette.requests import Request\nfrom starlette.responses import HTMLResponse, JSONResponse, PlainTextResponse, Response\nfrom starlette.types import ASGIInstance, Receive, Scope, Send\n\ntry:\n    import graphene\n    from graphql.execution.executors.asyncio import AsyncioExecutor\n    from graphql.error import format_error as format_graphql_error\n    from graphql.error import GraphQLError\nexcept ImportError:  # pragma: nocover\n    graphene = None  # type: ignore\n    AsyncioExecutor = None  # type: ignore\n    format_graphql_error = None  # type: ignore\n    GraphQLError = None  # type: ignore\n\n\nclass GraphQLApp:\n    def __init__(self, schema: \"graphene.Schema\", executor: typing.Any = None) -> None:\n        self.schema = schema\n        self.executor = executor\n        self.is_async = isinstance(executor, AsyncioExecutor)\n\n    def __call__(self, scope: Scope) -> ASGIInstance:\n        return functools.partial(self.asgi, scope=scope)\n\n    async def asgi(self, receive: Receive, send: Send, scope: Scope) -> None:\n        request = Request(scope, receive=receive)\n        response = await self.handle_graphql(request)\n        await response(receive, send)\n\n    async def handle_graphql(self, request: Request) -> Response:\n        if request.method in (\"GET\", \"HEAD\"):\n            if \"text/html\" in request.headers.get(\"Accept\", \"\"):\n                return await self.handle_graphiql(request)\n\n            data = request.query_params  # type: typing.Mapping[str, typing.Any]\n\n        elif request.method == \"POST\":\n            content_type = request.headers.get(\"Content-Type\", \"\")\n\n            if \"application/json\" in content_type:\n                data = await request.json()\n            elif \"application/graphql\" in content_type:\n                body = await request.body()\n                text = body.decode()\n                data = {\"query\": text}\n            elif \"query\" in request.query_params:\n                data = request.query_params\n            else:\n                return PlainTextResponse(\n                    \"Unsupported Media Type\",\n                    status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE,\n                )\n\n        else:\n            return PlainTextResponse(\n                \"Method Not Allowed\", status_code=status.HTTP_405_METHOD_NOT_ALLOWED\n            )\n\n        try:\n            query = data[\"query\"]\n            variables = data.get(\"variables\")\n            operation_name = data.get(\"operationName\")\n        except KeyError:\n            return PlainTextResponse(\n                \"No GraphQL query found in the request\",\n                status_code=status.HTTP_400_BAD_REQUEST,\n            )\n\n        background = BackgroundTasks()\n        context = {\"request\": request, \"background\": background}\n\n        result = await self.execute(\n            query, variables=variables, context=context, operation_name=operation_name\n        )\n        error_data = (\n            [format_graphql_error(err) for err in result.errors]\n            if result.errors\n            else None\n        )\n        response_data = {\"data\": result.data, \"errors\": error_data}\n        status_code = (\n            status.HTTP_400_BAD_REQUEST if result.errors else status.HTTP_200_OK\n        )\n\n        return JSONResponse(\n            response_data, status_code=status_code, background=background\n        )\n\n    async def execute(  # type: ignore\n        self, query, variables=None, context=None, operation_name=None\n    ):\n        if self.is_async:\n            return await self.schema.execute(\n                query,\n                variables=variables,\n                operation_name=operation_name,\n                executor=self.executor,\n                return_promise=True,\n                context=context,\n            )\n        else:\n            return await run_in_threadpool(\n                self.schema.execute,\n                query,\n                variables=variables,\n                operation_name=operation_name,\n                context=context,\n            )\n\n    async def handle_graphiql(self, request: Request) -> Response:\n        text = GRAPHIQL.replace(\"{{REQUEST_PATH}}\", json.dumps(request.url.path))\n        return HTMLResponse(text)\n\n\nGRAPHIQL = \"\"\"\n<!--\n *  Copyright (c) Facebook, Inc.\n *  All rights reserved.\n *\n *  This source code is licensed under the license found in the\n *  LICENSE file in the root directory of this source tree.\n-->\n<!DOCTYPE html>\n<html>\n  <head>\n    <style>\n      body {\n        height: 100%;\n        margin: 0;\n        width: 100%;\n        overflow: hidden;\n      }\n      #graphiql {\n        height: 100vh;\n      }\n    </style>\n    <!--\n      This GraphiQL example depends on Promise and fetch, which are available in\n      modern browsers, but can be \"polyfilled\" for older browsers.\n      GraphiQL itself depends on React DOM.\n      If you do not want to rely on a CDN, you can host these files locally or\n      include them directly in your favored resource bunder.\n    -->\n    <link href=\"//cdn.jsdelivr.net/npm/graphiql@0.12.0/graphiql.css\" rel=\"stylesheet\"/>\n    <script src=\"//cdn.jsdelivr.net/npm/whatwg-fetch@2.0.3/fetch.min.js\"></script>\n    <script src=\"//cdn.jsdelivr.net/npm/react@16.2.0/umd/react.production.min.js\"></script>\n    <script src=\"//cdn.jsdelivr.net/npm/react-dom@16.2.0/umd/react-dom.production.min.js\"></script>\n    <script src=\"//cdn.jsdelivr.net/npm/graphiql@0.12.0/graphiql.min.js\"></script>\n  </head>\n  <body>\n    <div id=\"graphiql\">Loading...</div>\n    <script>\n      /**\n       * This GraphiQL example illustrates how to use some of GraphiQL's props\n       * in order to enable reading and updating the URL parameters, making\n       * link sharing of queries a little bit easier.\n       *\n       * This is only one example of this kind of feature, GraphiQL exposes\n       * various React params to enable interesting integrations.\n       */\n      // Parse the search string to get url parameters.\n      var search = window.location.search;\n      var parameters = {};\n      search.substr(1).split('&').forEach(function (entry) {\n        var eq = entry.indexOf('=');\n        if (eq >= 0) {\n          parameters[decodeURIComponent(entry.slice(0, eq))] =\n            decodeURIComponent(entry.slice(eq + 1));\n        }\n      });\n      // if variables was provided, try to format it.\n      if (parameters.variables) {\n        try {\n          parameters.variables =\n            JSON.stringify(JSON.parse(parameters.variables), null, 2);\n        } catch (e) {\n          // Do nothing, we want to display the invalid JSON as a string, rather\n          // than present an error.\n        }\n      }\n      // When the query and variables string is edited, update the URL bar so\n      // that it can be easily shared\n      function onEditQuery(newQuery) {\n        parameters.query = newQuery;\n        updateURL();\n      }\n      function onEditVariables(newVariables) {\n        parameters.variables = newVariables;\n        updateURL();\n      }\n      function onEditOperationName(newOperationName) {\n        parameters.operationName = newOperationName;\n        updateURL();\n      }\n      function updateURL() {\n        var newSearch = '?' + Object.keys(parameters).filter(function (key) {\n          return Boolean(parameters[key]);\n        }).map(function (key) {\n          return encodeURIComponent(key) + '=' +\n            encodeURIComponent(parameters[key]);\n        }).join('&');\n        history.replaceState(null, null, newSearch);\n      }\n      // Defines a GraphQL fetcher using the fetch API. You're not required to\n      // use fetch, and could instead implement graphQLFetcher however you like,\n      // as long as it returns a Promise or Observable.\n      function graphQLFetcher(graphQLParams) {\n        // This example expects a GraphQL server at the path /graphql.\n        // Change this to point wherever you host your GraphQL server.\n        return fetch({{REQUEST_PATH}}, {\n          method: 'post',\n          headers: {\n            'Accept': 'application/json',\n            'Content-Type': 'application/json',\n          },\n          body: JSON.stringify(graphQLParams),\n          credentials: 'include',\n        }).then(function (response) {\n          return response.text();\n        }).then(function (responseBody) {\n          try {\n            return JSON.parse(responseBody);\n          } catch (error) {\n            return responseBody;\n          }\n        });\n      }\n      // Render <GraphiQL /> into the body.\n      // See the README in the top level of this module to learn more about\n      // how you can customize GraphiQL by providing different values or\n      // additional child elements.\n      ReactDOM.render(\n        React.createElement(GraphiQL, {\n          fetcher: graphQLFetcher,\n          query: parameters.query,\n          variables: parameters.variables,\n          operationName: parameters.operationName,\n          onEditQuery: onEditQuery,\n          onEditVariables: onEditVariables,\n          onEditOperationName: onEditOperationName\n        }),\n        document.getElementById('graphiql')\n      );\n    </script>\n  </body>\n</html>\n\"\"\"\n", "path": "starlette/graphql.py"}], "after_files": [{"content": "import functools\nimport json\nimport typing\n\nfrom starlette import status\nfrom starlette.background import BackgroundTasks\nfrom starlette.concurrency import run_in_threadpool\nfrom starlette.requests import Request\nfrom starlette.responses import HTMLResponse, JSONResponse, PlainTextResponse, Response\nfrom starlette.types import ASGIInstance, Receive, Scope, Send\n\ntry:\n    import graphene\n    from graphql.execution.executors.asyncio import AsyncioExecutor\n    from graphql.error import format_error as format_graphql_error\n    from graphql.error import GraphQLError\nexcept ImportError:  # pragma: nocover\n    graphene = None  # type: ignore\n    AsyncioExecutor = None  # type: ignore\n    format_graphql_error = None  # type: ignore\n    GraphQLError = None  # type: ignore\n\n\nclass GraphQLApp:\n    def __init__(\n        self,\n        schema: \"graphene.Schema\",\n        executor: typing.Any = None,\n        executor_class: type = None,\n    ) -> None:\n        self.schema = schema\n        if executor is None:\n            # New style in 0.10.0. Use 'executor_class'.\n            # See issue https://github.com/encode/starlette/issues/242\n            self.executor = executor\n            self.executor_class = executor_class\n            self.is_async = executor_class is not None and issubclass(\n                executor_class, AsyncioExecutor\n            )\n        else:\n            # Old style. Use 'executor'.\n            # We should remove this in the next median/major version bump.\n            self.executor = executor\n            self.executor_class = None\n            self.is_async = isinstance(executor, AsyncioExecutor)\n\n    def __call__(self, scope: Scope) -> ASGIInstance:\n        return functools.partial(self.asgi, scope=scope)\n\n    async def asgi(self, receive: Receive, send: Send, scope: Scope) -> None:\n        if self.executor is None and self.executor_class is not None:\n            self.executor = self.executor_class()\n\n        request = Request(scope, receive=receive)\n        response = await self.handle_graphql(request)\n        await response(receive, send)\n\n    async def handle_graphql(self, request: Request) -> Response:\n        if request.method in (\"GET\", \"HEAD\"):\n            if \"text/html\" in request.headers.get(\"Accept\", \"\"):\n                return await self.handle_graphiql(request)\n\n            data = request.query_params  # type: typing.Mapping[str, typing.Any]\n\n        elif request.method == \"POST\":\n            content_type = request.headers.get(\"Content-Type\", \"\")\n\n            if \"application/json\" in content_type:\n                data = await request.json()\n            elif \"application/graphql\" in content_type:\n                body = await request.body()\n                text = body.decode()\n                data = {\"query\": text}\n            elif \"query\" in request.query_params:\n                data = request.query_params\n            else:\n                return PlainTextResponse(\n                    \"Unsupported Media Type\",\n                    status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE,\n                )\n\n        else:\n            return PlainTextResponse(\n                \"Method Not Allowed\", status_code=status.HTTP_405_METHOD_NOT_ALLOWED\n            )\n\n        try:\n            query = data[\"query\"]\n            variables = data.get(\"variables\")\n            operation_name = data.get(\"operationName\")\n        except KeyError:\n            return PlainTextResponse(\n                \"No GraphQL query found in the request\",\n                status_code=status.HTTP_400_BAD_REQUEST,\n            )\n\n        background = BackgroundTasks()\n        context = {\"request\": request, \"background\": background}\n\n        result = await self.execute(\n            query, variables=variables, context=context, operation_name=operation_name\n        )\n        error_data = (\n            [format_graphql_error(err) for err in result.errors]\n            if result.errors\n            else None\n        )\n        response_data = {\"data\": result.data, \"errors\": error_data}\n        status_code = (\n            status.HTTP_400_BAD_REQUEST if result.errors else status.HTTP_200_OK\n        )\n\n        return JSONResponse(\n            response_data, status_code=status_code, background=background\n        )\n\n    async def execute(  # type: ignore\n        self, query, variables=None, context=None, operation_name=None\n    ):\n        if self.is_async:\n            return await self.schema.execute(\n                query,\n                variables=variables,\n                operation_name=operation_name,\n                executor=self.executor,\n                return_promise=True,\n                context=context,\n            )\n        else:\n            return await run_in_threadpool(\n                self.schema.execute,\n                query,\n                variables=variables,\n                operation_name=operation_name,\n                context=context,\n            )\n\n    async def handle_graphiql(self, request: Request) -> Response:\n        text = GRAPHIQL.replace(\"{{REQUEST_PATH}}\", json.dumps(request.url.path))\n        return HTMLResponse(text)\n\n\nGRAPHIQL = \"\"\"\n<!--\n *  Copyright (c) Facebook, Inc.\n *  All rights reserved.\n *\n *  This source code is licensed under the license found in the\n *  LICENSE file in the root directory of this source tree.\n-->\n<!DOCTYPE html>\n<html>\n  <head>\n    <style>\n      body {\n        height: 100%;\n        margin: 0;\n        width: 100%;\n        overflow: hidden;\n      }\n      #graphiql {\n        height: 100vh;\n      }\n    </style>\n    <!--\n      This GraphiQL example depends on Promise and fetch, which are available in\n      modern browsers, but can be \"polyfilled\" for older browsers.\n      GraphiQL itself depends on React DOM.\n      If you do not want to rely on a CDN, you can host these files locally or\n      include them directly in your favored resource bunder.\n    -->\n    <link href=\"//cdn.jsdelivr.net/npm/graphiql@0.12.0/graphiql.css\" rel=\"stylesheet\"/>\n    <script src=\"//cdn.jsdelivr.net/npm/whatwg-fetch@2.0.3/fetch.min.js\"></script>\n    <script src=\"//cdn.jsdelivr.net/npm/react@16.2.0/umd/react.production.min.js\"></script>\n    <script src=\"//cdn.jsdelivr.net/npm/react-dom@16.2.0/umd/react-dom.production.min.js\"></script>\n    <script src=\"//cdn.jsdelivr.net/npm/graphiql@0.12.0/graphiql.min.js\"></script>\n  </head>\n  <body>\n    <div id=\"graphiql\">Loading...</div>\n    <script>\n      /**\n       * This GraphiQL example illustrates how to use some of GraphiQL's props\n       * in order to enable reading and updating the URL parameters, making\n       * link sharing of queries a little bit easier.\n       *\n       * This is only one example of this kind of feature, GraphiQL exposes\n       * various React params to enable interesting integrations.\n       */\n      // Parse the search string to get url parameters.\n      var search = window.location.search;\n      var parameters = {};\n      search.substr(1).split('&').forEach(function (entry) {\n        var eq = entry.indexOf('=');\n        if (eq >= 0) {\n          parameters[decodeURIComponent(entry.slice(0, eq))] =\n            decodeURIComponent(entry.slice(eq + 1));\n        }\n      });\n      // if variables was provided, try to format it.\n      if (parameters.variables) {\n        try {\n          parameters.variables =\n            JSON.stringify(JSON.parse(parameters.variables), null, 2);\n        } catch (e) {\n          // Do nothing, we want to display the invalid JSON as a string, rather\n          // than present an error.\n        }\n      }\n      // When the query and variables string is edited, update the URL bar so\n      // that it can be easily shared\n      function onEditQuery(newQuery) {\n        parameters.query = newQuery;\n        updateURL();\n      }\n      function onEditVariables(newVariables) {\n        parameters.variables = newVariables;\n        updateURL();\n      }\n      function onEditOperationName(newOperationName) {\n        parameters.operationName = newOperationName;\n        updateURL();\n      }\n      function updateURL() {\n        var newSearch = '?' + Object.keys(parameters).filter(function (key) {\n          return Boolean(parameters[key]);\n        }).map(function (key) {\n          return encodeURIComponent(key) + '=' +\n            encodeURIComponent(parameters[key]);\n        }).join('&');\n        history.replaceState(null, null, newSearch);\n      }\n      // Defines a GraphQL fetcher using the fetch API. You're not required to\n      // use fetch, and could instead implement graphQLFetcher however you like,\n      // as long as it returns a Promise or Observable.\n      function graphQLFetcher(graphQLParams) {\n        // This example expects a GraphQL server at the path /graphql.\n        // Change this to point wherever you host your GraphQL server.\n        return fetch({{REQUEST_PATH}}, {\n          method: 'post',\n          headers: {\n            'Accept': 'application/json',\n            'Content-Type': 'application/json',\n          },\n          body: JSON.stringify(graphQLParams),\n          credentials: 'include',\n        }).then(function (response) {\n          return response.text();\n        }).then(function (responseBody) {\n          try {\n            return JSON.parse(responseBody);\n          } catch (error) {\n            return responseBody;\n          }\n        });\n      }\n      // Render <GraphiQL /> into the body.\n      // See the README in the top level of this module to learn more about\n      // how you can customize GraphiQL by providing different values or\n      // additional child elements.\n      ReactDOM.render(\n        React.createElement(GraphiQL, {\n          fetcher: graphQLFetcher,\n          query: parameters.query,\n          variables: parameters.variables,\n          operationName: parameters.operationName,\n          onEditQuery: onEditQuery,\n          onEditVariables: onEditVariables,\n          onEditOperationName: onEditOperationName\n        }),\n        document.getElementById('graphiql')\n      );\n    </script>\n  </body>\n</html>\n\"\"\"\n", "path": "starlette/graphql.py"}]}