Ali Shakiba
Ali Shakiba

Reputation: 21277

GraphQL: What is rootValue specification that is passed to execute?

I use express-graphql which is initialized with rootValue and passes it to GraphQL's execute function. I wonder what is rootValue's specification. I have seen some simple examples but I'm interested in full specification.

Upvotes: 3

Views: 1627

Answers (1)

Daniel Rearden
Daniel Rearden

Reputation: 84777

The rootValue is specific to the javascript implementation and, to my knowledge, not something that's explicitly required by the official specification.

This is the type definition for the resolve function (or resolver) provided in the docs:

type GraphQLFieldResolveFn = (
  source?: any,
  args?: {[argName: string]: any},
  context?: any,
  info?: GraphQLResolveInfo
) => any

The first parameter passed to the resolver is the "source", "root" or "parent" value. A field is always associated with some Object type. The "source" value is simply the value that the field that returned that Object type resolved to. For example, given a query like:

{
  user(id: 1) {
    location {
      city
    }
  }
}

The user field returns an Object type. When it resolves, the resolved value is passed to the location resolver as the "source". Similarly, when location resolves, the resolved value is passed to the resolvers for all of its requested fields, like city.

In our example, user is field, like any other, it just happens to be on the Query type, but that type itself is still an Object type. Because it's a field, it's resolved by calling the resolver associated with it. But because it's at the root of the query, there is no "source" value. This is the only purpose of the rootValue you pass to execute -- it gets passed to every root level resolver as the "source" value.

In other words, whatever you set rootValue will be passed as the first parameter to the resolver for every field of the Query, Mutation and Subscription types.

Since the rootValue is only available to root level resolvers, it's very limited in its use. Any data that should be available to all resolvers should be included in the context instead.

For completion's sake, I should note that there are examples out there that show how to create a schema using SDL and buildSchema. Because buildSchema does not offer a way to provide resolvers for any fields, these examples provide a way to resolve the root level fields by passing in resolver functions through the rootValue. This works because, as the docs note:

[If] a resolver function is not provided, then the default resolver is used, which looks for a method on source of the same name as the field. If found, the method is called with (args, context, info).

However, again, the rootValue is only available to fields on the root types (Query, Mutation and Subscription). If you create a schema this way, you won't be able to define resolvers for fields on any other types. In other words, don't do it. See this answer for more details.

Upvotes: 6

Related Questions