Skip to content

Navigation Menu

Sign in
Sign up

add stats to extensions array (e.g. duration and complexity)? #2634

Unanswered
wivaku asked this question in Q&A
Discussion options

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?

You must be logged in to vote

Replies: 1 comment 4 replies

Comment options

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.

You must be logged in to vote
4 replies
Comment options

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?

Comment options

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?

Comment options

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?

Comment options

@wivaku Please review #2637.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet
2 participants

AltStyle によって変換されたページ (->オリジナル) /