Using the graphql module from Node.JS, I have implemented an API. For a given type of object, some fields are expensive to resolve, so I don't want to always resolve them, only for the results to be thrown away by the GraphQL engine if the client didn't request them.
Example: Let's say the API can return users, and each user has a number of properties. One property is photo which is expensive to resolve.
With a query like this, the photo should be resolved by the GraphQL server:
user(id: 2) {
name
photo
}
but with a query like this, we can skip resolving the photo:
user(id: 2) {
name
}
I've implemented this by having the resolver for the User type query the info object contained in the GraphQL context passed to each resolver function, to check if the current field node has any child node named photo.
This works so far, until I realized some clients are using variables with @include directives:
query($userId: String!, $loadPhoto: Boolean = false) {
user(id: $userId) {
name
photo @include(if: $loadPhoto)
}
}
variables:
{
"userId": "2",
"loadPhoto": false
}
In this case, the field node will have a child called photo, but it has a directive node with a if condition connected to a variable node. If a client calls this with loadPhoto: false the server will still fetch the photo, only for the GraphQL engine to throw it away when formatting the response. Blurgh!
While the logic to determine whether the photo should be dynamically resolved or not can of course be implemented by investigating the directive nodes for the field etc, I'm thinking there must be a better way than doing this manually. It's getting complex already. Is there no utility function in the graphql library that does this, considering it has to do it somewhere already in order to know whether the photo field should be included in the response? Is there a function to call to get a list of the child fields of a particular node that will be returned from the query, after directives, variables etc have been processed, to avoid resolving expensive values that will be thrown away later on?