Exemplo n.º 1
0
def make_executable_schema(
    type_defs: Union[str, List[str]],
    *bindables: Union[SchemaBindable, List[SchemaBindable]],
    directives: Dict[str, Type[SchemaDirectiveVisitor]] = None,
) -> GraphQLSchema:
    if isinstance(type_defs, list):
        type_defs = join_type_defs(type_defs)

    ast_document = parse(type_defs)
    schema = build_and_extend_schema(ast_document)
    validate_schema(schema)

    for bindable in bindables:
        if isinstance(bindable, list):
            for obj in bindable:
                obj.bind_to_schema(schema)
        else:
            bindable.bind_to_schema(schema)

    set_default_enum_values_on_schema(schema)

    if directives:
        SchemaDirectiveVisitor.visit_schema_directives(schema, directives)

    assert_valid_schema(schema)

    return schema
def try_fast_introspection(schema: GraphQLSchema,
                           query: str) -> Optional[ExecutionResult]:
    """Compute the GraphQL introspection query if query can be computed fastly.

    Args:
        schema: GraphQL schema object, obtained from the graphql library
        query: string containing the introspection query to be executed on the schema

    Returns:
        - GraphQL Execution Result with data = None: there were schema validation errors.
        - GraphQL ExecutionResult with data != None: fast introspection was successful and computed
          data can be found under data attribute.
        - None if the query does not match the set introspection query in this module: the query
          cannot be computed fastly with this module.
    """
    if _remove_whitespace_from_query(
            query) != _whitespace_free_introspection_query:
        return None

    # Schema validations
    schema_validation_errors = validate_schema(schema)
    if schema_validation_errors:
        return ExecutionResult(data=None, errors=schema_validation_errors)

    return _execute_fast_introspection_query(schema)
Exemplo n.º 3
0
def make_executable_schema(
    type_defs: Union[str, List[str]],
    bindables: Union[SchemaBindable, List[SchemaBindable], None] = None,
) -> GraphQLSchema:
    if isinstance(type_defs, list):
        type_defs = join_type_defs(type_defs)

    ast_document = parse(type_defs)
    schema = build_and_extend_schema(ast_document)
    validate_schema(schema)

    if isinstance(bindables, list):
        for obj in bindables:
            obj.bind_to_schema(schema)
    elif bindables:
        bindables.bind_to_schema(schema)

    set_default_enum_values_on_schema(schema)

    return schema
Exemplo n.º 4
0
    def _build_schema(self) -> GraphQLSchema:
        schema = build_and_extend_schema(self._all_schema())

        schema_validation_errors = validate_schema(schema)
        if schema_validation_errors:
            raise Exception(f'Invalid schema: {schema_validation_errors}')

        schema = fix_abstract_resolve_type(schema)

        self._make_executable(schema)

        return schema
Exemplo n.º 5
0
    def __init__(
        self,
        # TODO: can we make sure we only allow to pass something that has been decorated?
        query: Type,
        mutation: Optional[Type] = None,
        subscription: Optional[Type] = None,
        directives=(),
        types=(),
        extensions: Sequence[Type[Extension]] = (),
        execution_context_class: Optional[Type[GraphQLExecutionContext]] = None,
    ):
        self.extensions = extensions
        self.execution_context_class = execution_context_class
        self.schema_converter = GraphQLCoreConverter()

        query_type = self.schema_converter.from_object_type(query)
        mutation_type = (
            self.schema_converter.from_object_type(mutation) if mutation else None
        )
        subscription_type = (
            self.schema_converter.from_object_type(subscription)
            if subscription
            else None
        )

        self.middleware: List[Middleware] = [DirectivesMiddleware(directives)]

        directives = [
            self.schema_converter.from_directive(directive.directive_definition)
            for directive in directives
        ]

        self._schema = GraphQLSchema(
            query=query_type,
            mutation=mutation_type,
            subscription=subscription_type if subscription else None,
            directives=specified_directives + directives,
            types=list(map(self.schema_converter.from_object_type, types)),
        )

        # Validate schema early because we want developers to know about
        # possible issues as soon as possible
        errors = validate_schema(self._schema)
        if errors:
            formatted_errors = "\n\n".join(f"❌ {error.message}" for error in errors)
            raise ValueError(f"Invalid Schema. Errors:\n\n{formatted_errors}")

        self.query = self.schema_converter.type_map[query_type.name]
