def validate(self, path, schema, field, parent_type_name, **__):
        rtype = find_field_reduced_type(parent_type_name, field.name.value,
                                        schema)

        if not rtype:
            return (
                []
            )  # Handled by field_selections_on_objects_interfaces_and_unions_types rule
            # TODO maybe think about rule order/dependencies

        is_gql_composite_type = isinstance(rtype, GraphQLCompositeType)

        if not field.selection_set and is_gql_composite_type:
            return [
                graphql_error_from_nodes(
                    message=
                    f"Field {field.name.value} of type {rtype.name} must have a selection of subfields.",
                    nodes=field,
                    path=path,
                    extensions=self._extensions,
                )
            ]

        if field.selection_set and not is_gql_composite_type:
            return [
                graphql_error_from_nodes(
                    message=
                    f"Field {field.name.value} must not have a selection since type {rtype.name} has no subfields.",
                    nodes=field,
                    path=path,
                    extensions=self._extensions,
                )
            ]

        return []
Exemplo n.º 2
0
    def _validate_input_fields(
        self,
        arg,
        schema_type_name,
        schema_input_fields,
        object_node,
        errors,
        path,
        schema,
    ):  # pylint: disable=too-many-locals
        for schema_input_field in schema_input_fields:
            if (schema_input_field
                    not in [x.name.value for x in object_node.fields]
                    and isinstance(
                        schema_input_fields[schema_input_field].gql_type,
                        GraphQLNonNull,
                    ) and schema_input_fields[schema_input_field].default_value
                    is None):
                errors.append(
                    graphql_error_from_nodes(
                        message=
                        f"Missing non nullable Input Field < {schema_input_field} > for Input Object < {schema_type_name} >.",
                        nodes=object_node,
                        path=path,
                        extensions=self._extensions,
                    ))

        for query_field_node in object_node.fields:
            if query_field_node.name.value not in schema_input_fields:
                errors.append(
                    graphql_error_from_nodes(
                        message=
                        f"Unknown Input Field < {query_field_node.name.value} > in < {schema_type_name} > Input Object",
                        nodes=query_field_node,
                        path=path,
                        extensions=self._extensions,
                    ))
                continue

            c_argument_schema_type = schema_input_fields[
                query_field_node.name.value].graphql_type
            r_argument_schema_type = reduce_type(c_argument_schema_type)
            if isinstance(r_argument_schema_type, str):
                r_argument_schema_type = schema.find_type(
                    r_argument_schema_type)

            errors = self._validate(
                r_argument_schema_type,
                c_argument_schema_type,
                arg,
                path,
                errors,
                schema,
                value_node=query_field_node.value,
                input_field=query_field_node,
            )
        return errors
def ensure_valid_runtime_type(
    runtime_type_or_name: Union["GraphQLObjectType", str],
    execution_context: "ExecutionContext",
    return_type: "GraphQLAbstractType",
    field_nodes: List["FieldNodes"],
    info: "ResolveInfo",
    result: Any,
) -> "GraphQLObjectType":
    """
    Validates and returns that the filled in runtime type is valid.
    :param runtime_type_or_name: name or GraphQLType of the runtime type
    :param execution_context: instance of the query execution context
    :param return_type: the GraphQLAbstractType instance of the object
    :param field_nodes: AST nodes related to the coerced field
    :param info: information related to the execution and the resolved field
    :param result: result to treat
    :type runtime_type_or_name: Union[GraphQLObjectType, str]
    :type execution_context: ExecutionContext
    :type return_type: GraphQLAbstractType
    :type field_nodes: List[FieldNode]
    :type info: ResolveInfo
    :type result: Any
    :return: the GraphQLObjectType representing the runtime type
    :rtype: GraphQLObjectType
    """
    if isinstance(runtime_type_or_name, str):
        try:
            runtime_type = execution_context.schema.find_type(
                runtime_type_or_name)
        except KeyError:
            runtime_type = runtime_type_or_name
    else:
        runtime_type = runtime_type_or_name

    if not isinstance(runtime_type, GraphQLObjectType):
        raise graphql_error_from_nodes(
            f"Abstract type < {return_type.name} > must resolve to an object "
            "type at runtime for field "
            f"< {info.parent_type.name}.{info.field_name} > with value "
            f"< {result} >, received < {runtime_type} >. "
            f"Either the < {return_type.name} > type should implements a "
            "< @TypeResolver > or the "
            f"< {info.parent_type.name}.{info.field_name} > field resolver "
            "should implement a `type_resolver` attribute.",
            nodes=field_nodes,
        )

    if not return_type.is_possible_type(runtime_type):
        raise graphql_error_from_nodes(
            f"Runtime object type < {runtime_type.name} > is not a possible "
            f"type for < {return_type.name} >.",
            nodes=field_nodes,
        )
    return runtime_type
