Pass arguments to callables for resolving StreamField block values #322
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Overview
Grapple already supports callables in StreamFields (#220). This allows us to dynamically compute what to return when querying a field of a StreamField block.
Unfortunately, Grapple does now allow us to pass arguments to those callables. Such a functionality would be useful, however, when we want make the computation of the query result depend on some parameters provided by the user.
This PR implements support for callables in StreamFields so that we can make queries like the following, where
CustomBlock
is a StreamField block for which we want to add a GraphQL fieldcustomizedField
that takes a string argumentextraArg
.Implementation
When using
graphql_fields
for declaring the custom fields for a StreamField block, the field types are generated by the existing functionget_field_type(item)
, whereitem
can be aGraphQLField
or a tuple(field, wrapper)
.item
is aGraphQLField
, then the field is generated asgraphene.Field(field_type)
, wherefield_type
is the appropriate type. Note that this does not declare any arguments.item
is a tuple(field, wrapper)
, then the field is generated aswrapper(field_type)
. With this mechanism, we can specify a wrapper that generates something likegraphene.Field(field_type, extra_arg=graphene.String())
.Unfortunately the following does not work:
There are two reasons this does not work:
Firstly, Grapple does not take the field wrappers into account when generating resolvers. The resolvers are generated in
grapple.actions.build_streamfield_type
like this (abridged):Note that
graphql_field=item
is passed tocustom_cls_resolver
. This works ifitem
is aGraphQLField
but not if it is a tuple(field, wrapper)
. (Grapple will fall back to thestreamfield_resolver
, which we do not want.) I suspect this is an oversight and fixed it by replacinggraphql_field=item
withgraphql_field=field
.Secondly, when we define a field with custom arguments and implement the resolver with a callable,
custom_cls_resolver
does not supply the user-provided values for these arguments to the callable. This is easily fixed by passingkwargs
along.I added tests for this. Hopefully it's fine. Happy to improve further.