0

Apollo-Client 2.0. I am using chained Mutation components. I am trying to pass a returned value from the first Mutation to the second Mutation. I execute the mutations when an onSubmit button is clicked on a form component. The returned value from first mutation is not being passed as one of the "variables" in second mutation

I reviewed solutions in two very similar posts: How to wrap GraphQL mutation in Apollo client mutation component in React and How to chain together Mutations in apollo client. I think my use of a form is adding some additional complexity to my solution. Although the passed value (competitionId) is visible in the handleOnSubmit function (if I console log after createCompetition() in handleOnSubmit), it is not getting passed as a variable in the second Mutation which is called in the handleOnSubmit. The result is a successful execution of the first Mutation and a 400 error on the second mutation: “errors”:[{“message”:“Variable \“$competitionId\” of required type \“ID!\” was not provided.” To be more specific, the value of CompetitionId DOES get passed to the second mutation after the first mutation runs, but it does not get passed as a "variables" to the createMatch function passed as an argument to the handleOnSubmit. It looks like the "variables" passed along with the createMatch function to the handleOnSubmit, only include the variables that are available when the submit button is clicked. The competitionId, is generated after the submit button is clicked and the first mutation returns it as a result.

handleOnSubmit = async(event, createCompetition, createMatch) => {
event.preventDefault();
await createCompetition();
await createMatch();
this.clearState();
this.props.history.push('/home');

}

render () {
const {location, name, action, caliber, rifleName, dateOf,competitionScore} = this.state;
const { matchNumber, targetNumber, relay, distanceToTarget, matchScore} = this.state;
return (
<div className="App">
  <h2 className="App">Add Competition</h2>
  <Mutation 
    mutation={CREATE_COMPETITION} 
    variables={{location, name, action, caliber, rifleName, dateOf, competitionScore}}
    refetchQueries={() => [
      { query: GET_ALL_COMPETITIONS, variables:{name: name}}
    ]}
    update={this.updateCache}>
    {(createCompetition, {data, loading, error}) => {

      if(loading) return <div>loading competition...</div>
      if(error) return <div>error: {error}</div>
      let competitionId;
      if(data) {
        competitionId = data.createCompetition._id;
      }
      return (
        <Mutation
          mutation={CREATE_MATCH}
          variables={{competitionId, matchNumber, targetNumber, distanceToTarget, matchScore}}>
          {(createMatch, {_, loading, error}) => {
            if(loading) return <div>loading match...</div>
            return (
              <form 
                className="form" 
                onSubmit={event => this.handleOnSubmit (event, createCompetition, createMatch)}>
                <label>  remaining form deleted for brevity

I expected the value of the CompetitionId to be passed as a variable to the createMatch function called in the handleOnSubmit method. It is not provided.

2 Answers2

0

Seems what you needs is nested mutations :thinkingface;

Q: Are you using prisma?

Well, in GraphQL you can create nodes by a single mutation, this is pretty simple if your Types are related, so I assume this is your case.

And should looks something like this:

datamodel.graphql

type Competition {
  id: ID! @unique
  name: String!
  match: Match! @relation(name: "CompetitionMatch")
}

type Match {
  id: ID! @unique
  name: String!
  campetition: Competition! @relation(name: "CompetitionMatch")
}

So, now in your schema.graphql should looks like this:

type Mutation {
  createCompetition (name: String! match: MatchInput): Competition
}

input MatchInput {
  name: String!
}

and now when you call your createCompetition mutation, you have to send the match data, like so:

mutation createCompetition (
 name: 'Loremp competition'
 match: { name: 'child match'}
) {
 id
 name
 match {
  id
  name
 }
}

Ref: https://www.graph.cool/docs/reference/graphql-api/mutation-api-ol0yuoz6go/#nested-create-mutations

Hope this help!

regards

masmerino
  • 957
  • 9
  • 8
  • I am not using prisma. I would prefer to continue to use Apollo-Server 2 along with mongoose. Once I understand Apollo-Server/ Client better, I may try prisma. Your assumption about my type being related are correct and queries work fine, it is the mutations that are a challenge: type Competition { _id: ID name: String rifleName: String location: String action: String caliber: Float dateOf: String competitionScore: String matches: [Match] } `; – James Semaj Jan 24 '19 at 18:10
  • I solved this issue by writing a more complex mutation with supporting schema on the backend. Then all I had to do was call the single mutation, with no chaining required. I received a suggestion to try this technique at our local React MeetUp. After looking into this, I took to heart the guidance provided in the Apollo documentation. That guidance was that you should write specific mutations/queries based on how best the clients can use the data. I wrote a single mutation on the backend API, that creates a single competition, 3 matches, and 60 shots. – James Semaj Jan 26 '19 at 20:57
0

Where the if (data) is, is where you should return the 2nd mutation

Aron
  • 38
  • 5