naming your graphql mutations in react-apollo - graphql

consider the following
const createBob1 = gql`
mutation createBob2($var: data) {
createBob3(var: $var) {
id
}
}
`
at three levels, we're naming the mutation:
createBob1 defines the graphql document
createBob2 defines the apollo mutation
createBob3 defines the graphql resolver function to call
(I think?)
Has anyone settled on a naming convention for how to keep all three names consistent? Do you name them all the same?

Related

Sending dynamic number of mutations at once

Is there a standard way to send a dynamic number of mutations in the same request with Apollo client ?
I have to deal with a Graphql API that only expose a single delete mutation, and I'd like to call it with multiple ids. Here's how it's defined:
mutation DeleteItemById($id: Int) {
delete_item(id: $id) {
id
}
}
From what I read, I could do something like
mutation DeleteItemById($id_1: Int, $id_2: Int) {
delete_item_1: delete_item(id: $id_1) {
id
}
delete_item_2: delete_item(id: $id_2) {
id
}
}
But how could I generate such a query dynamically ? Is it a good practice anyway ? I always read it was not a good idea to dynamically generate graphql queries.
Plus, I'm using graphql-codegen and statically defining queries in .graphql files, so I imagine it will have trouble parsing dynamic ones.
In general it's a bad idea to generate GraphQL queries dynamically. A good way to deal with this is to create a new mutation that supports multiple ids, validate and delete all in the same batch, like:
type Mutation {
deleteItems(ids: [String!]!): Boolean!
}

Why do you need to wrap GraphQL mutations?

I have never understood why GraphQL mutations need to be "wrapped". You'll often see something like this demonstrated (assuming a mutation named addThing which requires a name):
mutation addThing($name: String!) {
addThing(name: $name) {
id
name
}
}
However, the outer "wrapper" could be named anything. For example, the following nonsense works equally well:
mutation nonsense($name: String!) {
addThing(name: $name) {
id
name
}
}
What is the reasoning for "wrapping" the mutations this way?

Call the same GraphQL mutation action many times in one http request [duplicate]

I have a mutation:
const createSomethingMutation = gql`
mutation($data: SomethingCreateInput!) {
createSomething(data: $data) {
something {
id
name
}
}
}
`;
How do I create many Somethings in one request? Do I need to create a new Mutation on my GraphQL server like this:
mutation {
addManySomethings(data: [SomethingCreateInput]): [Something]
}
Or is there a way to use the one existing createSomethingMutation from Apollo Client multiple times with different arguments in one request?
You can in fact do this using aliases, and separate variables for each alias:
const createSomethingMutation = gql`
mutation($dataA: SomethingCreateInput!) {
createA: createSomething(data: $dataA) {
something {
id
name
}
}
createB: createSomething(data: $dataB) {
something {
id
name
}
}
}
`;
You can see more examples of aliases in the spec.
Then you just need to provide a variables object with two properties -- dataA and dataB. Things can get pretty messy if you need the number of mutations to be dynamic, though. Generally, in cases like this it's probably easier (and more efficient) to just expose a single mutation to handle creating/updating one or more instances of a model.
If you're trying to reduce the number of network requests from the client to server, you could also look into query batching.
It's not possible so easily.
Because the mutation has one consistent name and graphql will not allow to have the same operation multiple times in one query. So for this to work Apollo would have to map the mutations into aliases and then even map the variables data into some unknown iterable form, which i highly doubt it does.

How to use graphql type in other files for relationship without duplication

I am trying to separate all the tables in different directory. However, I am encountering some problems. Look at the ExpenseItem below. ExpenseType is under ExpenseType directory so graphql throws error. In order to solve that I need to add ExpenseType in ExpeseItem/typeDefs which is redundant.
ExpenseItem/typeDefs
type ExpenseItem {
id: ID!
name: String,
updatedAt: DateTime,
expenseType: [ExpenseType]
}
Is there any better way to stitch the schema?
I also tried something like this. However, graphql stop working.
When I query, it does not goes into the resolver, is there anything wrong on setup?
const schemas = makeExecutableSchema({
typeDefs: `
scalar JSON
scalar DateTime
type Query {
test: String
}
${typeDefs1}
${typeDefs2}
${typeDefs3}
${typeDefs4}
`,
resolvers: {
// Type resolvers
JSON: GraphQLJSON,
DateTime: GraphQLDateTime,
// schema resolvers
...resolvers1,
...resolvers2,
...resolvers3,
...resolvers4
}
})
const server = new ApolloServer({
schema,
context: { db }
})
You cannot merge your resolvers like this. Using the spread operator to merge an object results in a shallow merge. If the merged objects share any common properties (for example, Query), only the last merged property will be present in the resulting object. You need to deep merge the objects. You can do so yourself, or use something like lodash's merge.
Additionally, you can pass an array of strings as the typeDefs to makeExecutableSchema instead of combining them yourself.

Apollo GraphQL fails to invoke resolver for a nested field

I've the following structure in my schema:
type gn_Feature implements Some_Interface {
s_description: String
s_id: URL!
some_parent: gn_Feature
}
As you can see, each gn_Feature has an another linked gn_Feature object (the linking is handled elsewhere, it doesn't really matter). By my current understanding, you only need to define the resolvers for the return types, so my resolvers look like the following:
export const resolvers = Object.assign(
{},
{
DateTime: DateTime,
Date: DateTime,
Time: RegularExpression("Time", /^\d{2}:\d{2}(:\d{2})?$/),
URL,
Query: {
gn_Feature: gn_FeatureResolver
},
gn_Feature: gn_FeatureResolver
}
);
But, my queries fail with the following error if I don't explicitly define the resolver for the nested field, like so:
gn_Feature: {some_parent: gn_FeatureResolver}
Error:
"message": "Resolve function for \"gn_Feature.s_description\"
returned undefined"
My resolver function doesn't even get invoked for my nested object when I don't specify it like the above.
My backend consists of some voodoo transpiling of GraphQL queries into SparQL queries which return data back so I won't post the resolver code as I utilize one universal resolver for many fields. I'd like to avoid having to specify resolvers for each nested field as that's going be extremely tedious (I have dozens of types with dozens of fields). Any clarifications are welcome, as I'm completely baffled.
Example GraphQL query:
gn_Feature(some_field:"AD", last:2){
s_description,
s_id
some_parent{
s_description
}
}
When executing a query, only the value of any particular field is initially unknown and needs to be resolved... everything else, like the types, selection sets, etc. is already known. A resolver is a function called to resolve a specific field. In GraphQL.js, there are no resolvers for types.
Apollo muddies the waters a bit in this regard, since for convenience, the API for makeExecutableSchema allows you to define custom scalars by including them in the resolver map. Additionally, even though interfaces and unions don't have resolvers either, Apollo lets you use the resolver map to specify a __resolveType function for these abstract types as well. Apollo's docs actually define a resolver as "a function that connects schema fields and types to various backends." However, in the context of GraphQL in general, you should think of a resolvers as "a functions that resolves the value of a field".
So, given a type called gn_Feature and a field called some_parent, this is the correct way to structure your resolvers:
const resolvers = {
gn_Feature: {
some_parent: someResolverFunction
}
}
Also note that Query and Mutation are both types themselves, so if you have a query called gn_Feature, you are actually resolving a field called gn_Feature for the Query type.

Resources