How to get a type of a single resolver function? - graphql-codegen

I wondering if it possible to get a type of single resolver function generated by graphql-codegen?
I also use graphql-modules with graphql-modules-preset. All of these libraries provide me a list of automatically generated types, but unfortunately I can't find a type of a single resolver function.
I would expected something like this:
const createRepository: CreateRepositoryMutationResolver = (parent, args, context, info) => {
// Code goes here
}
where all arguments of the function (parent, args, context and info) are strongly typed.
Instead, I could only find this way of providing types
const createRepository: ResolverFn<{}, MutationCreateRepositoryInput, GraphQLContext, GraphQLInfo> = (parent, args, context, info) => {
// Code goes here
}
I would like to skip this step where I need to fill in generics of ResolverFn
Any ideas?
P.S. If I declare all resolvers in single file, then types work as expected.
const resolvers: RepositoryModule.Resolvers = {
Mutations: {
createRepository: (parent, args, context, info) => {
// all types of all arguments work as expected
},
removeRepository: (parent, args, context, info) => {
// all types of all arguments work as expected
}
}
}
But I want to move each resolver into separate file

I did a little research on the types that were generated by graphql-codegen and found that all properties of Resolvers interface as well as all of its children are optional. It means that I can re-use this interface, but specify only resolvers that I need in the separate files
First file
// create-repository.resolver.ts
import { RepositoryModule } from '../../generated-types/module-types'
const resolvers: RepositoryModule.Resolvers = {
Mutation: {
createRepository: async (parent, args, context, info) => {
// code goes here
}
}
}
export default resolvers
second file
// create-repository.resolver.ts
import { RepositoryModule } from '../../generated-types/module-types'
const resolvers: RepositoryModule.Resolvers = {
Mutation: {
removeRepository: async (parent, args, context, info) => {
// code goes here
}
}
}
export default resolvers
and after, in a module, I can join all resolvers by loadFileSync
import { loadFilesSync } from '#graphql-tools/load-files'
import { createModule } from 'graphql-modules'
import { join } from 'path'
const resolvers = loadFilesSync(join(__dirname, './**/*.resolver.ts'), { useRequire: true })
export const repositoryModule = createModule({
id: 'repositoryModule-module',
dirname: __dirname,
resolvers: resolvers,
...
})
I'm not sure if this is the correct way to use this interface, but it works for me

Related

Using composeResolvers with an array of resolvers

Is it possible to pass an array of resolvers into composeResolvers from "#graphql-tools/resolvers-composition". If I do something like composeResolvers(authorsResolvers, resolversComposition); it works however if I try to pass in all my resolvers, composeResolvers(resolvers, resolversComposition);, it doesn't work.
const rootResolver = {};
const resolvers = [rootResolver, authorsResolvers, booksResolvers];
const isAuthenticated =
() =>
(next: any) =>
async (root: any, args: any, context: any, info: any) => {
if (!context.currentUser) {
throw new Error("You are not authorized");
}
return next(root, args, context, info);
};
const resolversComposition = {
"*.*": [isAuthenticated()],
};
const composedResolvers = composeResolvers(resolvers, resolversComposition);
export default composedResolvers;
No, composeResolvers expects an object as the first argument.
If all valid resolver objects, you could do something like this:
const resolvers = {...rootResolver, ...authorsResolvers, ...booksResolvers};
But make sure to do the necessary adjustments in case they have overlapping attributes, otherwise the last one will override the former.

How to access data loaded with gatsby-source-graphql in a resolver?

In Gatsby how can I create a resolver that uses data loaded by the gatsby-source-graphql plugin. I'm having trouble figuring out to query the data inside a resolver. Can this be done? Any advice on what I'm missing would be helpful.
something like this in gatsby-node.js ...
exports.createResolvers = ({ createResolvers }) => {
createResolvers({
Query: {
getStructure: {
type: `Structure`,
async resolve(source, args, context, info) {
// assume gatsby-config.js is configured with gatsby-source-graphql and this node exists
const myGraphQlApiNode = await context.nodeModel.runQuery({
query: {
filter: {
fieldName: { eq: "myGqlApi" }
}
},
type: "GraphQLSource"
});
const someGqlApiData = // query all of type MyGqlApi_SomeTypeFromGqlApi loaded via gatsby-source-graphql
return toStructure(someGqlApiData)
}
}
}
});
};
It may be an unofficial solution
Because gatsby doesn’t provide graphql method in createResolvers but do it on createPages
you can do st like this
in gatsby-node.js
let apiHelperGraphql = null
exports.createPages = async ({ actions, graphql }) => {
// steal it from create Pages
apiHelperGraphql = graphql
}
exports.createResolvers = ({ createResolvers }) => {
// and call it here, do what ever you want
apiHelperGraphql(`same as grapql syntax`)
}

