Example #1
0
    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
Example #2
0
    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)
Example #3
0
    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)
Example #5
0
    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])
Example #6
0
    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
Example #7
0
    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
Example #8
0
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,
    )
Example #9
0
    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),
        )
Example #10
0
    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])
Example #11
0
    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
        )