On this page you will find information about what GraphQL resolvers are and how they work. This page will be most useful for developers that are already familiar with GraphQL.
Resolvers exist in any GraphQL implementation, not just WPGraphQL, but how they are implemented and the API for working with them varies from language to language, which is why you find this page under the WPGraphQL Concepts section.
A GraphQL Schema consists of Types and Fields, which declares what is possible to be asked for. Resolvers are the functions that execute when a field is asked for.
When registering a field to theWPGraphQL Schema defining a resolver is optional.
Registering a field without a resolver:
Below is an example of registering a field to the Schema without a resolve function defined.
This will add a
hello field to the RootQuery in the Schema and will allow this query to be executed:
However, if we were to execute this, the results would be a
null value for the hello field, like so:
This is because we registered the field to the Schema, but did not define a resolver.
Registering a field with a resolver:
Below is the same example as above, but with a resolve function included.
Here we defined a
resolve function and have it return the string
world. So now, if the above query were executed again, the results would be:
In most cases, fields in a GraphQL schema will not simply resolve with a hard-coded string, like the above example. Resolvers often need more information to properly resolve.
In GraphQL, all resolve functions get passed 4 function arguments which the resolve function can use to during execution:
- \$root (mixed): This first argument is whatever previous object or array was being resolved. In this case, our field is at the Root, so it's passed a null value. If our field was on a
Posttype, for example, it would be passed an instance of a Post (
- \$args (array): The 2nd argument is the args on the field. The field we registered doesn't have any args, but if it did, the input values of the args would be passed here as an array.
- \$context (AppContext): The 3rd argument is an instance of the AppContext class. This class is passed to every resolver and is used for things like DataLoading so resolvers can pull from centrally cached data instead of fetching fresh data, etc.
- \$info (ResolveInfo): The 4th argument is an instance of ResolveInfo, which can be used to determine things about where in the resolveTree the field is, what the Parent Type is, what fields have been selected on this Type, and more.
To better understand how these function arguments work, let's add an argument to the
hello field to accept a name as input:
Here we added an argument named
name that accepts a string.
In the resolve function, we added the 4 function arguments to the function call, and we check to see if the
name argument was passed through on the field, and if so, we return the value for the resolver, and default to
world if no value was input.
Now we could query like so:
And we would get the following result:
You may find yourself in a situation where you need to override an existing resolver. There are many ways to accomplish this. Let's look at some examples:
During GraphQL execution, the
graphql_pre_resolve_field filter executes prior to the default field resolution. If this filter returns a value, it will return the value and skip executing the default resolver.
This can be used like so:
This first checks if the filter is being applied to the
hello field on the
RootQuery type, and if it is it returns a string of "custom value".
The same query for the
hello field would now return the following:
NOTE: We used
strtolower()to convert the type name to lowercase because behind the scenes WPGraphQL converts type names to lowercase strings, so it's always safest to check type names using all lowercase characters.
This filter is similar to above, but the difference is that this filter runs after default execution of the resolve field has already run.
Let's say we wanted to prefix the results of the
hello field with something custom.
We could do that like so:
Now executing the following query:
Would return the following, with our prefix before the existing results of the query:
Below is an example of replacing the field's resolve function altogether.
Let's say we wanted the
hello field to always return the string "goodbye", no matter what.
We could replace the resolve function for the field like so:
Now the same query for the hello field (with or without an input argument supplied to the query) would return the following: