GraphQL has three predefined ROOT RESOLVERS, called Query, Mutation, and Subscription.
all other resolvers sit within these three categories to do business logic things.
resolvers are like Redux's reducers, they are the ONE AND ONLY ONE place to write logic between your result param (from your database) and your graphql response (what you send back from your GraphQL API).
this is where you make connections to the database and do crud
this is where you do your api requests if you need them
it is the actual implementation of the GraphQL schema.
and this set of rules are enforced by whatever GraphQL engine your code is running on, to make sure everybody holds up their end of the deal.
Query and Mutation Function signatures go like this:
const someQuery = (parent, args, context, info) => {
// code the get the value
return value
}it looks like this:
const resolvers = {
// Query, Mutation and Subscription keys are reserved, graphql knows what to do with these
Query: {
someQuery: someQuery, // from above
info: () => `this is the API endpoints of a Hacker News Clone`,
feed: () =>
// your logic to make querying for the feed happen
[...DB.entries()].map(entry => ({
id: entry[0],
...entry[1],
})),
link: (parent, args) => {
// your logic for making querying for a link by id happen
return DB.get(args.id)
},
},
Mutation: {
createLink: (parent, args) => {
// your logic to make post happen
const id = `link-${idCount++}`
const link = {
description: args.description,
url: args.url,
}
DB.set(id, link)
return { id, ...link }
},
updateLink: (parent, args) => {
// your logic to make updateLink happen
if (DB.has(args.id)) {
const original = DB.get(args.id)
DB.addToDB(
args.id,
args.url || original.url,
args.description || original.description
)
return DB.get(args.id)
} else {
return null
}
},
deleteLink: (parent, args) => {
// your logic to make deleteLink happen
if (DB.has(args.id)) {
const data = {
id: args.id,
...DB.get(args.id),
}
DB.delete(args.id)
return data
} else {
return null
}
},
},
}Subscription Function signatures go like this:
const someSubscription = {
subscribe: (parent, args, context, info) => {
// code the get an Async Iterator object
return AsyncIteratorThing
},
resolve: (payload) => {
return payload
}
}const resolvers = {
Query: {}, // ...
Mutation: {}, // ...
Subscription: {
someSubscription: someSubscription
}
}Resolvers for subscriptions are slightly different than the ones for queries and mutations:
Rather than returning any data directly, they return an AsyncIterator which subsequently is used by the GraphQL server to push the event data to the client. Subscription resolvers are wrapped inside an object and need to be provided as the value for a subscribe field. You also need to provide another field called resolve that actually returns the data from the data emitted by the AsyncIterator.
the following is taken from the ref article and then extended with my notes.
A resolver function takes four arguments (in that order):
context paramlike so:
const resolvers = {
Query: {
feed: (parent, args, context, info) => {
// your logic for returning a list of links
},
},
}Why was the 'User' type redefined in the application schema when it's already part of the Prisma database schema and could be imported from there?