Exemplo n.º 4
0
    def _validate_selection_set(self, operation, selection_set, fragments,
                                path):
        nb_selections = len(selection_set.selections)
        if nb_selections > 1:
            message = f"{f'Subcription {operation.name.value}' if operation.name else 'Anonymous Subscription'}"
            return [
                graphql_error_from_nodes(
                    message=f"{message} must select only one top level field.",
                    nodes=[operation, selection_set],
                    path=path,
                    extensions=self._extensions,
                )
            ]

        if nb_selections == 1:
            selected = selection_set.selections[0]
            if isinstance(selected, FragmentSpreadNode):
                frag = _find_fragment(fragments, selected.name.value)

                if not frag:
                    return []  # Handled by another validator

                return self._validate_selection_set(operation,
                                                    frag.selection_set,
                                                    fragments, path)

            if isinstance(selected, InlineFragmentNode):
                return self._validate_selection_set(operation,
                                                    selected.selection_set,
                                                    fragments, path)

        return []
    def _validate_is_possible(
        self, type_name, nodes, message, path, schema, locations=None
    ):  # pylint: disable=too-many-locals
        errors = []

        if not schema.has_type(type_name):
            return []  # Handled by another Validator (5.5.2.1)

        schema_type = schema.find_type(type_name)
        if not isinstance(schema_type, GraphQLCompositeType):
            return []  # Handled by another Validator (5.5.1.3)

        for index, node in enumerate(nodes):
            if not _validate_node(
                node, schema, schema_type.possible_types_set
            ):
                location = node.type_condition
                details = ""
                if message == "spread":
                    details = f" via < {node.name.value} > Fragment "
                    location = locations[index]["spread"]
                    path = locations[index]["path"]

                errors.append(
                    graphql_error_from_nodes(
                        message=f"Can't {message} < {node.type_condition.name.value} >{details}on Type < {type_name} >.",
                        nodes=location,
                        path=path,
                        extensions=self._extensions,
                    )
                )

        return errors
    def _validate_operation(self, operation, per_operation, per_fragment,
                            schema):
        errors = []
        for used_arg in _get_args_using_var(operation, per_operation,
                                            per_fragment):
            schema_argument = _find_schema_argument(used_arg, schema)
            variable_used = _find_variable_by_name(
                operation.variable_definitions,
                used_arg["arg"].value.name.value,
            )

            if not schema_argument or not variable_used:
                continue  # Handled by another validators

            if not _validate_usage(schema_argument, variable_used):
                errors.append(
                    graphql_error_from_nodes(
                        message=
                        f"Can't use < ${variable_used.variable.name.value} / {variable_used.type} > for type < {schema_argument.gql_type} >.",
                        nodes=[variable_used, used_arg["arg"].value],
                        path=used_arg["path"],
                        extensions=self._extensions,
                    ))

        return errors
