1
- import typing as t
1
+ from typing import Any , Optional , List , Dict , Union , overload
2
+ from typing_extensions import TypedDict
2
3
3
4
from abc import ABC
4
5
from asyncio import gather
5
6
6
7
7
- from hiku .schema import GraphQLError , GraphQLRequest , GraphQLResponse , Schema
8
- from ..graph import Graph
8
+ from hiku .schema import ExecutionResult , GraphQLError , Schema
9
9
10
10
11
- BatchedRequest = t . List [ GraphQLRequest ]
12
- BatchedResponse = t . List [ GraphQLResponse ]
11
+ class GraphQLErrorObject ( TypedDict ):
12
+ message : str
13
13
14
- SingleOrBatchedRequest = t .Union [GraphQLRequest , BatchedRequest ]
15
- SingleOrBatchedResponse = t .Union [GraphQLResponse , BatchedResponse ]
16
14
15
+ class GraphQLRequest (TypedDict , total = False ):
16
+ query : str
17
+ variables : Optional [Dict [Any , Any ]]
18
+ operationName : Optional [str ]
17
19
18
- # TODO: do we need it ?
19
- G = t .TypeVar ("G" , bound = Graph )
20
- C = t .TypeVar ("C" )
21
20
21
+ class GraphQLResponse (TypedDict , total = False ):
22
+ data : Optional [Dict [str , object ]]
23
+ errors : Optional [List [object ]]
24
+ extensions : Optional [Dict [str , object ]]
22
25
23
- class BaseGraphQLEndpoint (ABC , t .Generic [C ]):
26
+
27
+ BatchedRequest = List [GraphQLRequest ]
28
+ BatchedResponse = List [GraphQLResponse ]
29
+
30
+ SingleOrBatchedRequest = Union [GraphQLRequest , BatchedRequest ]
31
+ SingleOrBatchedResponse = Union [GraphQLResponse , BatchedResponse ]
32
+
33
+
34
+ class BaseGraphQLEndpoint (ABC ):
24
35
"""TODO: add doc explaining the purpose of this class over plain schema"""
25
36
26
37
schema : Schema
@@ -33,10 +44,18 @@ def __init__(
33
44
self .schema = schema
34
45
self .batching = batching
35
46
47
+ def process_result (self , result : ExecutionResult ) -> GraphQLResponse :
48
+ data : GraphQLResponse = {"data" : result .data }
49
+
50
+ if result .error :
51
+ data ["errors" ] = [{"message" : e } for e in result .error .errors ]
52
+
53
+ return data
54
+
36
55
37
56
class BaseSyncGraphQLEndpoint (BaseGraphQLEndpoint ):
38
57
def dispatch (
39
- self , data : GraphQLRequest , context : t . Optional [t . Dict ] = None
58
+ self , data : GraphQLRequest , context : Optional [Dict ] = None
40
59
) -> GraphQLResponse :
41
60
"""
42
61
Dispatch graphql request to graph
@@ -46,32 +65,45 @@ def dispatch(
46
65
47
66
Returns: graphql response: data or errors
48
67
"""
49
- return self .schema .execute_sync (data , context )
68
+ assert "query" in data , "query is required"
69
+ result = self .schema .execute_sync (
70
+ query = data ["query" ],
71
+ variables = data .get ("variables" ),
72
+ operation_name = data .get ("operationName" ),
73
+ context = context ,
74
+ )
75
+ return self .process_result (result )
50
76
51
77
52
78
class BaseAsyncGraphQLEndpoint (BaseGraphQLEndpoint ):
53
79
async def dispatch (
54
- self , data : GraphQLRequest , context : t . Optional [t . Dict ] = None
80
+ self , data : GraphQLRequest , context : Optional [Dict ] = None
55
81
) -> GraphQLResponse :
56
- # TODO: what it we want to override exception handling?
57
- return await self .schema .execute (data , context )
82
+ assert "query" in data , "query is required"
83
+ result = await self .schema .execute (
84
+ query = data ["query" ],
85
+ variables = data .get ("variables" ),
86
+ operation_name = data .get ("operationName" ),
87
+ context = context ,
88
+ )
89
+ return self .process_result (result )
58
90
59
91
60
92
class GraphQLEndpoint (BaseSyncGraphQLEndpoint ):
61
- @t . overload
93
+ @overload
62
94
def dispatch (
63
- self , data : GraphQLRequest , context : t . Optional [t . Dict ] = None
95
+ self , data : GraphQLRequest , context : Optional [Dict ] = None
64
96
) -> GraphQLResponse :
65
97
...
66
98
67
- @t . overload
99
+ @overload
68
100
def dispatch (
69
- self , data : BatchedRequest , context : t . Optional [t . Dict ] = None
101
+ self , data : BatchedRequest , context : Optional [Dict ] = None
70
102
) -> BatchedResponse :
71
103
...
72
104
73
105
def dispatch (
74
- self , data : SingleOrBatchedRequest , context : t . Optional [t . Dict ] = None
106
+ self , data : SingleOrBatchedRequest , context : Optional [Dict ] = None
75
107
) -> SingleOrBatchedResponse :
76
108
if isinstance (data , list ):
77
109
if not self .batching :
@@ -88,26 +120,26 @@ def dispatch(
88
120
class BatchGraphQLEndpoint (GraphQLEndpoint ):
89
121
"""For backward compatibility"""
90
122
91
- def __init__ (self , * args : t . Any , ** kwargs : t . Any ):
123
+ def __init__ (self , * args : Any , ** kwargs : Any ):
92
124
kwargs ["batching" ] = True
93
125
super ().__init__ (* args , ** kwargs )
94
126
95
127
96
128
class AsyncGraphQLEndpoint (BaseAsyncGraphQLEndpoint ):
97
- @t . overload
129
+ @overload
98
130
async def dispatch (
99
- self , data : GraphQLRequest , context : t . Optional [t . Dict ] = None
131
+ self , data : GraphQLRequest , context : Optional [Dict ] = None
100
132
) -> GraphQLResponse :
101
133
...
102
134
103
- @t . overload
135
+ @overload
104
136
async def dispatch (
105
- self , data : BatchedRequest , context : t . Optional [t . Dict ] = None
137
+ self , data : BatchedRequest , context : Optional [Dict ] = None
106
138
) -> BatchedResponse :
107
139
...
108
140
109
141
async def dispatch (
110
- self , data : SingleOrBatchedRequest , context : t . Optional [t . Dict ] = None
142
+ self , data : SingleOrBatchedRequest , context : Optional [Dict ] = None
111
143
) -> SingleOrBatchedResponse :
112
144
if isinstance (data , list ):
113
145
return list (
@@ -129,6 +161,6 @@ async def dispatch(
129
161
class AsyncBatchGraphQLEndpoint (AsyncGraphQLEndpoint ):
130
162
"""For backward compatibility"""
131
163
132
- def __init__ (self , * args : t . Any , ** kwargs : t . Any ):
164
+ def __init__ (self , * args : Any , ** kwargs : Any ):
133
165
kwargs ["batching" ] = True
134
166
super ().__init__ (* args , ** kwargs )
0 commit comments