示例#1
0
def perform_operation_validation(request):
    errors = []
    operations = {}
    fragments = {}
    for definition in request.ast.definitions:
        if isinstance(definition, OperationDefinition):
            if definition.name in operations:
                raise GraphQLError('Non-unique operation name: {}'.format(
                    definition.name))
            else:
                operations[definition.name] = definition
        elif isinstance(definition, FragmentDefinition):
            if definition.name in fragments:
                raise GraphQLError('Non-unique fragment name: {}'.format(
                    definition.name))
            else:
                fragments[definition.name] = definition

    if request.operation_name:
        if request.operation_name not in operations:
            raise GraphQLError('No operation found called `{}`'.format(
                request.operation_name))
    else:
        if len(operations) > 1:
            raise GraphQLError(
                'Multiple operations provided but no operation name')
        elif len(operations) == 0:
            raise GraphQLError('At least one operation must be provided')

    return errors
def test_related_object_args():
    document = '''
    {
        episode (number: 4) {
            characters (types: [null]) {
                name
            }
        }
    }
    '''
    request = Request(document, schema)
    request.validate()
    assert request.errors == [
        GraphQLError("Non-null argument 'types' on 'characters' is null"),
    ]

    document = '''
    {
        episode (number: 4) {
            characters {
                appears_in {
                    characters(types: [null]) {
                        name
                    }
                }
            }
        }
    }
    '''
    request = Request(document, schema)
    request.validate()
    assert request.errors == [
        GraphQLError("Non-null argument 'types' on 'characters' is null"),
    ]
示例#3
0
 def get_value(self):
     raw_value = self.get_raw_value()
     if not self.null and raw_value is None:
         raise GraphQLError(
             'Field {} returned null but is not nullable'.format(self.name))
     if hasattr(self.type_, 'coerce_result'):
         try:
             return self.type_.coerce_result(raw_value)
         except ValueError:
             raise GraphQLError('Cannot coerce {} ({}) to {}'.format(
                 type(raw_value).__name__, raw_value,
                 self.type_.object_name))
     return raw_value
    def validate(self):
        """
        Used to perform validation of a query before execution.
        Errors produced from validation can be accessed
        from ``request.errors``.

        If a Request object has been validated once,
        additional calls will not re-run validation.
        """
        if self._validated:
            return

        self._validated = True

        try:
            self._errors.extend(perform_operation_validation(self))
            if self._errors:  # If the request is invalid, stop validation
                return

            self.query_root = self.schema.get_query_root(self)
            self._errors.extend(perform_argument_validation(self.query_root))

        except Exception as e:
            if not isinstance(e, GraphQLError):
                e = GraphQLError(e)
            self.errors.append(e)
示例#5
0
    def fields(self):
        if not hasattr(self, '_fields'):
            self._fields = OrderedDict()

            selections = get_selections(
                selections=self.ast.selections,
                fragments=self.fragments,
                object_type=self.__class__,
            )

            # Copy the field instances so that obj instances have
            # isolated field instances that they can modify safely.
            # Only copy field instances that are selected.
            # If the field doesn't exist, create a dummy field that returns None
            for selection in selections:
                try:
                    field = copy.deepcopy(
                        self._declared_fields[selection.name])
                except KeyError:
                    self.errors.append(
                        GraphQLError('{} does not have field {}'.format(
                            self.object_name, selection.name)))
                    field = Field()
                    field.type_ = MockScalar

                self._fields[selection.name] = field
                field.bind(selection=selection, obj=self)
        return self._fields
示例#6
0
def validate_non_null_args(field_name, field):
    """
    NonNull arguments are required and cannot be null
    """
    errors = []
    for arg_name, arg_type in field.arguments.items():
        if not arg_type.null and arg_name not in field.selection_arguments:
            errors.append(
                GraphQLError(
                    "Required argument '{}' on '{}' is missing".format(
                        arg_name, field_name)))
            continue

        arg_value = field.selection_arguments.get(arg_name)
        if not non_null_arg_provided(arg_type, arg_value):
            errors.append(
                GraphQLError("Non-null argument '{}' on '{}' is null".format(
                    arg_name, field_name)))
    return errors
def test_null_list_item():
    document = '''
    {
        nested(arg: [null])
    }
    '''
    request = Request(document, test_schema)
    request.validate()
    assert request.errors == [
        GraphQLError("Non-null argument 'arg' on 'nested' is null"),
    ]