Exemplo n.º 6
0
    def __init__(
        self,
        query: Type,
        mutation: Optional[Type] = None,
        subscription: Optional[Type] = None,
        scalars: Optional[GraphQLScalarMap] = None,
        enums: Optional[GraphQLEnumMap] = None,
        interfaces: Optional[GraphQLInterfaceMap] = None,
        query_types: Optional[GraphQLObjectTypeMap] = None,
        mutation_types: Optional[GraphQLInputObjectTypeMap] = None,
        camelcase=True,
    ):
        super().__init__()
        self.camelcase = camelcase
        builder = Builder(
            self.camelcase,
            scalars=scalars,
            enums=enums,
            interfaces=interfaces,
            query_types=query_types,
            mutation_types=mutation_types,
        )
        query_gql, mutation_gql, subscription_gql = None, None, None
        if query:
            self.query = query
            fields = builder.query_fields(query)
            query_gql = GraphQLObjectType(
                "Query",
                fields=fields,
            )

        if mutation:
            self.mutation = mutation
            mutation_fields = builder.query_fields(mutation)
            mutation_gql = GraphQLObjectType("Mutation",
                                             fields=mutation_fields)

        if subscription:
            self.subscription = subscription
            subscription_fields = builder.query_fields(subscription)
            subscription_gql = GraphQLObjectType("subscription",
                                                 fields=subscription_fields)

        super().__init__(query_gql, mutation_gql, subscription_gql)
        errors = validate_schema(self)
        if errors:
            raise errors[0]
Exemplo n.º 7
0
    def __init__(
            self,
            # TODO: can we make sure we only allow to pass something that has been decorated?
            query: Type,
            mutation: Optional[Type] = None,
            subscription: Optional[Type] = None,
            directives=(),
            types=(),
            extensions: Sequence[Type[Extension]] = (),
    ):
        self.extensions = extensions
        self.type_map: Dict[str, ConcreteType] = {}

        query_type = get_object_type(query, self.type_map)
        mutation_type = get_object_type(mutation,
                                        self.type_map) if mutation else None
        subscription_type = (get_object_type(subscription, self.type_map)
                             if subscription else None)

        self.middleware: List[Middleware] = [DirectivesMiddleware(directives)]

        directives = [
            get_directive_type(directive, self.type_map)
            for directive in directives
        ]

        self._schema = GraphQLSchema(
            query=query_type,
            mutation=mutation_type,
            subscription=subscription_type if subscription else None,
            directives=specified_directives + directives,
            types=[get_object_type(type, self.type_map) for type in types],
        )

        # Validate schema early because we want developers to know about
        # possible issues as soon as possible
        errors = validate_schema(self._schema)
        if errors:
            formatted_errors = "\n\n".join(f"❌ {error.message}"
                                           for error in errors)
            raise ValueError(f"Invalid Schema. Errors:\n\n{formatted_errors}")

        self.query = self.type_map[query_type.name]
Exemplo n.º 8
0
    def __init__(
        self,
        # TODO: can we make sure we only allow to pass something that has been decorated?
        query: Type,
        mutation: Optional[Type] = None,
        subscription: Optional[Type] = None,
        directives=(),
        types=(),
        extensions: Sequence[Union[Type[Extension], Extension]] = (),
        execution_context_class: Optional[Type[GraphQLExecutionContext]] = None,
        config: Optional[StrawberryConfig] = None,
        scalar_overrides: Optional[
            Dict[object, Union[ScalarWrapper, ScalarDefinition]]
        ] = None,
    ):
        self.extensions = extensions
        self.execution_context_class = execution_context_class
        self.config = config or StrawberryConfig()

        scalar_registry: Dict[object, Union[ScalarWrapper, ScalarDefinition]] = {
            **DEFAULT_SCALAR_REGISTRY
        }
        if scalar_overrides:
            scalar_registry.update(scalar_overrides)

        self.schema_converter = GraphQLCoreConverter(self.config, scalar_registry)
        self.directives = directives

        query_type = self.schema_converter.from_object(query._type_definition)
        mutation_type = (
            self.schema_converter.from_object(mutation._type_definition)
            if mutation
            else None
        )
        subscription_type = (
            self.schema_converter.from_object(subscription._type_definition)
            if subscription
            else None
        )

        directives = [
            self.schema_converter.from_directive(directive.directive_definition)
            for directive in directives
        ]

        graphql_types = []
        for type_ in types:
            graphql_type = self.schema_converter.from_object(type_._type_definition)
            graphql_types.append(graphql_type)

        self._schema = GraphQLSchema(
            query=query_type,
            mutation=mutation_type,
            subscription=subscription_type if subscription else None,
            directives=specified_directives + directives,
            types=graphql_types,
        )

        # Validate schema early because we want developers to know about
        # possible issues as soon as possible
        errors = validate_schema(self._schema)
        if errors:
            formatted_errors = "\n\n".join(f"❌ {error.message}" for error in errors)
            raise ValueError(f"Invalid Schema. Errors:\n\n{formatted_errors}")

        self.query = self.schema_converter.type_map[query_type.name]
Exemplo n.º 9
0
def test_convert_manager(info, session, manager_collection):
    converted = Convert(manager_collection.manager_map.values())
    converted_schema = converted.generate_schema()
    schema_validator = validate_schema(converted_schema)
    assert schema_validator == []
    assert assert_valid_schema(converted_schema) is None
Exemplo n.º 10
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
        )