GraphQL Subscription Filtering — Sending Targeted Events to Specific Clients
In this tutorial, you will learn about Graphql Subscription Filtering. We cover key concepts, practical examples, and best practices to help you master this topic.
GraphQL subscription filtering controls which clients receive which events by using subscription arguments, context-based filtering, and server-side event routing for targeted delivery.
What You'll Learn
- Filtering subscriptions with arguments
- Context-based subscription filtering
- Multi-tenant event routing patterns
Why It Matters
Without filtering, every subscriber receives every event. Filtering ensures clients only receive relevant events, reducing bandwidth and client-side processing.
Code Examples
# Filtered subscriptions
type Subscription {
postAdded(channelId: ID!): Post!
commentAdded(postId: ID!): Comment!
notificationReceived(userId: ID!): Notification!
userStatusChanged(userIds: [ID!]!): UserStatus!
taskUpdated(projectId: ID!): Task!
}
// Subscription filtering with arguments
const pubsub = new PubSub();
const resolvers = {
Subscription: {
postAdded: {
subscribe: (parent, { channelId }, context) => {
// Only subscribe to events for this channel
return pubsub.asyncIterator(`POST_ADDED_${channelId}`);
}
},
commentAdded: {
subscribe: (parent, { postId }, context) => {
return pubsub.asyncIterator(`COMMENT_ADDED_${postId}`);
}
},
// Context-based filtering for authenticated users
notificationReceived: {
subscribe: (parent, { userId }, { user }) => {
// Security: ensure user can only listen to their own notifications
if (user.id !== userId) {
throw new Error('Unauthorized');
}
return pubsub.asyncIterator(`NOTIFICATION_${userId}`);
}
}
}
};
// Publishing events - filter by channel ID
function publishPost(channelId, post) {
pubsub.publish(`POST_ADDED_${channelId}`, { postAdded: post });
}
# Python subscription filtering
import strawberry
@strawberry.type
class Subscription:
@strawberry.subscription
async def post_added(
self, channel_id: str, info: strawberry.types.Info
) -> Post:
# Subscribe only to this channel's events
async for event in my_pubsub.subscribe(f'post_added:{channel_id}'):
yield event
@strawberry.subscription
async def notification_received(
self, user_id: str, info: strawberry.types.Info
) -> Notification:
# Ensure user can only subscribe to their own notifications
if info.context['user'].id != user_id:
raise Exception('Unauthorized')
async for event in my_pubsub.subscribe(f'notification:{user_id}'):
yield event
Common Mistakes
1. Not Filtering by User ID
Without user-specific filtering, users receive notifications intended for others.
2. Exposing Internal Event Channels
Use opaque channel IDs that do not reveal internal system details.
3. Missing Authentication in Subscription Filters
Always verify the subscriber is authorized to receive the filtered events.
4. Creating Too Many Event Channels
Each unique channel uses memory. Use generic channels with client-side filtering for large datasets.
5. Not Cleaning Up Unused Channels
Remove channels when no subscribers remain to prevent memory leaks.
Practice Questions
- How do you filter subscriptions by argument?
- How do you ensure a user can only subscribe to their own events?
- What is the difference between server-side and client-side filtering?
- How do you create event channels per resource?
- How do you handle multi-tenant event filtering?
Answers:
- Use subscription arguments to create resource-specific event channels.
- Verify user identity in the subscribe resolver using context.
- Server-side filtering reduces bandwidth; client-side filtering is simpler to implement.
- Use resource ID in the event channel name: POST_ADDED_{channelId}.
- Include tenant ID in the event channel: NOTIFICATION_{tenantId}_{userId}.
Challenge: Build a real-time collaboration system with filtered subscriptions: document changes filtered by document ID, user presence filtered by team, and notifications filtered by user ID with authentication.
FAQ
Mini Project
Build a real-time notification system with subscription filtering: document edits (by document ID), team updates (by team ID), admin alerts (admin role only), and user mentions (by user ID). Implement authentication checks in subscribe resolvers.
What's Next
Learn about subscription context for Websocket authentication, then explore DataLoader caching for performance.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro