99
1010from graphql import GraphQLSchema , ExecutionResult
1111
12+ from ..render_graphiql import render_graphiql_sync
13+ from .. import GraphQLParams
1214
13- class GraphQLHttpConsumer (AsyncHttpConsumer ):
14- """
15- A consumer to provide a view for GraphQL over HTTP.
16- To use this, place it in your ProtocolTypeRouter for your channels project:
17-
18- ```
19- from graphql_ws.channels import GraphQLHttpConsumer
20- from channels.routing import ProtocolTypeRouter, URLRouter
21- from django.core.asgi import get_asgi_application
22- application = ProtocolTypeRouter({
23- "http": URLRouter([
24- re_path("^graphql", GraphQLHttpConsumer(schema=schema)),
25- re_path("^", get_asgi_application()),
26- ]),
27- })
28- ```
29- """
3015
16+ class GraphQLHttpConsumer (AsyncHttpConsumer ):
3117 def __init__ (
3218 self ,
3319 schema : GraphQLSchema ,
@@ -37,107 +23,108 @@ def __init__(
3723 self .graphiql = graphiql
3824 super ().__init__ ()
3925
40- # def headers(self):
41- # return {
42- # header_name.decode("utf-8").lower(): header_value.decode("utf-8")
43- # for header_name, header_value in self.scope["headers"]
44- # }
45-
46- # async def parse_multipart_body(self, body):
47- # await self.send_response(500, "Unable to parse the multipart body")
48- # return None
49-
50- # async def get_graphql_params(self, data):
51- # query = data.get("query")
52- # variables = data.get("variables")
53- # id = data.get("id")
54-
55- # if variables and isinstance(variables, str):
56- # try:
57- # variables = json.loads(variables)
58- # except Exception:
59- # await self.send_response(500, b"Variables are invalid JSON.")
60- # return None
61- # operation_name = data.get("operationName")
62-
63- # return query, variables, operation_name, id
64-
65- # async def get_request_data(self, body) -> Optional[Any]:
66- # if self.headers.get("content-type", "").startswith("multipart/form-data"):
67- # data = await self.parse_multipart_body(body)
68- # if data is None:
69- # return None
70- # else:
71- # try:
72- # data = json.loads(body)
73- # except json.JSONDecodeError:
74- # await self.send_response(500, b"Unable to parse request body as JSON")
75- # return None
76-
77- # query, variables, operation_name, id = self.get_graphql_params(data)
78- # if not query:
79- # await self.send_response(500, b"No GraphQL query found in the request")
80- # return None
81-
82- # return query, variables, operation_name, id
83-
84- # async def post(self, body):
85- # request_data = await self.get_request_data(body)
86- # if request_data is None:
87- # return
88- # context = await self.get_context()
89- # root_value = await self.get_root_value()
90-
91- # result = await self.schema.execute(
92- # query=request_data.query,
93- # root_value=root_value,
94- # variable_values=request_data.variables,
95- # context_value=context,
96- # operation_name=request_data.operation_name,
97- # )
98-
99- # response_data = self.process_result(result)
100- # await self.send_response(
101- # 200,
102- # json.dumps(response_data).encode("utf-8"),
103- # headers=[(b"Content-Type", b"application/json")],
104- # )
105-
106- # def graphiql_html_file_path(self) -> Path:
107- # return Path(__file__).parent.parent.parent / "static" / "graphiql.html"
108-
109- # async def render_graphiql(self, body):
110- # html_string = self.graphiql_html_file_path.read_text()
111- # html_string = html_string.replace("{{ SUBSCRIPTION_ENABLED }}", "true")
112- # await self.send_response(
113- # 200, html_string.encode("utf-8"), headers=[(b"Content-Type", b"text/html")]
114- # )
115-
116- # def should_render_graphiql(self):
117- # return bool(self.graphiql and "text/html" in self.headers.get("accept", ""))
118-
119- # async def get(self, body):
120- # # if self.should_render_graphiql():
121- # # return await self.render_graphiql(body)
122- # # else:
123- # await self.send_response(
124- # 200, "{}", headers=[(b"Content-Type", b"text/json")]
125- # )
26+ def headers (self ):
27+ return {
28+ header_name .decode ("utf-8" ).lower (): header_value .decode ("utf-8" )
29+ for header_name , header_value in self .scope ["headers" ]
30+ }
31+
32+ async def parse_multipart_body (self , body ):
33+ await self .send_response (500 , "Unable to parse the multipart body" )
34+ return None
35+
36+ async def get_graphql_params (self , data ):
37+ query = data .get ("query" )
38+ variables = data .get ("variables" )
39+ id = data .get ("id" )
40+
41+ if variables and isinstance (variables , str ):
42+ try :
43+ variables = json .loads (variables )
44+ except Exception :
45+ await self .send_response (500 , b"Variables are invalid JSON." )
46+ return None
47+ operation_name = data .get ("operationName" )
48+
49+ return query , variables , operation_name , id
50+
51+ async def get_request_data (self , body ) -> Optional [Any ]:
52+ if self .headers .get ("content-type" , "" ).startswith ("multipart/form-data" ):
53+ data = await self .parse_multipart_body (body )
54+ if data is None :
55+ return None
56+ else :
57+ try :
58+ data = json .loads (body )
59+ except json .JSONDecodeError :
60+ await self .send_response (500 , b"Unable to parse request body as JSON" )
61+ return None
62+
63+ query , variables , operation_name , id = self .get_graphql_params (data )
64+ if not query :
65+ await self .send_response (500 , b"No GraphQL query found in the request" )
66+ return None
67+
68+ return query , variables , operation_name , id
69+
70+ async def post (self , body ):
71+ request_data = await self .get_request_data (body )
72+ if request_data is None :
73+ return
74+ context = await self .get_context ()
75+ root_value = await self .get_root_value ()
76+
77+ result = await self .schema .execute (
78+ query = request_data .query ,
79+ root_value = root_value ,
80+ variable_values = request_data .variables ,
81+ context_value = context ,
82+ operation_name = request_data .operation_name ,
83+ )
84+
85+ response_data = self .process_result (result )
86+ await self .send_response (
87+ 200 ,
88+ json .dumps (response_data ).encode ("utf-8" ),
89+ headers = [(b"Content-Type" , b"application/json" )],
90+ )
91+
92+ def graphiql_html_file_path (self ) -> Path :
93+ return Path (__file__ ).parent .parent .parent / "static" / "graphiql.html"
94+
95+ async def render_graphiql (self , body , params ):
96+ # html_string = self.graphiql_html_file_path.read_text()
97+ # html_string = html_string.replace("{{ SUBSCRIPTION_ENABLED }}", "true")
98+ html_string = render_graphiql_sync (body , params )
99+ await self .send_response (
100+ 200 , html_string .encode ("utf-8" ), headers = [(b"Content-Type" , b"text/html" )]
101+ )
102+
103+ def should_render_graphiql (self ):
104+ return bool (self .graphiql and "text/html" in self .headers .get ("accept" , "" ))
105+
106+ async def get (self , body ):
107+ if self .should_render_graphiql ():
108+ return await self .render_graphiql (body , params = GraphQLParams (query = "" ))
109+ else :
110+ await self .send_response (
111+ 200 , "{}" , headers = [(b"Content-Type" , b"text/json" )]
112+ )
126113
127114 async def handle (self , body ):
128- # if self.scope["method"] == "GET":
129- # return await self.get(body)
130- # if self.scope["method"] == "POST":
131- # return await self.post(body)
115+ if self .scope ["method" ] == "GET" :
116+ return await self .get (body )
117+ if self .scope ["method" ] == "POST" :
118+ return await self .post (body )
132119 await self .send_response (
133120 200 , b"Method not allowed" , headers = [b"Allow" , b"GET, POST" ]
134121 )
135122
136- # async def get_root_value(self) -> Any:
137- # return None
123+ async def get_root_value (self ) -> Any :
124+ return None
138125
139- # async def get_context(self) -> Any:
140- # return None
126+ async def get_context (self ) -> Any :
127+ return None
141128
142- # def process_result(self, result: ExecutionResult):
143- # return result.formatted
129+ def process_result (self , result : ExecutionResult ):
130+ return result .formatted
0 commit comments