Exemplo n.º 7
0
 def _validate_input_object(
     self,
     arg,
     schema_argument_definition,
     object_node,
     errors,
     path,
     schema,
 ):
     if not isinstance(object_node, ObjectValueNode):
         errors.append(
             graphql_error_from_nodes(
                 message=
                 f"Value is not a valid < {schema_argument_definition.name} > type, Object expected",
                 nodes=object_node,
                 path=path,
                 extensions=self._extensions,
             ))
     else:
         errors = self._validate_input_fields(
             arg,
             schema_argument_definition.name,
             schema_argument_definition.input_fields,
             object_node,
             errors,
             path,
             schema,
         )
     return errors
    def validate(self,
                 operations=None,
                 per_operation=None,
                 per_fragment=None,
                 **_):

        errors = []

        if not operations:
            return []  # No operation

        if not per_operation:
            per_operation = {}

        if not per_fragment:
            per_fragment = {}

        for operation in operations:
            errors.extend([
                graphql_error_from_nodes(
                    message=_get_message(operation, k),
                    nodes=[operation] + v,
                    path=None,
                    extensions=self._extensions,
                ) for k, v in _validate_operation(operation, per_operation,
                                                  per_fragment).items()
            ])

        return errors
Exemplo n.º 9
0
 def __init__(self, fragments, extensions):
     super().__init__()
     self.tartiflette_errors = [
         graphql_error_from_nodes(
             message="Fragment Cylcle Detected",
             path=None,
             nodes=fragments,
             extensions=extensions,
         )
     ]
 def _to_errors(self, erronous_speads, path):
     errors = []
     for spread_name, spreads in erronous_speads.items():
         errors.append(
             graphql_error_from_nodes(
                 message=f"Unknown Fragment for Spread < {spread_name} >.",
                 nodes=spreads,
                 path=path,
                 extensions=self._extensions,
             ))
     return errors
    def validate(self, directive, schema, path, **_):
        if not schema.has_directive(directive.name.value):
            return [
                graphql_error_from_nodes(
                    message=f"Unknow Directive < @{directive.name.value} >.",
                    nodes=directive,
                    path=path,
                    extensions=self._extensions,
                )
            ]

        return []
async def input_directives_coercer(
    parent_node: Union["VariableDefinitionNode", "InputValueDefinitionNode"],
    node: "Node",
    value: Any,
    ctx: Optional[Any],
    coercer: Callable,
    directives: Optional[Callable],
    path: Optional["Path"] = None,
) -> "CoercionResult":
    """
    Executes the directives on the coerced value.
    :param parent_node: the root parent AST node
    :param node: the AST node to treat
    :param value: the raw value to compute
    :param ctx: context passed to the query execution
    :param coercer: pre-computed coercer to use on the value
    :param directives: the directives to execute
    :param path: the path traveled until this coercer
    :type parent_node: Union[VariableDefinitionNode, InputValueDefinitionNode]
    :type node: Node
    :type value: Any
    :type ctx: Optional[Any]
    :type coercer: Callable
    :type directives: Optional[Callable]
    :type path: Optional[Path]
    :return: the coercion result
    :rtype: CoercionResult
    """
    coercion_result = await coercer(parent_node, node, value, ctx, path=path)

    if not directives:
        return coercion_result

    value, errors = coercion_result
    if errors:
        return coercion_result

    try:
        return CoercionResult(value=await directives(
            parent_node, value, ctx, context_coercer=ctx))
    except Exception as raw_exception:  # pylint: disable=broad-except
        return CoercionResult(errors=[
            graphql_error_from_nodes(
                str(raw_exception),
                node,
                original_error=(raw_exception if not is_coercible_exception(
                    raw_exception) else None),
            ) for raw_exception in (raw_exception.exceptions if isinstance(
                raw_exception, MultipleException) else [raw_exception])
        ])
Exemplo n.º 13
0
    def validate(self, path, schema, fragment, **__):
        errors = []

        if fragment.type_condition and not schema.has_type(
                fragment.type_condition.name.value):
            errors.append(
                graphql_error_from_nodes(
                    message=
                    f"Unknown type {fragment.type_condition.name.value}.",
                    nodes=fragment,
                    path=path,
                    extensions=self._extensions,
                ))

        return errors
