mutate
Executes a mutation to modify server data.
API
Apollo.mutate<TData, TVariables>(
options: MutationOptions<TData, TVariables>
): Observable<MutationResult<TData>>
Returns a MutationResult<TData>
observable. This observable terminates with a result when the mutation is successful or an an error when it it fails.
The observable must be subscribed to for the mutation to execute.
For the complete list of options available, please refer to Apollo Client docs
Executing a mutation
To execute a mutation, inject Apollo
and pass it a GraphQL mutation document.
First, we'll create a GraphQL mutation named UpdateBook
:
mutation UpdateBook($id: ID!, $book: UpdateBookInput!) {
updateBook(id: $id, book: $book) {
...BookFragment
}
}
Saving book.graphql will trigger codegen of UPDATE_BOOK_MUTATION
typed gql document in /graphql/types.ts file as per our setup.
For more information about codegen and how it works, please refer to the Codegen section.
We have used the same BookFragment
from our previous query example, that way Apollo Client will automatically normalize and update the cache with the new data returned from the mutation.
This will automatically update any active QueryObservable
instances that are watching the same data, and the UI will display the new data without any additional effort by the developer.
Next, we execute the mutation and handle the result.
import { Apollo } from '@apollo-orbit/angular';
import { UPDATE_BOOK_MUTATION, UpdateBookInput } from '../graphql/types';
@Component({
selector: 'app-books',
templateUrl: './books.component.html'
})
export class BooksComponent {
private readonly apollo = inject(Apollo);
private readonly notificationService = inject(NotificationService);
protected readonly loading = signal<boolean>(false);
protected readonly error = signal<Error | undefined>(undefined);
...
protected updateBook(id: string, book: UpdateBookInput): void {
this.loading.set(true);
this.error.set(undefined);
this.apollo.mutate({ mutation: UPDATE_BOOK_MUTATION, variables: { id, book } }).pipe(
finalize(() => this.loading.set(false)),
).subscribe({
next: result => this.notificationService.success(`Book '${result.data!.updateBook.name}' was updated successfully.`),
error: (error) => this.error.set(error)
});
}
}
We apply non-null assertion !
to result.data
above because we know that, in this case, a successful mutation will always return data.
In some edge cases both data
and error
might be undefined, for example when errorPolicy
is set to ignore
.
mapMutation
Similar to mapQuery
, Apollo Orbit provides a mapMutation
RxJS operator to map the data
of a mutation result while preserving the other properties.
This is useful when you want to map the mutation result without dealing with the nullability of data
property.
import { mapMutation } from '@apollo-orbit/angular';
...
this.apollo.mutate({ mutation: UPDATE_BOOK_MUTATION, variables: { id, book } }).pipe(
mapMutation(data => data.updateBook.name)
).subscribe({
next: name => this.notification.success(`Book '${name}' was updated successfully.`),
error: (error) => this.error.set(error)
});
Cache normalisation
As we've seen above, Apollo Client automatically updates the cache with the new data returned from the mutation.
But this might not be as straight forward with other mutations like addBook
or deleteBook
where the cache needs to be updated manually because Apollo Client cannot identify which parts of the cache reference the list of books.
For example, we might need to add a book to an author's books list and to the full list of books in cache.
This, including optimistic UI & refetching queries, will be covered in more detail in the State section of the docs.