evo-company/hiku

Support optional GraphQL arguments for QueryValidator

playpauseandstop opened this issue · 3 comments

Long story short: GraphQL arguments can be optional without default value.


From GraphQL documentation,

Arguments can be either required or optional. When an argument is optional, we can define a default value - if the unit argument is not passed, it will be set to METER by default.

From GraphQL specification,

Arguments can be required. If the argument type is non‐null the argument is required and furthermore the explicit value null may not be provided. Otherwise, the argument is optional.


But in Hiku there is no way to provide optional arguments, when using QueryValidator cause of,

    def visit_option(self, obj):
        default = _undefined if obj.default is None else obj.default
        value = self._options.get(obj.name, default)
        if value is _undefined:
            node, field = self.for_
            self.errors.report('Required option "{}.{}:{}" is not specified'
                               .format(node, field, obj.name))

Hiku enforces all options to be required or use non-null default values, which not conforms GraphQL specification cited above. As result right now there is impossible to mix QueryValidator and optional arguments.


Code to reproduce,

    Field(
        'count_documents',
        Integer,
        resolve_count_documents,
        options=[
            Option('search', String, default=None),
            Option('folder_id', Integer, default=None),
            Option('status_id', Integer, default=None),
            Option('signatures_to_finish', Integer, default=None),
            Option('gte', String, default=None),
            Option('lte', String, default=None),
        ]),

Works as expected for { count_documents } query without QueryValidator, but returns,

{
    'data': None,
    'errors': [
        {'message': 'Required option "root.count_documents:search" is not specified'},
        {'message': 'Required option "root.count_documents:folder_id" is not specified'},
        {'message': 'Required option "root.count_documents:status_id" is not specified'},
        {'message': 'Required option "root.count_documents:signatures_to_finish" is not specified'},
        {'message': 'Required option "root.count_documents:gte" is not specified'},
        {'message': 'Required option "root.count_documents:lte" is not specified'}
    ]
}

when Hiku handler contains,

        validator = QueryValidator(graph)
        validator.visit(query)
        if validator.errors.list:
            return web.json_response({'data': None, 'errors': ...})

Right now it is possible to handle this case by providing non-null, but some empty values for arguments of count_documents field (like '') or by omitting QueryValidator at all, but I'd prefer if Hiku works with GraphQL arguments due to specification and does not enforce all arguments to be required.

Agreed, the problem is that Hiku uses None as an indicator of that there are no default value. Should be trivial to fix, I will look into this as soon as I can.

Fixed in 7118e40, made a release candidate hiku==0.3.9rc1 for you for further testing, here is how to specify properly non-required options for GraphQL:

Option('search', Optional[String], default=None)

And there is an interesting case with default values:

Option('foo', Integer, default=123)

This option is totally valid in Hiku: it is not required, and if it will be missing in query, Hiku will use default value 123 and won't accept null values. But in GraphQL this option will be required. As your quote from specification says:

If the argument type is non‐null the argument is required

So GraphQL here is slightly less flexible and Hiku maybe is slightly more complicated, as it gives you ability to distinguish when value is null and when it is missing.

Updated Hiku to 0.3.9rc1 and can confirm that optional arguments work as expected with query validation.

Thanks!