graphql-js icon indicating copy to clipboard operation
graphql-js copied to clipboard

Consider exporting collectFields

Open henhal opened this issue 2 years ago • 2 comments

My question on SO has zero answers but describes the problem the best I think: https://stackoverflow.com/questions/73650751/get-list-of-fields-to-resolve-from-a-graphql-resolver-supporting-include-direct

Summary:

Take this query:

query($userId: String!, $loadPhoto: Boolean = false) {
  user(id: $userId) {
    name
    photo @include(if: $loadPhoto)
  }
}

variables:

{
  "userId": "2",
  "loadPhoto": false
}

When implementing the resolver function for user, I want to know if photo is requested or not because the API I'm calling to fetch the user and optionally the user's photo is much more expensive if the photo should be included, but by checking the node list in the info object, it will always be there, regardless of whether the field will be excluded by a directive, so: How can I find the child nodes of a node being resolved, after taking into account any @include directives etc?

The above query of course is for a single object so it could be achieved by having a custom resolver for user that delays execution using a DataLoader or similar, and then sets a flag inside a resolver function for the photo field. But it quickly becomes very complex, especially if the user is in turn part of a list of users, etc etc. I started an implementation using a DataLoader which had to group my requests fed to the loader in three steps to actually find what users I should resolve and what fields. It's simply just a mess.

So why not offer a way from the graphql module to get the evaluated list of child nodes?

It seems like https://github.com/graphql/graphql-js/blob/a24a9f35b876bdd0d5050eca34d3020bd0db9a29/src/execution/execute.ts#L531 does this as part of the execution, i.e., collects all fields with respect to directives, because I've seen that a resolver function for a field failing an @Include directive is never called. So perhaps this curated list of fields could be included in the info object passed to each resolver or something, alongside the "raw" node list? Or even simply extracted as a public utility function of the library for getting the child fields of a given field including any applied directives?

henhal avatar Sep 23 '22 13:09 henhal