def parse( self, query: str, full_fragments: str = "", should_validate: bool = True, is_fragment: bool = False, ) -> ParsedQuery: query_document_ast = parse("".join([full_fragments, query])) document_ast = parse(query) if not is_fragment: operation = get_operation_ast(document_ast) if not operation.name: raise AnonymousQueryError() if should_validate: errors = validate( self.schema, query_document_ast, [rule for rule in specified_rules if rule is not NoUnusedFragmentsRule], ) if errors: raise InvalidQueryError(errors) type_info = TypeInfo(self.schema) visitor = FieldToTypeMatcherVisitor(self.schema, type_info, query) visit(document_ast, TypeInfoVisitor(type_info, visitor)) result = visitor.parsed return result
def execute(self, *args, **kwargs): operation_ast = get_operation_ast(args[0]) if operation_ast and operation_ast.operation == "subscription": result = subscribe(self.schema, *args, **kwargs) if isinstance(result, Observable): a = [] result.subscribe(lambda x: a.append(x)) if len(a) > 0: result = a[-1] return result return execute(self.schema, *args, **kwargs)
def get_operation_ast(self, request): data = self.parse_body(request) query = request.GET.get("query") or data.get("query") if not query: return None source = Source(query, name="GraphQL request") document_ast = parse(source) operation_ast = get_operation_ast(document_ast, None) return operation_ast
def execute_graphql_request(self, method, query, variables, operation_name, show_graphiql=False): if not query: if show_graphiql: raise Return(None) raise HTTPError(400, 'Must provide query string.') source = Source(query, name='GraphQL request') try: document_ast = parse(source) validation_errors = validate(self.schema, document_ast) except Exception as e: raise Return(ExecutionResult(errors=[e], invalid=True)) if validation_errors: raise Return( ExecutionResult( errors=validation_errors, invalid=True, )) if method.lower() == 'get': operation_ast = get_operation_ast(document_ast, operation_name) if operation_ast and operation_ast.operation != 'query': if show_graphiql: raise Return(None) raise HTTPError( 405, 'Can only perform a {} operation from a POST request.'. format(operation_ast.operation)) try: result = yield self.execute(document_ast, root_value=self.root_value, variable_values=variables, operation_name=operation_name, context_value=self.context, middleware=self.middleware, executor=self.executor or TornadoExecutor(), return_promise=True) except Exception as e: raise Return(ExecutionResult(errors=[e], invalid=True)) raise Return(result)
def execute_graphql_request( self, request, data, query, variables, operation_name, ): if not query: raise HttpError( HttpResponseBadRequest("Must provide query string.")) with opentracing.global_tracer().start_active_span( "graphql_query") as scope: span = scope.span span.set_tag(opentracing.tags.COMPONENT, "GraphQL") try: document = parse(query) except GraphQLError as e: return ExecutionResult(errors=[e], data=dict(invalid=True)) if request.method.lower() == "get": operation_ast = get_operation_ast(document, operation_name) if operation_ast and operation_ast.operation != OperationType.QUERY: raise HttpError( HttpResponseNotAllowed( ["POST"], "Can only perform a {} operation from a POST request." .format(operation_ast.operation.value), )) validation_errors = validate(self.schema.graphql_schema, document) if validation_errors: return ExecutionResult(data=None, errors=validation_errors) try: with connection.execute_wrapper(tracing_wrapper): return self.schema.execute( source=query, root_value=self.get_root_value(request), variable_values=variables, operation_name=operation_name, context_value=self.get_context(request), middleware=self.get_middleware(request), ) except GraphQLError as e: span.set_tag(opentracing.tags.ERROR, True) return ExecutionResult(errors=[e])
def parse(self, query: str, should_validate: bool = True) -> ParsedQuery: document_ast = parse(query) operation = get_operation_ast(document_ast) if not operation.name: raise AnonymousQueryError() if should_validate: errors = validate(self.schema, document_ast) if errors: raise InvalidQueryError(errors) type_info = TypeInfo(self.schema) visitor = FieldToTypeMatcherVisitor(self.schema, type_info, query) visit(document_ast, TypeInfoVisitor(type_info, visitor)) result = visitor.parsed return result
def execute_graphql_request( schema: GraphQLSchema, params: GraphQLParams, allow_only_query: bool = False, **kwargs, ): if not params.query: raise HttpQueryError(400, "Must provide query string.") try: document = parse(params.query) except GraphQLError as e: return ExecutionResult(data=None, errors=[e]) except Exception as e: e = GraphQLError(str(e), original_error=e) return ExecutionResult(data=None, errors=[e]) if allow_only_query: operation_ast = get_operation_ast(document, params.operation_name) if operation_ast: operation = operation_ast.operation.value if operation != "query": raise HttpQueryError( 405, f"Can only perform a {operation} operation from a POST request.", headers={"Allow": "POST"}, ) # Note: the schema is not validated here for performance reasons. # This should be done only once when starting the server. validation_errors = validate(schema, document) if validation_errors: return ExecutionResult(data=None, errors=validation_errors) return execute( schema, document, variable_values=params.variables, operation_name=params.operation_name, **kwargs, )
def execute_graphql_request( self, request, data, query, variables, operation_name, show_graphiql=False ): if not query: if show_graphiql: return None raise HttpError(HttpResponseBadRequest("Must provide query string.")) try: document = parse(query) except Exception as e: return ExecutionResult(errors=[e]) if request.method.lower() == "get": operation_ast = get_operation_ast(document, operation_name) if operation_ast and operation_ast.operation != OperationType.QUERY: if show_graphiql: return None raise HttpError( HttpResponseNotAllowed( ["POST"], "Can only perform a {} operation from a POST request.".format( operation_ast.operation.value ), ) ) validation_errors = validate(self.schema.graphql_schema, document) if validation_errors: return ExecutionResult(data=None, errors=validation_errors) return self.schema.execute( source=query, root_value=self.get_root_value(request), variable_values=variables, operation_name=operation_name, context_value=self.get_context(request), middleware=self.get_middleware(request), )
def execute_graphql_request( self, request, data, query, variables, operation_name, show_graphiql=False ): if not query: if show_graphiql: return None raise HttpError(HttpResponseBadRequest("Must provide query string.")) try: document = parse(query) except Exception as e: return ExecutionResult(errors=[e]) if request.method.lower() == "get": operation_ast = get_operation_ast(document, operation_name) if operation_ast and operation_ast.operation != OperationType.QUERY: if show_graphiql: return None raise HttpError( HttpResponseNotAllowed( ["POST"], "Can only perform a {} operation from a POST request.".format( operation_ast.operation.value ), ) ) validation_errors = validate(self.schema.graphql_schema, document) if validation_errors: return ExecutionResult(data=None, errors=validation_errors) try: extra_options = {} if self.execution_context_class: extra_options["execution_context_class"] = self.execution_context_class options = { "source": query, "root_value": self.get_root_value(request), "variable_values": variables, "operation_name": operation_name, "context_value": self.get_context(request), "middleware": self.get_middleware(request), } options.update(extra_options) operation_ast = get_operation_ast(document, operation_name) if ( operation_ast and operation_ast.operation == OperationType.MUTATION and ( graphene_settings.ATOMIC_MUTATIONS is True or connection.settings_dict.get("ATOMIC_MUTATIONS", False) is True ) ): with transaction.atomic(): result = self.schema.execute(**options) if getattr(request, MUTATION_ERRORS_FLAG, False) is True: transaction.set_rollback(True) return result return self.schema.execute(**options) except Exception as e: return ExecutionResult(errors=[e])
async def __call__(self, request: Request) -> Response: """ Run the GraphQL query provided. :param request: aiohttp Request :return: aiohttp Response """ request_method = request.method.lower() try: variables = json.loads(request.query.get("variables", "{}")) except json.decoder.JSONDecodeError: return self.error_response("Variables are invalid JSON.") operation_name = request.query.get("operationName") if request_method == "options": return self.process_preflight(request) elif request_method == "post": try: data = await self.parse_body(request) except json.decoder.JSONDecodeError: return self.error_response("POST body sent invalid JSON.") operation_name = data.get("operationName", operation_name) elif request_method == "get": data = {"query": request.query.get("query")} else: return self.error_response( "GraphQL only supports GET and POST requests.", 405, headers={"Allow": "GET, POST"}, ) is_tool = self.is_tool(request) vars_dyn = data.get("variables", {}) or {} variables.update( vars_dyn if isinstance(vars_dyn, dict) else json.loads(vars_dyn) ) query = cast(str, data.get("query")) context = self.get_context(request) invalid = False if is_tool: tool = cast(GraphQLTool, self.tool) return await tool.render(query, variables, operation_name) if not data.get("query"): return self.encode_response( request, ExecutionResult( data=None, errors=[GraphQLError(message="Must provide query string.")], ), invalid=True, ) # Validate Schema schema_validation_errors = validate_schema(self.schema) if schema_validation_errors: # pragma: no cover return self.encode_response( request, ExecutionResult(data=None, errors=schema_validation_errors), invalid=True, ) # Parse try: document = parse(query) op = get_operation_ast(document, operation_name) if op is None: invalid = True else: if request_method == "get" and op.operation != OperationType.QUERY: return self.error_response( "Can only perform a {} operation from a POST request.".format( op.operation.value ), 405, headers={"Allow": "POST"}, ) except GraphQLError as error: return self.encode_response( request, ExecutionResult(data=None, errors=[error]), invalid=True ) except Exception as error: # pragma: no cover error = GraphQLError(str(error), original_error=error) return self.encode_response( request, ExecutionResult(data=None, errors=[error]), invalid=True ) # Validate validation_errors = validate(self.schema, document) if validation_errors: return self.encode_response( request, ExecutionResult(data=None, errors=validation_errors), invalid=True, ) if self.asynchronous: result = self._graphql( self.schema, document=document, variable_values=variables, operation_name=operation_name, root_value=self.root_value, context_value=context, middleware=self.middleware, ) if isawaitable(result): # pragma: no branch result = await cast(Awaitable[ExecutionResult], result) else: result = self._graphql( self.schema, document=document, variable_values=variables, operation_name=operation_name, root_value=self.root_value, context_value=context, middleware=self.middleware, ) return self.encode_response( request, cast(ExecutionResult, result), invalid=invalid )