Exemplo n.º 14
0
    def validate(self, variable, path, schema, **__):
        var_type = get_wrapped_named_type(variable.type)

        if schema.has_type(var_type.name.value) and not isinstance(
            schema.find_type(var_type.name.value), GraphQLInputType
        ):
            return [
                graphql_error_from_nodes(
                    message=f"Variable {variable.variable.name.value} cannot be non-input type {var_type.name.value}.",
                    path=path,
                    nodes=variable,
                    extensions=self._extensions,
                )
            ]

        return []
    def validate(self, definitions, path, **__):
        bad_nodes = [
            x for x in definitions
            if not isinstance(x, ExecutableDefinitionNode)
        ]
        if bad_nodes:
            return [
                graphql_error_from_nodes(
                    message="Theses definitions are not executable.",
                    path=path,
                    nodes=bad_nodes,
                    extensions=self._extensions,
                )
            ]

        return []
 def _validate_arguments(self, parent_node, schema_definition, path,
                         message_suffix):
     errors = []
     for schema_arg in schema_definition.arguments.values():
         if (isinstance(schema_arg.graphql_type, GraphQLNonNull)
                 and schema_arg.default_value is None
                 and not find_nodes_by_name(parent_node.arguments,
                                            schema_arg.name)):
             errors.append(
                 graphql_error_from_nodes(
                     message=
                     f"Missing mandatory argument < {schema_arg.name} > {message_suffix}",
                     nodes=parent_node,
                     path=path,
                     extensions=self._extensions,
                 ))
     return errors
Exemplo n.º 17
0
 def get_operation_root_type(
         self, operation: "OperationDefinitionNode") -> "GraphQLObjectType":
     """
     Extracts the root type of the operation from the schema.
     :param operation: AST operation definition node from which retrieve the
     root type
     :type operation: OperationDefinitionNode
     :return: the GraphQLObjectType instance related to the operation
     definition
     :rtype: GraphQLObjectType
     """
     try:
         return self._operation_types[operation.operation_type]
     except KeyError:
         raise graphql_error_from_nodes(
             "Schema is not configured for %ss." % operation.operation_type,
             nodes=operation,
         )
    def validate(self, path, fragments, fragment_spreads=None, **__):
        errors = []

        if not fragment_spreads:
            fragment_spreads = []

        for fragment in fragments:
            if not find_nodes_by_name(fragment_spreads, fragment.name.value):
                errors.append(
                    graphql_error_from_nodes(
                        message=
                        f"Fragment < {fragment.name.value} > is never used.",
                        nodes=fragment,
                        path=path,
                        extensions=self._extensions,
                    ))

        return errors
    def validate(self, path, schema, field, parent_type_name, **__):
        graphql_type = find_field_reduced_type(
            parent_type_name, field.name.value, schema
        )

        if field.name.value.startswith("__"):
            return []

        if graphql_type is None:
            return [
                graphql_error_from_nodes(
                    message=f"Field {field.name.value} doesn't exist on {parent_type_name or 'Root'}",
                    nodes=field,
                    path=path,
                    extensions=self._extensions,
                )
            ]

        return []
Exemplo n.º 20
0
    def _validate_directive_arguments(self, query_node, path, schema):
        errors = []
        if not schema.has_directive(query_node.name.value):
            return []  # Handled by another Validator

        schema_directive = schema.find_directive(query_node.name.value)

        for argument in query_node.arguments:
            if argument.name.value not in schema_directive.arguments:
                errors.append(
                    graphql_error_from_nodes(
                        message=f"Provided Argument < {argument.name.value} > doesn't exist on directive < @{schema_directive.name} >.",
                        nodes=argument,
                        path=path,
                        extensions=self._extensions,
                    )
                )

        return errors
