Mutations
Learn how to update data using the Apollo `mutate` in GraphQL mutations. Code examples in Angular and explanations on Optimistic UI.
In addition to fetching data using queries, Apollo also handles GraphQL mutations. Mutations are
identical to queries in syntax, the only difference being that you use the keyword mutation
instead of query to indicate that the operation is used to change the dataset behind the schema.
GraphQL’s mutations consist of two parts:
- The mutation name with arguments (
upvotePost), which represents the actual operation to be done on the server - The fields you want back from the result of the mutation to update the client (
idandvote)
The result of the above mutation might be:
When we use mutations in Apollo, the result is typically integrated into the cache automatically based on the id of the result, which in turn updates UI automatically, so we don’t explicitly handle the results ourselves. In order for the client to correctly do this, we need to ensure we select the correct fields (as in all the fields that we care about that may have changed).
Basic Mutations
Using Apollo it’s easy to call mutation. You can simply use mutate method.
Calling mutations
Most mutations will require arguments in the form of query variables, and you may wish to provide
other options to
ApolloClient#mutate.
You can directly pass options to mutate when you call it in the wrapped component:
As you can see, mutate method returns an Observable that resolves with ApolloQueryResult. It
is the same result we get when we fetch queries.
However, typically you’d want to keep the concern of understanding the mutation’s structure out of your presentational component. The best way to do this is to use a service to bind your mutate function:
Optimistic UI
Sometimes your client code can easily predict the result of the mutation, if it succeeds, even before the server responds with the result. For instance, in GitHunt, when a user comments on a repository, we want to show the new comment in context immediately, without waiting on the latency of a round trip to the server, giving the user the experience of a snappy UI. This is what we call Optimistic UI. This is possible if the client can predict an Optimistic Response for the mutation.
Apollo Client gives you a way to specify the optimisticResponse option, that will be used to
update active queries immediately, in the same way that the server’s mutation response will. Once
the actual mutation response returns, the optimistic part will be thrown away and replaced with the
real result.
For the example above, it is easy to construct an optimistic response, since we know the shape of the new post and can predict the new title. The optimistic response doesn’t have to be exactly correct because it will always be replaced with the real result from the server, but it should be close enough to make users feel like there is no delay.
Loading State
The result of Apollo.mutate() contains loading property. By default, it’s always false and the
result is emitted with the response from the ApolloLink execution chain. In order to correct it you
can enable useMutationLoading flag in configuration.
Designing Mutation Results
When people talk about GraphQL, they often focus on the data fetching side of things, because that’s where GraphQL brings the most value. Mutations can be pretty nice if done well, but the principles of designing good mutations, and especially good mutation result types, are not yet well-understood in the open source community. So when you are working with mutations it might often feel like you need to make a lot of application-specific decisions.
In GraphQL, mutations can return any type, and that type can be queried just like a regular GraphQL query. So the question is - what type should a particular mutation return?
In GraphQL itself, there isn’t any specification about how this is supposed to work. In most cases, the data available from a mutation result should be the server developer’s best guess of the data a client would need to understand what happened on the server. For example, a mutation that creates a new comment on a blog post might return the comment itself. A mutation that reorders an array might need to return the new array.