Mutations and Subscriptions Explained
Key Concepts
- Mutations
- Subscriptions
- GraphQL Mutations
- GraphQL Subscriptions
- Real-time Data Updates
- Subscriptions vs Polling
- Subscription Lifecycle
- Handling Mutations
- Handling Subscriptions
- Error Handling in Mutations
- Error Handling in Subscriptions
- Optimistic UI Updates
- Subscription Best Practices
- Real-world Examples
- Analogies
Mutations
Mutations in GraphQL are operations that modify data on the server. They are analogous to POST, PUT, PATCH, and DELETE requests in REST APIs. Mutations allow you to create, update, or delete data.
Example:
mutation CreatePost($input: CreatePostInput!) { createPost(input: $input) { id title content } }
Subscriptions
Subscriptions in GraphQL are a way to receive real-time data updates from the server. Unlike queries and mutations, which are one-time operations, subscriptions maintain a persistent connection to the server and receive updates as they happen.
Example:
subscription OnPostCreated { postCreated { id title content } }
GraphQL Mutations
GraphQL mutations are defined in the schema using the mutation keyword. They specify the operations that can modify data on the server. Mutations can return data, allowing you to update the client-side state after the mutation is performed.
Example:
type Mutation { createPost(input: CreatePostInput!): Post updatePost(id: ID!, input: UpdatePostInput!): Post deletePost(id: ID!): Boolean }
GraphQL Subscriptions
GraphQL subscriptions are defined in the schema using the subscription keyword. They specify the events that clients can subscribe to in order to receive real-time updates. Subscriptions are typically implemented using WebSockets.
Example:
type Subscription { postCreated: Post postUpdated: Post postDeleted: Post }
Real-time Data Updates
Real-time data updates are achieved using GraphQL subscriptions. When a client subscribes to an event, the server sends updates to the client as soon as the event occurs. This allows for real-time notifications and live data feeds.
Example:
subscription OnNewMessage { newMessage { id content sender } }
Subscriptions vs Polling
Subscriptions differ from polling in that they maintain a persistent connection to the server, allowing for real-time updates. Polling, on the other hand, involves periodically sending requests to the server to check for updates. Subscriptions are more efficient and provide instant updates.
Example:
// Polling example setInterval(() => { fetch('/api/messages') .then(response => response.json()) .then(data => updateMessages(data)); }, 5000);
Subscription Lifecycle
The lifecycle of a subscription includes the following stages:
- Client sends a subscription request to the server.
- Server establishes a WebSocket connection.
- Server sends updates to the client as events occur.
- Client receives updates and updates the UI.
- Client can unsubscribe to stop receiving updates.
Handling Mutations
Handling mutations involves sending a mutation request to the server and processing the response. The response can be used to update the client-side state or display success/error messages.
Example:
const [createPost] = useMutation(CREATE_POST_MUTATION); const handleCreatePost = () => { createPost({ variables: { input: { title: 'New Post', content: 'Post content' } } }) .then(response => { console.log('Post created:', response.data.createPost); }) .catch(error => { console.error('Error creating post:', error); }); };
Handling Subscriptions
Handling subscriptions involves setting up a subscription client and subscribing to events. The client will receive updates from the server and update the UI accordingly.
Example:
const { data, error } = useSubscription(POST_CREATED_SUBSCRIPTION); useEffect(() => { if (data) { console.log('New post created:', data.postCreated); } if (error) { console.error('Subscription error:', error); } }, [data, error]);
Error Handling in Mutations
Error handling in mutations involves catching and processing errors that occur during the mutation process. Errors can be displayed to the user or logged for debugging purposes.
Example:
const [createPost] = useMutation(CREATE_POST_MUTATION); const handleCreatePost = () => { createPost({ variables: { input: { title: 'New Post', content: 'Post content' } } }) .catch(error => { console.error('Error creating post:', error); alert('Failed to create post. Please try again.'); }); };
Error Handling in Subscriptions
Error handling in subscriptions involves catching and processing errors that occur during the subscription process. Errors can be displayed to the user or logged for debugging purposes.
Example:
const { data, error } = useSubscription(POST_CREATED_SUBSCRIPTION); useEffect(() => { if (error) { console.error('Subscription error:', error); alert('Failed to receive updates. Please try again.'); } }, [error]);
Optimistic UI Updates
Optimistic UI updates involve updating the UI before the server confirms the mutation. This provides a better user experience by making the UI feel more responsive. If the mutation fails, the UI can be rolled back to its previous state.
Example:
const [createPost] = useMutation(CREATE_POST_MUTATION, { optimisticResponse: { createPost: { id: 'temp-id', title: 'New Post', content: 'Post content', __typename: 'Post' } }, update: (cache, { data: { createPost } }) => { cache.modify({ fields: { posts(existingPosts = []) { const newPostRef = cache.writeFragment({ data: createPost, fragment: gql fragment NewPost on Post { id title content } }); return [...existingPosts, newPostRef]; } } }); } });
Subscription Best Practices
Best practices for subscriptions include:
- Use subscriptions for real-time data updates.
- Handle errors gracefully to provide a good user experience.
- Use optimistic UI updates to improve responsiveness.
- Unsubscribe from events when they are no longer needed to avoid memory leaks.
- Use WebSockets for efficient and real-time communication.
Real-world Examples
Real-world examples of using mutations and subscriptions include:
- Creating a real-time chat application with message subscriptions.
- Updating a social media feed with new posts as they are created.
- Handling user notifications in real-time.
- Managing live data feeds for financial applications.
Analogies
Think of mutations as placing an order at a restaurant. You send a request (mutation) to the kitchen (server) to prepare a dish (create, update, or delete data). The kitchen then sends back the prepared dish (response) for you to enjoy.
Subscriptions are like having a live news feed. You subscribe to a channel (subscription) and receive updates (real-time data) as soon as they happen. This keeps you informed without having to constantly check for updates.