Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to know which fields were requested in a GraphQL query?

I have written a GraphQL query which like the one below:

{
  posts {
    author {
      comments
    }
    comments
  }
}

I want to know how can I get the details about the requested child fields inside the posts resolver.

I want to do it to avoid nested calls of resolvers. I am using ApolloServer's DataSource API.

I can change the API server to get all the data at once.

I am using ApolloServer 2.0 and any other ways of avoiding nested calls are also welcome.

like image 870
WitVault Avatar asked Mar 04 '19 13:03

WitVault


People also ask

What does GraphQL query return?

After being validated, a GraphQL query is executed by a GraphQL server which returns a result that mirrors the shape of the requested query, typically as JSON.

What is __ Typename in GraphQL?

The __typename field returns the object type's name as a String (e.g., Book or Author ). GraphQL clients use an object's __typename for many purposes, such as to determine which type was returned by a field that can return multiple types (i.e., a union or interface).

What is GraphQL field resolver?

Resolvers are per field functions that are given a parent object, arguments, and the execution context, and are responsible for returning a result for that field. Resolvers cannot be included in the GraphQL schema language, so they must be added separately. The collection of resolvers is called the "resolver map".


2 Answers

You'll need to parse the info object that's passed to the resolver as its fourth parameter. This is the type for the object:

type GraphQLResolveInfo = {
  fieldName: string,
  fieldNodes: Array<Field>,
  returnType: GraphQLOutputType,
  parentType: GraphQLCompositeType,
  schema: GraphQLSchema,
  fragments: { [fragmentName: string]: FragmentDefinition },
  rootValue: any,
  operation: OperationDefinition,
  variableValues: { [variableName: string]: any },
}

You could transverse the AST of the field yourself, but you're probably better off using an existing library. I'd recommend graphql-parse-resolve-info. There's a number of other libraries out there, but graphql-parse-resolve-info is a pretty complete solution and is actually used under the hood by postgraphile. Example usage:

posts: (parent, args, context, info) => {
  const parsedResolveInfo = parseResolveInfo(info)
  console.log(parsedResolveInfo)
}

This will log an object along these lines:

{
  alias: 'posts',
  name: 'posts',
  args: {},
  fieldsByTypeName: {
    Post: {
      author: {
        alias: 'author',
        name: 'author',
        args: {},
        fieldsByTypeName: ...
      }
      comments: {
        alias: 'comments',
        name: 'comments',
        args: {},
        fieldsByTypeName: ...
      }
    }
  }
}

You can walk through the resulting object and construct your SQL query (or set of API requests, or whatever) accordingly.

like image 79
Daniel Rearden Avatar answered Sep 24 '22 11:09

Daniel Rearden


Here, are couple main points that you can use to optimize your queries for performance.

  1. In your example there would be great help to use https://github.com/facebook/dataloader. If you load comments in your resolvers through data loader you will ensure that these are called just once. This will reduce the number of calls to database significantly as in your query is demonstrated N+1 problem.
  2. I am not sure what exact information you need to obtain in posts ahead of time, but if you know the post ids you can consider to do a "look ahead" by passing already known ids into comments. This will ensure that you do not need to wait for posts and you will avoid graphql tree calls and you can do resolution of comments without waiting for posts. This is great article for optimizing GraphQL waterfall requests and might you give good idea how to optimize your queries with data loader and do look ahead https://blog.apollographql.com/optimizing-your-graphql-request-waterfalls-7c3f3360b051
like image 20
David Mraz Avatar answered Sep 26 '22 11:09

David Mraz