Skip to content

Conversation

anivar
Copy link
Contributor

@anivar anivar commented Sep 25, 2025

This PR adds subscription variables support to DataStore, addressing the long-standing need for server-side subscription filtering in multi-tenant applications. Fixes #9413.

The implementation adds a new subscriptionVariables configuration option that allows passing custom variables to GraphQL subscriptions. This enables filtering at the subscription level rather than receiving all updates and filtering client-side - a critical requirement for multi-tenant SaaS applications where each tenant should only receive their own real-time updates.

The solution integrates cleanly with the existing DataStore sync engine by extending DataStoreConfig with an optional subscriptionVariables field. Variables are processed in SubscriptionProcessor and passed through to buildSubscriptionGraphQLOperation. The implementation supports both static variables (objects) and dynamic variables (functions that receive the operation type).

// Static variables for simple multi-tenant filtering
DataStore.configure({
  subscriptionVariables: {
    Todo: { storeId: 'store-123' }
  }
});

// Dynamic variables based on operation type
DataStore.configure({
  subscriptionVariables: {
    Todo: (operation) => ({
      storeId: 'store-123',
      isNew: operation === 'CREATE'
    })
  }
});

The implementation includes comprehensive production safeguards: deep cloning to prevent mutation side effects on cached values, filtering of reserved GraphQL keywords (filter, owner, limit, etc.), memoization to avoid redundant function calls, and proper error handling for edge cases like circular references and Object.create(null).

This directly addresses the use cases discussed in the issue thread where developers need to filter subscriptions by tenant/store IDs at the server level. Without this feature, multi-tenant apps must receive all updates across all tenants and filter client-side, which is inefficient and potentially insecure.

The changes are fully backward compatible - existing DataStore usage continues to work unchanged. Added 12 comprehensive unit tests covering basic functionality, edge cases, mutation protection, and caching behavior. All existing DataStore tests continue to pass.

- Add subscriptionVariables option to DataStoreConfig
- Support both static and function-based variables per model
- Pass variables to GraphQL subscription operations
- Enable multi-tenant filtering at subscription level

Addresses issue aws-amplify#9413 for multi-tenant app support
…ables

- Add try-catch error handling around function calls
- Prevent override of reserved GraphQL variables (filter, owner, limit, etc)
- Validate GraphQL variable names (alphanumeric + underscore only)
- Skip null/undefined values gracefully
- Add comprehensive logging for debugging

Makes the feature more robust for production use
…ption variables

- Add caching to prevent repeated function calls (3x per model)
- Validate static variables are objects (not primitives)
- Simplify reserved key filtering logic
- Clear cache on processor stop for memory hygiene

Improves performance when subscription variable functions are expensive
- Deep clone objects to prevent mutation side effects
- Handle Object.create(null) safely with try-catch fallback
- Return copies of static variables to prevent mutations
- Handle circular references gracefully
- Add comprehensive edge case tests (8 new tests)

Ensures production-grade safety for all input scenarios
- Extract subscription variable processing into utility functions in sync/utils.ts
- Follow existing Amplify patterns for utility functions
- Simplify SubscriptionProcessor by removing duplicate logic
- Update tests to use the refactored utility functions
- Maintain all edge case protections and caching behavior
- Remove unnecessary comments
- Simplify code structure
- Follow minimal Amplify style
- Clean up test files
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

DataStore Subscriptions by Argument
1 participant