Is there a way to reconstruct a query from info of a graphql.js resolver?

let root = {
books: (parent, args, info) { ... }
}
let res = await graphql(schema, `{ books { title } }`, root);
Is there already a helper function in graphql.js to reconstruct the query using the info?
yes there is a way:
When you use graphqlHTTP from express-graphql, the 3rd argument is graphQLParams, you can give it the context for instance.
graphqlHTTP(async (request, response, graphQLParams) => ({
schema,
graphiql: true,
context: graphQLParams
}))
Then in your schema definition, you can grab the context from any resolve function like this:
products: {
type: new GraphQLList(productType),
resolve: (parent, args, { query }, info) => {
return getProducts({
query
});
}
},
context.query is your actual query in this example its:
{ products { id } }

Nested per-field resolvers with Apollo Server

I'm having some trouble building resolvers for something I'm working on. I'm doing something similar to what this article suggests, where I have separate resolvers for each field within an entity. Here's a contrived version of my schema:
// schema.graphql
type Query {
service: ServiceInfo
}
type ServiceInfo {
configuration: ServiceConfiguration
publicKey: PublicKey
serverTokenInfo: ServerTokenInfo
}
type ServiceConfiguration {
platformA: PlatformConfiguration
platformB: PlatformConfiguration
platformC: PlatformConfiguration
}
The deal is that ServiceInfo resolves each of its fields from a different datasource, which is fine. The difficulty that I'm encountering is that platformA, platformB, and platformC all resolve their fields from different datasources.
Here's the resolvers for what I have working at the moment:
// resolvers.js
export default {
Query: {
service: () => ({})
},
ServiceInfo: {
 configuration: () => ({}),
publicKey: (_, args, ctx) => ctx.dataSources.service.getPublicKey(),
serverTokenInfo: : (_, args, ctx) => ctx.dataSources.service.getTokenInfo(),
}
}
Now, I need to write a resolver for the configuration. I've tried a couple things:
// resolvers.js
export default {
// ...
ServiceInfo: {
 configuration: () => ({}),
// ...
ServiceConfiguration: {
platformA: (_, args, ctx) => ctx.dataSources.service.getConfig("A"),
platformB: (_, args, ctx) => ctx.dataSources.service.getConfig("B"),
platformC: (_, args, ctx) => ctx.dataSources.service.getConfig("C"),
}
}
}
This fails and tells me: ServiceInfo.ServiceConfiguration defined in resolvers, but not in schema. The next thing I tried was moving the ServiceConfiguration resolver to the top level:
// resolvers.js
export default {
// ...
ServiceInfo: {
// ...
}
ServiceConfiguration: {
platformA: (_, args, ctx) => ctx.dataSources.service.getConfig("A"),
platformB: (_, args, ctx) => ctx.dataSources.service.getConfig("B"),
platformC: (_, args, ctx) => ctx.dataSources.service.getConfig("C"),
}
}
...and it now fails and tells me that ServiceConfiguration defined in resolvers, but not in schema and I'm out of ideas. If anybody has some insight, I'd really appreciate it—I'm very stuck.

GraphQL arguments in child resolver

I'm using graphql-tools and am testing a schema where both parent and child receive an argument.
{
parentWithArg(a: "test") {
childWithArg(b: "test")
}
}
When the child resolver runs, I'm confused because the first argument contains args, which does not match the spec. The obj argument appears to be completely absent?
const resolvers = {
Query: {
parentWithArg(obj, args, ctx) {
console.log('parentWithArg obj:', obj); // `{}` as expected
return {
childWithArg(obj, args, ctx) {
console.log('childWithArg obj:', obj); // `{ b: 'test' }`
return args.b; // null
}
};
},
},
};
Here is the example on Apollo Launchpad: https://launchpad.graphql.com/p08j03j8r0
That happens when you return a function for one of the properties in the object returned by a resolver -- GraphQL will call the function to resolve the value but it will only call it with three parameters instead of four (args, context and info). The parent or "root" value in this case is dropped because the function in this case is being called as part of resolving that very same root value.
To access the root value, your resolver for the childWithArg field should go under the resolvers for the Parent type, like this:
const resolvers = {
Query: {
parentWithArg(obj, args, ctx) {
return {}
},
},
Parent: {
childWithArg(obj, args, ctx) {
console.log('childWithArg obj:', obj)
return args.b
},
},
}

Resources