Exemplo n.º 21
0
    def validate(self, path, operations, **__):
        bad_nodes = []
        errors = []

        if len(operations) > 1:
            for operation in operations:
                if operation.name is None:
                    bad_nodes.append(operation)

        if bad_nodes:
            errors.append(
                graphql_error_from_nodes(
                    message="Anonymous operation must be the only defined operation.",
                    path=path,
                    nodes=bad_nodes,
                    extensions=self._extensions,
                )
            )

        return errors
    def validate(self, path, schema, fragment, **__):
        errors = []
        if (fragment.type_condition
                and schema.has_type(fragment.type_condition.name.value)
                and not isinstance(
                    schema.find_type(fragment.type_condition.name.value),
                    GraphQLCompositeType,
                )):
            message = (f"Fragment {fragment.name.value}"
                       if not isinstance(fragment, InlineFragmentNode) else
                       f"Inline Fragment")
            errors.append(
                graphql_error_from_nodes(
                    message=
                    f"{message} cannot condition on non composite type {fragment.type_condition.name.value}.",
                    nodes=fragment,
                    path=path,
                    extensions=self._extensions,
                ))

        return errors
    def validate(self, path, fragments, **__):
        errors = []
        already_tested = []

        for fragment in fragments:
            if fragment.name.value in already_tested:
                continue

            with_same_name = find_nodes_by_name(fragments, fragment.name.value)
            if len(with_same_name) > 1:
                already_tested.append(fragment.name.value)
                errors.append(
                    graphql_error_from_nodes(
                        message=
                        f"Can't have multiple fragments named < {fragment.name.value} >.",
                        path=path,
                        nodes=with_same_name,
                        extensions=self._extensions,
                    ))

        return errors
Exemplo n.º 24
0
    def _validate_field_arguments(self, query_field, path, schema,
                                  parent_type_name):
        errors = []

        schema_field = find_field(parent_type_name, query_field.name.value,
                                  schema)

        if not schema_field:
            return []  # Handled somewhere else.

        for query_field_argument in query_field.arguments:
            if query_field_argument.name.value not in schema_field.arguments:
                errors.append(
                    graphql_error_from_nodes(
                        message=
                        f"Provided Argument < {query_field_argument.name.value} > doesn't exists on field < {parent_type_name}.{schema_field.name} >.",
                        nodes=query_field_argument,
                        path=path,
                        extensions=self._extensions,
                    ))

        return errors
Exemplo n.º 25
0
    def validate(self, path, operations, **__):
        errors = []
        already_tested = []

        for operation in operations:
            if not operation.name or operation.name.value in already_tested:
                continue

            with_same_name = find_nodes_by_name(operations,
                                                operation.name.value)
            if len(with_same_name) > 1:
                already_tested.append(operation.name.value)
                errors.append(
                    graphql_error_from_nodes(
                        message=
                        f"Can't have multiple operations named < {operation.name.value} >.",
                        path=path,
                        nodes=with_same_name,
                        extensions=self._extensions,
                    ))

        return errors
Exemplo n.º 26
0
    def validate(self, path, input_fields, **__):
        errors = []
        already_tested = []

        for ifield in input_fields:
            if ifield.name.value in already_tested:
                continue

            with_same_name = find_nodes_by_name(input_fields,
                                                ifield.name.value)
            if len(with_same_name) > 1:
                already_tested.append(ifield.name.value)
                errors.append(
                    graphql_error_from_nodes(
                        message=
                        f"Can't have multiple Input Field named < {ifield.name.value} >.",
                        path=path,
                        nodes=with_same_name,
                        extensions=self._extensions,
                    ))

        return errors
    def validate(self, path, variable_definitions, **__):
        errors = []
        already_tested = []

        variables = [x.variable for x in variable_definitions]

        for variable in variables:
            if variable.name.value in already_tested:
                continue

            with_same_name = find_nodes_by_name(variables, variable.name.value)
            if len(with_same_name) > 1:
                already_tested.append(variable.name.value)
                errors.append(
                    graphql_error_from_nodes(
                        message=
                        f"Can't have multiple variables named < {variable.name.value} >.",
                        path=path,
                        nodes=with_same_name,
                        extensions=self._extensions,
                    ))

        return errors
