-
-
Notifications
You must be signed in to change notification settings - Fork 468
I want to add stats to certain results: the duration the query took and the calculated complexity.
Assumed: best to be done using field middleware?
E.g.: type Query { posts: [Post!]! @paginate(defaultCount: 10) @stats }
Complexity is enabled in lighthouse.php config: e.g. 'max_query_complexity' => 1000.
What I tried: php artisan lighthouse:directive --field stats and selected FieldMiddleware.
This created the stub:
public function handleField(FieldValue $fieldValue, \Closure $next) { // TODO implement the field middleware }
BTW I believe that should be without $next?
(interface says: public function handleField(FieldValue $fieldValue): void;)
Based on the documentation I added:
public function handleField(FieldValue $fieldValue): void { // If you have any work to do that does not require the resolver arguments, do it here. // This code is executed only once per field, whereas the resolver can be called often. // ------------------------ $start = microtime(true); // ------------------------ $fieldValue->wrapResolver(fn (callable $resolver) => function (mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo) use ($resolver, $start) { // Do something before the resolver, e.g. validate $args, check authentication // Call the actual resolver $result = $resolver($root, $args, $context, $resolveInfo); // Do something with the result, e.g. transform some fields // ------------------------ $duration = round((microtime(true) - $start) * 1000, 2); // Duration in ms // Q: how to retrieve the (previously) calculated complexity? // Q: how to add $duration and $complexity to the "extensions" part of the $result? // ------------------------ return $result; }); }
How to retrieve the calculated complexity, and how to add the duration and complexity to the result?
All reactions
Replies: 1 comment 4 replies
Regarding handleField: I fixed the stub with https://github.com/nuwave/lighthouse/releases/tag/v6.45.1, thanks.
Complexity is handled by the underlying GraphQL library webonyx/graphql-php, it just calls into Lighthouse through a mechanism we expose through field directives implementing ComplexityResolverDirective. You would have to dig into their internals to find ways to retrieve that information.
To add stuff to extensions, you need to collect the information somewhere outside your field directive - probably a singleton bound to the request - and handle the BuildExtensionsResponse lifecycle event, see https://lighthouse-php.com/master/api-reference/events.html#lifecycle-events.
All reactions
stub fixed: thanks!
extensions: use BuildExtensionsResponse - this put the pieces together for me, thanks.
I can indeed add stats to my request in the fieldmiddleware directive: request()->merge(['stats' => $stats]);,
and then insert them in BuildExtensionsResponse:
return new ExtensionsResponse(key: 'stats', content: request()->get('stats'));
complexity: webonyx library has method ->getQueryComplexity() in GraphQL\Validator\Rules\QueryComplexity
How to access it inside Lighthouse?
All reactions
I don't see an easy way to access GraphQL\Validator\Rules\QueryComplexity::getQueryComplexity in Lighthouse. The instance is created in Nuwave\Lighthouse\Execution\ValidationRulesProvider::validationRules or \Nuwave\Lighthouse\Execution\CacheableValidationRulesProvider::validationRules and the are used in \Nuwave\Lighthouse\GraphQL::executeParsedQueryRaw, but currently not kept around to access after execution has finished. Perhaps we can collect it after execution and include it in some of the lifecycle events, but I am not sure how that should look?
All reactions
To add the complexity, here's an approach.
In GraphQL.php:
// new: store as variable $validationRules = $this->providesValidationRules->validationRules(); $result = GraphQLBase::executeQuery( $schema, $query, $root, $context, $variables, $operationName, null, // $this->providesValidationRules->validationRules(), $validationRules, ); // new: access the QueryComplexity $validator = $validationRules['GraphQL\Validator\Rules\QueryComplexity'] ?? null; if($validator) { $complexity = $validator->getQueryComplexity(); // example of including the complexity in the result $result->extensions['complexity'] = $complexity; }
The above example always adds the complexity to the extensions array.
It would be preferred to store it somewhere and only use it if/when wanted.
My understanding of Lighthouse internals is not sufficient to recommend where/how to make it available.
Maybe you have suggestions?