Register Subscriptions with Context
Problem
You need to register GraphQL subscriptions with custom context data for filtering events and passing layer-specific information.
Enhancement Needed
Subscription patterns need team input for standardization and better context handling mechanisms.
Subscription Context Model
Section titled âSubscription Context ModelâDefine context models for subscription-specific data:
@freezed@JsonSerializable(includeIfNull: false)class ChatMessageSubscriptionContext with _$ChatMessageSubscriptionContext { const factory ChatMessageSubscriptionContext({ required String chatId, required String currentUserId, }) = _ChatMessageSubscriptionContext;
factory ChatMessageSubscriptionContext.fromJson(Map<String, dynamic> json) => _$ChatMessageSubscriptionContextFromJson(json);
Map<String, dynamic> toJson() => _$ChatMessageSubscriptionContextToJson(this);}Subscription Request Strategy
Section titled âSubscription Request StrategyâCreate subscription request with context handling:
class ChatMessageSubscriptionRequestStrategy implements RequestStrategy< GSubscribeToChatMessagesReq, SubscriptionRequestParams<ChatMessageSubscriptionContext> >, RequestHolder<GSubscribeToChatMessagesReq> {
@override String get key => ChatMessageRequestStrategyKeys.messageSubscription.name;
@override String get requestId => 'chat_message_subscription';
GSubscribeToChatMessagesReq? _request;
@override GSubscribeToChatMessagesReq? get request => _request;
@override GSubscribeToChatMessagesReq build( SubscriptionRequestParams<ChatMessageSubscriptionContext> params, ) { _request = GSubscribeToChatMessagesReq( (b) => b ..requestId = '${requestId}_${params.context?.chatId ?? 'all'}' ..updateCacheHandlerKey = ChatMessageCacheHandlerStrategyKeys .messageSubscriptionCacheHandler.name ..updateCacheHandlerContext = params.context?.toJson(), ); return _request!; }}Subscription Cache Handler
Section titled âSubscription Cache HandlerâImplement cache handler with context-based filtering:
class ChatMessageSubscriptionCacheHandlerStrategy implements CacheHandlerStrategy< GSubscribeToChatMessagesData, GSubscribeToChatMessagesVars > {
@override UpdateCacheHandler build(RequestContext requestContext) { return (proxy, response) { final subscriptionItem = response.data?.messageSubscription; final context = response.operationRequest.updateCacheHandlerContext;
if (context == null || subscriptionItem == null) { return; }
final subscriptionContext = ChatMessageSubscriptionContext.fromJson(context);
if (!_shouldProcessEvent(subscriptionContext, subscriptionItem)) { return; }
_updateMessageListCache(proxy, requestContext, subscriptionItem, subscriptionContext); }; }
bool _shouldProcessEvent( ChatMessageSubscriptionContext context, GSubscribeToChatMessagesData_messageSubscription subscriptionItem, ) { if (context.chatId != subscriptionItem.systemParentId) { return false; }
if (context.currentUserId == subscriptionItem.senderID) { return false; }
return true; }
void _updateMessageListCache( CacheProxy proxy, RequestContext requestContext, GSubscribeToChatMessagesData_messageSubscription subscriptionItem, ChatMessageSubscriptionContext context, ) { final filter = GmessageFilters( (b) => b..systemParentId = subscriptionItem.systemParentId, );
final listHolder = requestContext.getHolder<GQueryChatMessagesReq>( ChatMessageRequestStrategyKeys.messageList.name, );
final queryRequest = listHolder?.request ?? requestContext.execute< GQueryChatMessagesReq, ListRequestParams<GmessageFilters, GmessageOrder> >( ChatMessageRequestStrategyKeys.messageList.name, ListRequestParams(filter: filter), );
final prevData = proxy.readQuery(queryRequest); if (prevData == null) return;
final parsedItem = GQueryChatMessagesData_message_messageItems.fromJson( subscriptionItem.toJson(), );
proxy.writeQuery( queryRequest, prevData.rebuild((b) { return b ..message.messageItems.add(parsedItem) ..message.totalCount = (b.message.totalCount ?? 0) + 1; }), ); }
@override String get key => ChatMessageCacheHandlerStrategyKeys.messageSubscriptionCacheHandler.name;}Datasource Subscription Method
Section titled âDatasource Subscription MethodâImplement subscription method in datasource:
class ChatMessageDatasource { Stream<OperationResponse<GSubscribeToChatMessagesData, GSubscribeToChatMessagesVars>> subscribeToMessages({ required String chatId, required String currentUserId, }) { final context = ChatMessageSubscriptionContext( chatId: chatId, currentUserId: currentUserId, );
final params = SubscriptionRequestParams<ChatMessageSubscriptionContext>( context: context, );
final subscription = requestContext.execute< GSubscribeToChatMessagesReq, SubscriptionRequestParams<ChatMessageSubscriptionContext> >(ChatMessageRequestStrategyKeys.messageSubscription.name, params);
return client.request(subscription); }}Repository Subscription Usage
Section titled âRepository Subscription UsageâUse subscriptions in repository with proper context:
class ChatMessageRepository { Stream<ChatMessageEntity> subscribeToMessages({ required String chatId, required String currentUserId, }) { return datasource .subscribeToMessages( chatId: chatId, currentUserId: currentUserId, ) .map((response) => response.data?.messageSubscription) .where((data) => data != null) .map((data) => convertToChatMessage(data!)); }}Subscription Context Use Cases
Section titled âSubscription Context Use CasesâCommon subscription context scenarios:
- User Filtering - Skip events from current user
- Permission Checks - Filter based on user permissions
- Feature Flags - Enable/disable subscription features
- Rate Limiting - Control subscription frequency
- Data Enrichment - Add context-specific data
Team Enhancement Areas
Section titled âTeam Enhancement AreasâCurrent Limitations:
- Context Type Safety - Need better type enforcement
- Context Validation - Validate context data at runtime
- Context Inheritance - Share context between related subscriptions
- Context Caching - Cache context data for performance
Proposed Improvements:
- Typed Context Registry - Register context types with validation
- Context Middleware - Process context data before cache handlers
- Context Composition - Combine multiple context sources
- Context Debugging - Better debugging tools for context flow
Next Steps
Section titled âNext Stepsâ- Learn repository data cleaning
- Explore repository context patterns