Exemplo n.º 28
0
    def validate(self, directives, path, **_):
        errors = []
        already_tested = []

        for directive in directives:
            if directive.name.value in already_tested:
                continue

            with_same_name = find_nodes_by_name(
                directives, directive.name.value
            )
            if len(with_same_name) > 1:
                already_tested.append(directive.name.value)
                errors.append(
                    graphql_error_from_nodes(
                        message=f"Can't have multiple directives named < {directive.name.value} > in the same location.",
                        path=path,
                        nodes=with_same_name,
                        extensions=self._extensions,
                    )
                )

        return errors
    def validate(self, node, path, schema, **_):
        errors = []

        node_type = type(node)
        if isinstance(node, OperationDefinitionNode):
            node_type = node.operation_type.lower()

        for directive in node.directives:
            if not schema.has_directive(directive.name.value):
                continue  # Handled by another validator (5.7.1)

            schema_directive = schema.find_directive(directive.name.value)
            if (_NODE_TO_DIRECTIVE_LOCATION_MAP[node_type]
                    not in schema_directive.locations):
                errors.append(
                    graphql_error_from_nodes(
                        message=
                        f"Directive < @{directive.name.value} > is not used in a valid location.",
                        nodes=[node, directive],
                        path=path,
                        extensions=self._extensions,
                    ))

        return errors
Exemplo n.º 30
0
    def _validate(
        self,
        r_argument_schema_type,
        c_argument_schema_type,
        arg,
        path,
        errors,
        schema,
        value_node=None,
        input_field=None,
    ):  # pylint: disable=too-many-locals,too-many-arguments,too-many-branches,too-complex
        if value_node is None:
            value_node = arg.value

        if isinstance(value_node, VariableNode):
            # Handled by another Validator
            return errors

        if isinstance(c_argument_schema_type, GraphQLNonNull):
            if isinstance(value_node, NullValueNode):
                errors.append(
                    graphql_error_from_nodes(
                        message=
                        f"Argument < {arg.name.value} > of non-null type < {c_argument_schema_type} > must not be null."
                        if not input_field else
                        f"Input Field < {input_field.name.value} > of non-null type < {c_argument_schema_type} > must not be null.",
                        nodes=arg if not input_field else input_field,
                        extensions=self._extensions,
                        path=path,
                    ))
                return errors

            errors = self._validate(
                r_argument_schema_type,
                c_argument_schema_type.gql_type,
                arg,
                path,
                errors,
                schema,
                value_node=value_node,
                input_field=input_field,
            )
            return errors

        if isinstance(c_argument_schema_type, GraphQLList):
            if isinstance(value_node, NullValueNode):
                return errors

            arg_values = ([value_node]
                          if not isinstance(value_node, ListValueNode) else
                          value_node.values)

            for arg_value in arg_values:
                if isinstance(arg_value, VariableNode):
                    continue  # Handled by another validator

                errors = self._validate(
                    r_argument_schema_type,
                    c_argument_schema_type.gql_type,
                    arg,
                    path,
                    errors,
                    schema,
                    value_node=arg_value,
                    input_field=input_field,
                )
            return errors

        if isinstance(value_node, NullValueNode):
            return errors  # Because it's not non null, null node is okay

        if isinstance(r_argument_schema_type, GraphQLScalarType) and (
                r_argument_schema_type.parse_literal(value_node) is
                UNDEFINED_VALUE):
            errors.append(
                graphql_error_from_nodes(
                    message=
                    f"Value {value_node.value} is not of correct type {r_argument_schema_type.name}",
                    nodes=input_field or arg,
                    extensions=self._extensions,
                    path=path,
                ))
            return errors

        if isinstance(r_argument_schema_type, GraphQLInputObjectType):
            errors = self._validate_input_object(
                arg=arg,
                schema_argument_definition=r_argument_schema_type,
                object_node=value_node,
                errors=errors,
                path=path,
                schema=schema,
            )
            return errors

        if isinstance(r_argument_schema_type,
                      GraphQLEnumType) and value_node.value not in [
                          x.value for x in r_argument_schema_type.values
                      ]:
            errors.append(
                graphql_error_from_nodes(
                    message=
                    f"Value {value_node.value} is not a valid value for enum {r_argument_schema_type.name}",
                    nodes=arg,
                    path=path,
                    extensions=self._extensions,
                ))
            return errors

        return errors