Skip to main content

mutate

Executes a mutation to modify server data.

API

Apollo.mutate<TData, TVariables, TErrorPolicy>(
options: MutationOptions<TData, TVariables, TErrorPolicy>
): Observable<MutationResultForOptions<TData, TErrorPolicy>>

Returns an observable whose result follows errorPolicy and the application's declared defaults. Under none (the default), failures reach the error channel. Under all, failures are delivered in result.error; under ignore, errors are omitted and data can be undefined.

note

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:

library/gql/book.graphql
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/operations.ts file as per our setup.

For more information about codegen and how it works, please refer to the Codegen section.

tip

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.

library/books/books.component.ts
import { Apollo } from '@apollo-orbit/angular';
import { UPDATE_BOOK_MUTATION, UpdateBookInput } from '../graphql';

@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)
});
}
}

mapMutation

Similar to mapQuery, 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.

The mapped result preserves the original error type and whether data can be undefined, as determined by errorPolicy. Let the input observable infer the result type.

import { mapMutation } from '@apollo-orbit/angular';
...
this.apollo.mutate({ mutation: UPDATE_BOOK_MUTATION, variables: { id, book } }).pipe(
mapMutation(data => data.updateBook.name)
).subscribe({
next: result => this.notificationService.success(`Book '${result.data}' 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.