Reputation: 1117
I'm wondering why my arguments seem to be switched around inside my GraphQL resolver. I'm using express-graphql.
Example of one resolver:
getLocalDrivers: async (parent, args, ctx) => {
console.log(ctx);
}
I've written the argument names as they appear in the docs: http://graphql.org/learn/execution/
But when I debug and inspect the objects, it seems the args object is 1st, the context is 2nd, and the parent/root is 3rd.
parent:
Object {location: "020202"}
args:
IncomingMessage {_readableState: ReadableState, readable: false, domain: null, …}
context:
Object {fieldName: "getLocalDrivers", fieldNodes: ....
Some server code:
app.use(
"/graphql",
graphqlHTTP({
schema,
graphiql: true,
rootValue: rootResolver
})
);
My rootResolver:
var rootResolver = {
getLocalDrivers: async (obj, args, ctx) => {
console.log(ctx);
}
}
Schema:
var { buildSchema } = require("graphql");
var schema = buildSchema(`
type Query {
getLocalDrivers(location: String): [Driver]
}
type Driver {
name: String
location: String
}`);
Upvotes: 5
Views: 2821
Reputation: 84667
If a resolve
function is defined for a field, when GraphQL resolves that field, it will pass four parameters to that function:
obj
or root
)If a resolve function is absent for a particular field, GraphQL will utilize the default resolver, which simply searches for a property on the parent field and uses that if it's found.
So your getLocalDrivers
query could return an array of Driver
objects, and as long as the Driver
object has a name
property, the name
field will resolve to that property's value.
Coincidentally, the name
property on that Driver
object could also be a function. In that case, GraphQL would call that function to get its return value. And very much like a resolver, GraphQL passes some information to this function as parameters, namely 1) the arguments, 2) the context and 3) the info object. When fields are resolved in this way, the "obj" parameter is omitted.
Ok, so what about the root?
The root object is just the object that serves as the "parent field value" that's given to queries and mutations, which are fields like everything else.
So, if you haven't defined a "resolve" function for getLocalDrivers
(because you compiled you schema with buildQuery
for example), GraphQL will utilize the default resolver, and use the root object you passed in as the "parent field value". It sees a getLocalDrivers
, but as described above, because this a function, it calls that function with the above-mentioned three parameters.
So what's the lesson here?
Don't use root.
Seriously. Either define your schema as an object, or if you want to write the schema out using GraphQL schema language, use graphql-tools -- makeExecutableSchema
makes dealing with resolvers much much easier.
const typeDefs = `
type Query {
getLocalDrivers(location: String): [Driver]
}
type Driver {
name: String
location: String
}
`
const resolvers = {
Query: {
getLocalDrivers: (obj, args, ctx) => {
console.log({obj, args, ctx})
}
}
}
const schema = makeExecutableSchema({
typeDefs,
resolvers,
})
Upvotes: 4