-
Notifications
You must be signed in to change notification settings - Fork 150
Allow scalars as resolver return type #152
Description
Problem statement
All resolvers in Magento must implement Resolver interface, which in its turn forces the instance of \GraphQL\Deferred
to be returned by each resolver. To be precise, Magento wrapper for deferred, \Magento\Framework\GraphQl\Query\Resolver\Value
, must be returned.
/**
* Fetches the data from persistence models and format it according to the GraphQL schema.
*
* @param \Magento\Framework\GraphQl\Config\Element\Field $field
* @param $context
* @param ResolveInfo $info
* @param array|null $value
* @param array|null $args
* @throws \Exception
* @return Value
*/
public function resolve(
Field $field,
$context,
ResolveInfo $info,
array $value = null,
array $args = null
) : Value;
The main reason for using deferred in GraphQL is to optimize performance by solving N+1 problem where it exists.
An example of valid deferred usage in Magento can be found in \Magento\CatalogGraphQl\Model\Resolver\Product::resolve
.
In all other cases, when there is no need to solve N+1 problem, we end up with boilerplate code like:
$result = function () use ($data) {
return $data;
};
return $this->valueFactory->create($result);
Response type unification is one of the reasons why deferred was made the only possible return type for resolvers. However, after implementing more resolvers it became obvious that current design just adds unnecessary complexity to the resolver implementations.
Proposed solution
In addition to deferred, allow scalars and arrays of scalars as return types for \Magento\CatalogGraphQl\Model\Resolver\Product::resolve
.
It will also be easier to customize resolver with plugins, if it returns array/scalar instead of deferred
object.
Action items
- Modify existing resolvers, which have boilerplate code and do not require solving N+1 problem
Change
public function resolve(
Field $field,
$context,
ResolveInfo $info,
array $value = null,
array $args = null
) : Value;
to
public function resolve(
Field $field,
$context,
ResolveInfo $info,
array $value = null,
array $args = null
);
Also, replace boilerplate code in resolvers
$result = function () use ($data) {
return $data;
};
return $this->valueFactory->create($result);
with
return $data;
- Document the decision and make sure that all new resolvers return deferred only when necessary. Can just mark PR with "requires-documentation" label to leave this part for Magento's documentation team.