def test_missing_int():
    document = '''
    {
        nested(arg: [[]])
    }
    '''
    request = Request(document, test_schema)
    request.validate()
    assert request.errors == [
        GraphQLError("Non-null argument 'arg' on 'nested' is null"),
    ]
示例#9
0
    def get_resolver_args(self):
        if not self._bound:
            raise GraphQLError(
                'Usage exception: must bind Field to a selection and object first'
            )

        resolver_args = {name: None for name in self.arguments}

        for name, value in self.selection_arguments.items():
            arg_type = self.arguments.get(name)
            if not arg_type:
                continue
            try:
                arg_value = arg_type.coerce_input(value)
                resolver_args[name] = arg_value
            except ValueError:
                error = 'Query error: Argument {} expected a {} but got a {}'.format(
                    name, type(arg_type), type(value))
                raise GraphQLError(error)
        return resolver_args
def test_missing_arg():
    document = '''
    {
        nested
    }
    '''
    request = Request(document, test_schema)
    request.validate()
    assert request.errors == [
        GraphQLError("Required argument 'arg' on 'nested' is missing")
    ]
示例#11
0
    def __init__(self, document, schema, variables=None, operation_name=None):
        """
        Creates a Request object that can be validated and executed.

        :param document: The query string to execute.

            e.g. ``"query episodeNames { episodes { name } }"``

        :param schema: A Schema object to run the query against
        :param variables: A ``dict`` of variables to pass to the query (optional)
        :param operation_name: If the document contains multiple named queries,
            the name of the query to execute (optional)
        """
        self.document = document
        self.variables = variables or {}
        self.operation_name = operation_name
        self.schema = schema
        self._validated = False
        self._errors = []
        self.query_root = None
        parser = GraphQLParser()

        if not self.document:
            self._errors.append(GraphQLError('Must provide query string.'))
        else:
            try:
                self.ast = parser.parse(self.document)
            except (graphql_exceptions.LexerError,
                    graphql_exceptions.SyntaxError) as e:
                self.ast = None
                self._errors.append(
                    GraphQLError(
                        'Parse error: {}'.format(e),
                        line=e.line,
                        column=e.column,
                    ))

        # Additional errors are meaningless if we couldn't parse the document
        if self._errors:
            self._validated = True
示例#12
0
    def execute(self):
        data = {}
        for name, field in self.fields.items():
            try:
                value = field.get_value()
                self.errors.extend(field.errors)
            except Exception as e:
                value = None
                self.errors.append(
                    GraphQLError('Error resolving {}: {}'.format(name, e)))
            data[name] = value

        return data, self.errors
def test_null_scalar():
    document = '''
    {
        episode(number: null) {
            name
        }
    }
    '''
    request = Request(document, schema)
    request.validate()
    assert request.errors == [
        GraphQLError("Non-null argument 'number' on 'episode' is null"),
    ]
def test_missing_scalar():
    document = '''
    {
        episode {
            name
        }
    }
    '''
    request = Request(document, schema)
    request.validate()
    assert request.errors == [
        GraphQLError("Required argument 'number' on 'episode' is missing"),
    ]
def test_non_existent_field(starwars_data):
    document = '''
        {
            episode (number: 4) {
                name
                other_field
            }
        }
        '''
    request = Request(document, schema)
    data, errors = request.execute()
    assert data == {"episode": {"name": "A New Hope", "other_field": None}}
    assert errors == [
        GraphQLError('Episode does not have field other_field'),
    ]
def test_null_int():
    document = '''
    {
        nested(arg: [[null]])
    }
    '''
    request = Request(document, test_schema)
    request.validate()
    assert request.errors == [
        GraphQLError("Non-null argument 'arg' on 'nested' is null"),
    ]

    document = '''
    query nestedArgQuery($int: Int){
        nested(arg: [[$int]])
    }
    '''
    variables = {'int': None}

    request = Request(document, test_schema, variables=variables)
    request.validate()
    assert request.errors == [
        GraphQLError("Non-null argument 'arg' on 'nested' is null"),
    ]
def test_non_existent_episode(starwars_data):
    document = '''
        {
            episode (number: 12) {
                name
            }
        }
        '''
    request = Request(document, schema)
    data, errors = request.execute()
    assert data == {"episode": None}
    assert errors == [
        GraphQLError(
            'Error resolving episode: Episode matching query does not exist.'),
    ]
def test_blank_query(starwars_data):
    document = ''
    request = Request(document, schema)
    assert request.errors == [
        GraphQLError('Must provide query string.'),
    ]