8
8
DocumentNode , FieldNode , FragmentDefinitionNode ,
9
9
FragmentSpreadNode , InlineFragmentNode , OperationDefinitionNode ,
10
10
OperationType , SelectionSetNode )
11
+ from .middleware import MiddlewareManager
11
12
from ..pyutils import is_invalid , is_nullish , MaybeAwaitable
12
13
from ..utilities import get_operation_root_type , type_from_ast
13
14
from ..type import (
24
25
__all__ = [
25
26
'add_path' , 'assert_valid_execution_arguments' , 'default_field_resolver' ,
26
27
'execute' , 'get_field_def' , 'response_path_as_list' ,
27
- 'ExecutionResult' , 'ExecutionContext' ]
28
+ 'ExecutionResult' , 'ExecutionContext' , 'Middleware' ]
28
29
29
30
30
31
# Terminology
@@ -59,6 +60,53 @@ class ExecutionResult(NamedTuple):
59
60
60
61
ExecutionResult .__new__ .__defaults__ = (None , None ) # type: ignore
61
62
63
+ Middleware = Optional [Union [Tuple , List , MiddlewareManager ]]
64
+
65
+
66
+ def execute (
67
+ schema : GraphQLSchema , document : DocumentNode ,
68
+ root_value : Any = None , context_value : Any = None ,
69
+ variable_values : Dict [str , Any ]= None ,
70
+ operation_name : str = None ,
71
+ field_resolver : GraphQLFieldResolver = None ,
72
+ execution_context_class : Type [ExecutionContext ]= ExecutionContext ,
73
+ middleware : Middleware = None
74
+ ) -> MaybeAwaitable [ExecutionResult ]:
75
+ """Execute a GraphQL operation.
76
+
77
+ Implements the "Evaluating requests" section of the GraphQL specification.
78
+
79
+ Returns an ExecutionResult (if all encountered resolvers are synchronous),
80
+ or a coroutine object eventually yielding an ExecutionResult.
81
+
82
+ If the arguments to this function do not result in a legal execution
83
+ context, a GraphQLError will be thrown immediately explaining the invalid
84
+ input.
85
+ """
86
+ # If arguments are missing or incorrect, throw an error.
87
+ assert_valid_execution_arguments (schema , document , variable_values )
88
+
89
+ # If a valid execution context cannot be created due to incorrect
90
+ # arguments, a "Response" with only errors is returned.
91
+ exe_context = execution_context_class .build (
92
+ schema , document , root_value , context_value ,
93
+ variable_values , operation_name , field_resolver , middleware )
94
+
95
+ # Return early errors if execution context failed.
96
+ if isinstance (exe_context , list ):
97
+ return ExecutionResult (data = None , errors = exe_context )
98
+
99
+ # Return a possible coroutine object that will eventually yield the data
100
+ # described by the "Response" section of the GraphQL specification.
101
+ #
102
+ # If errors are encountered while executing a GraphQL field, only that
103
+ # field and its descendants will be omitted, and sibling fields will still
104
+ # be executed. An execution which encounters errors will still result in a
105
+ # coroutine object that can be executed without errors.
106
+
107
+ data = exe_context .execute_operation (exe_context .operation , root_value )
108
+ return exe_context .build_response (data )
109
+
62
110
63
111
class ExecutionContext :
64
112
"""Data that must be available at all points during query execution.
@@ -74,6 +122,7 @@ class ExecutionContext:
74
122
operation : OperationDefinitionNode
75
123
variable_values : Dict [str , Any ]
76
124
field_resolver : GraphQLFieldResolver
125
+ middleware_manager : Optional [MiddlewareManager ]
77
126
errors : List [GraphQLError ]
78
127
79
128
def __init__ (
@@ -83,6 +132,7 @@ def __init__(
83
132
operation : OperationDefinitionNode ,
84
133
variable_values : Dict [str , Any ],
85
134
field_resolver : GraphQLFieldResolver ,
135
+ middleware_manager : Optional [MiddlewareManager ],
86
136
errors : List [GraphQLError ]) -> None :
87
137
self .schema = schema
88
138
self .fragments = fragments
@@ -91,6 +141,7 @@ def __init__(
91
141
self .operation = operation
92
142
self .variable_values = variable_values
93
143
self .field_resolver = field_resolver # type: ignore
144
+ self .middleware_manager = middleware_manager
94
145
self .errors = errors
95
146
self ._subfields_cache : Dict [
96
147
Tuple [GraphQLObjectType , Tuple [FieldNode , ...]],
@@ -102,7 +153,8 @@ def build(
102
153
root_value : Any = None , context_value : Any = None ,
103
154
raw_variable_values : Dict [str , Any ]= None ,
104
155
operation_name : str = None ,
105
- field_resolver : GraphQLFieldResolver = None
156
+ field_resolver : GraphQLFieldResolver = None ,
157
+ middleware : Middleware = None
106
158
) -> Union [List [GraphQLError ], 'ExecutionContext' ]:
107
159
"""Build an execution context
108
160
@@ -115,6 +167,18 @@ def build(
115
167
operation : Optional [OperationDefinitionNode ] = None
116
168
has_multiple_assumed_operations = False
117
169
fragments : Dict [str , FragmentDefinitionNode ] = {}
170
+ middleware_manager : Optional [MiddlewareManager ] = None
171
+ if middleware is not None :
172
+ if isinstance (middleware , (list , tuple )):
173
+ middleware_manager = MiddlewareManager (* middleware )
174
+ elif isinstance (middleware , MiddlewareManager ):
175
+ middleware_manager = middleware
176
+ else :
177
+ raise TypeError (
178
+ "Middleware must be passed as a list or tuple of functions"
179
+ " or objects, or as a single MiddlewareManager object."
180
+ f" Got { middleware !r} instead." )
181
+
118
182
for definition in document .definitions :
119
183
if isinstance (definition , OperationDefinitionNode ):
120
184
if not operation_name and operation :
@@ -159,7 +223,8 @@ def build(
159
223
160
224
return cls (
161
225
schema , fragments , root_value , context_value , operation ,
162
- variable_values , field_resolver or default_field_resolver , errors )
226
+ variable_values , field_resolver or default_field_resolver ,
227
+ middleware_manager , errors )
163
228
164
229
def build_response (
165
230
self , data : MaybeAwaitable [Optional [Dict [str , Any ]]]
@@ -405,6 +470,9 @@ def resolve_field(
405
470
406
471
resolve_fn = field_def .resolve or self .field_resolver
407
472
473
+ if self .middleware_manager :
474
+ resolve_fn = self .middleware_manager .get_field_resolver (resolve_fn )
475
+
408
476
info = self .build_resolve_info (
409
477
field_def , field_nodes , parent_type , path )
410
478
@@ -752,49 +820,6 @@ def collect_subfields(
752
820
return sub_field_nodes
753
821
754
822
755
- def execute (
756
- schema : GraphQLSchema , document : DocumentNode ,
757
- root_value : Any = None , context_value : Any = None ,
758
- variable_values : Dict [str , Any ]= None ,
759
- operation_name : str = None , field_resolver : GraphQLFieldResolver = None ,
760
- execution_context_class : Type [ExecutionContext ]= ExecutionContext ,
761
- ) -> MaybeAwaitable [ExecutionResult ]:
762
- """Execute a GraphQL operation.
763
-
764
- Implements the "Evaluating requests" section of the GraphQL specification.
765
-
766
- Returns an ExecutionResult (if all encountered resolvers are synchronous),
767
- or a coroutine object eventually yielding an ExecutionResult.
768
-
769
- If the arguments to this function do not result in a legal execution
770
- context, a GraphQLError will be thrown immediately explaining the invalid
771
- input.
772
- """
773
- # If arguments are missing or incorrect, throw an error.
774
- assert_valid_execution_arguments (schema , document , variable_values )
775
-
776
- # If a valid execution context cannot be created due to incorrect
777
- # arguments, a "Response" with only errors is returned.
778
- exe_context = execution_context_class .build (
779
- schema , document , root_value , context_value ,
780
- variable_values , operation_name , field_resolver )
781
-
782
- # Return early errors if execution context failed.
783
- if isinstance (exe_context , list ):
784
- return ExecutionResult (data = None , errors = exe_context )
785
-
786
- # Return a possible coroutine object that will eventually yield the data
787
- # described by the "Response" section of the GraphQL specification.
788
- #
789
- # If errors are encountered while executing a GraphQL field, only that
790
- # field and its descendants will be omitted, and sibling fields will still
791
- # be executed. An execution which encounters errors will still result in a
792
- # coroutine object that can be executed without errors.
793
-
794
- data = exe_context .execute_operation (exe_context .operation , root_value )
795
- return exe_context .build_response (data )
796
-
797
-
798
823
def assert_valid_execution_arguments (
799
824
schema : GraphQLSchema , document : DocumentNode ,
800
825
raw_variable_values : Dict [str , Any ]= None ) -> None :
0 commit comments