amplify-flutter
amplify-flutter copied to clipboard
Real time subscriptions not working with Owner based scope
Description
I am trying to update a data record from Amplify Studio and see the real-time updates in my app.
When my model has @auth set to: {allow: private} the real-time subscriptions work perfectly, but when I also add the owner-based scopes (by deploying) the real-time does not seem to work no more.
Note: The record was added with owner-based scopes so "owner" field exists.
Categories
- [ ] Analytics
- [ ] API (REST)
- [ ] API (GraphQL)
- [ ] Auth
- [ ] Authenticator
- [X] DataStore
- [ ] Storage
Steps to Reproduce
- Set model with owner-based scope.
- Deploy
- Pull changes
- Create record from app
- Update record from amplify studio.
After updating the record no event is synced.
Screenshots
No response
Platforms
- [ ] iOS
- [X] Android
Android Device/Emulator API Level
API 32+
Environment
[✓] Flutter (Channel stable, 3.0.4, on Linux Mint 20.1 5.4.0-120-generic, locale en_US.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 32.1.0-rc1)
[✓] Chrome - develop for the web
[✓] Linux toolchain - develop for Linux desktop
[✓] Android Studio (version 2021.1)
[✓] Android Studio
[✓] IntelliJ IDEA Ultimate Edition (version 2020.3)
[✓] Connected device (3 available)
[✓] HTTP Host Availability
• No issues found!
Dependencies
Dart SDK 2.17.5
Flutter SDK 3.0.4
gymapp 1.0.0+1
dependencies:
- amplify_analytics_pinpoint 0.6.1 [amplify_analytics_pinpoint_android amplify_analytics_pinpoint_ios amplify_core aws_common flutter meta]
- amplify_api 0.6.1 [amplify_api_android amplify_api_ios amplify_core amplify_flutter aws_common collection flutter meta plugin_platform_interface]
- amplify_auth_cognito 0.6.1 [amplify_auth_cognito_android amplify_auth_cognito_ios amplify_core aws_common collection flutter meta plugin_platform_interface]
- amplify_authenticator 0.2.1 [amplify_auth_cognito amplify_core amplify_flutter aws_common collection flutter flutter_localizations intl]
- amplify_datastore 0.6.1 [flutter amplify_datastore_plugin_interface amplify_core plugin_platform_interface meta collection async]
- amplify_flutter 0.6.1 [amplify_core amplify_datastore_plugin_interface amplify_flutter_android amplify_flutter_ios aws_common collection flutter meta plugin_platform_interface]
- amplify_storage_s3 0.6.1 [amplify_storage_s3_android amplify_storage_s3_ios amplify_core aws_common flutter meta plugin_platform_interface]
- charts_flutter 0.12.0 [charts_common collection flutter intl logging meta]
- cupertino_icons 1.0.4
- file_picker 4.6.1 [flutter flutter_web_plugins flutter_plugin_android_lifecycle plugin_platform_interface ffi path win32]
- flutter 0.0.0 [characters collection material_color_utilities meta vector_math sky_engine]
- flutter_markdown 0.6.10 [flutter markdown meta path]
- http 0.13.4 [async http_parser meta path]
- path_provider 2.0.10 [flutter path_provider_android path_provider_ios path_provider_linux path_provider_macos path_provider_platform_interface path_provider_windows]
- provider 6.0.3 [collection flutter nested]
- video_player 2.4.2 [flutter html video_player_android video_player_avfoundation video_player_platform_interface video_player_web]
transitive dependencies:
- amplify_analytics_pinpoint_android 0.6.1 [flutter]
- amplify_analytics_pinpoint_ios 0.6.1 [flutter]
- amplify_api_android 0.6.1 [flutter]
- amplify_api_ios 0.6.1 [amplify_core flutter]
- amplify_auth_cognito_android 0.6.1 [flutter]
- amplify_auth_cognito_ios 0.6.1 [amplify_core flutter]
- amplify_core 0.6.1 [aws_common collection flutter intl json_annotation meta plugin_platform_interface uuid]
- amplify_datastore_plugin_interface 0.6.1 [amplify_core collection flutter meta]
- amplify_flutter_android 0.6.1 [flutter]
- amplify_flutter_ios 0.6.1 [amplify_core flutter]
- amplify_storage_s3_android 0.6.1 [flutter]
- amplify_storage_s3_ios 0.6.1 [flutter]
- args 2.3.1
- async 2.8.2 [collection meta]
- aws_common 0.1.1 [async collection http meta stream_transform uuid]
- characters 1.2.0
- charcode 1.3.1
- charts_common 0.12.0 [collection intl logging meta vector_math]
- clock 1.1.0
- collection 1.16.0
- crypto 3.0.2 [typed_data]
- csslib 0.17.2 [source_span]
- ffi 1.2.1
- file 6.1.2 [meta path]
- flutter_localizations 0.0.0 [flutter intl characters clock collection material_color_utilities meta path vector_math]
- flutter_plugin_android_lifecycle 2.0.6 [flutter]
- flutter_web_plugins 0.0.0 [flutter js characters collection material_color_utilities meta vector_math]
- html 0.15.0 [csslib source_span]
- http_parser 4.0.1 [collection source_span string_scanner typed_data]
- intl 0.17.0 [clock path]
- js 0.6.4
- json_annotation 4.5.0 [meta]
- logging 1.0.2
- markdown 5.0.0 [args charcode meta]
- material_color_utilities 0.1.4
- meta 1.7.0
- nested 1.0.0 [flutter]
- path 1.8.1
- path_provider_android 2.0.14 [flutter path_provider_platform_interface]
- path_provider_ios 2.0.9 [flutter path_provider_platform_interface]
- path_provider_linux 2.1.7 [ffi flutter path path_provider_platform_interface xdg_directories]
- path_provider_macos 2.0.6 [flutter path_provider_platform_interface]
- path_provider_platform_interface 2.0.4 [flutter platform plugin_platform_interface]
- path_provider_windows 2.0.7 [ffi flutter path path_provider_platform_interface win32]
- platform 3.1.0
- plugin_platform_interface 2.1.2 [meta]
- process 4.2.4 [file path platform]
- sky_engine 0.0.99
- source_span 1.8.2 [collection path term_glyph]
- stream_transform 2.0.0
- string_scanner 1.1.0 [charcode source_span]
- term_glyph 1.2.0
- typed_data 1.3.0 [collection]
- uuid 3.0.6 [crypto]
- vector_math 2.1.2
- video_player_android 2.3.5 [flutter video_player_platform_interface]
- video_player_avfoundation 2.3.4 [flutter video_player_platform_interface]
- video_player_platform_interface 5.1.2 [flutter plugin_platform_interface]
- video_player_web 2.0.10 [flutter flutter_web_plugins video_player_platform_interface]
- win32 2.5.2 [ffi]
- xdg_directories 0.2.0+1 [meta path process]
Device
Pixel 4
OS
Android 12
CLI Version
9.1.0
Additional Context
enum WorkoutType {
EMOM
AMRAP
RXT
}
enum UserWorkoutStatus {
PENDING
DONE
ERROR
}
type UserWorkout @model @auth(rules: [{allow: private}, {allow: owner}]) {
id: ID!
name: String
datetime: AWSDateTime!
status: UserWorkoutStatus!
videoKey: String!
workoutType: WorkoutType!
duration: Int!
userID: String
}
Hi @sanchez-gonzalo94 thanks for reporting this issue. Can you pasted the exception log in the Android app when the subscription fails for DataStore? Does the same auth rules configuration work in iOS?
Hi @HuiSF im not getting any exception log.
I use observeQuery , whenever I boot up the app the model gets synced correctly but real-time subscription dont seem to work :
VIEW MODEL:
List<UserWorkoutDatastore.UserWorkout> _userWorkouts = [];
Amplify.DataStore.observeQuery(UserWorkoutDatastore.UserWorkout.classType)
.listen((QuerySnapshot<UserWorkoutDatastore.UserWorkout> snapshot) {
var count = snapshot.items.length;
var now = DateTime.now().toIso8601String();
bool status = snapshot.isSynced;
print(
'[Observe Query] User Workout snapshot received with $count models, status: $status at $now');
_userWorkouts = snapshot.items;
notifyListeners();
});
VIEW:
class WorkoutListView2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer<UserWorkoutVW>(
builder: (context, userWorkoutVW, child) {
return ListView.builder(
shrinkWrap: true,
itemCount: context.watch<UserWorkoutVW>().userWorkouts.length,
itemBuilder: (context, index) {
return WorkoutCard(
userWorkout: userWorkoutVW.userWorkouts[index],
);
},
);
},
);
}
}
Thanks for the clarification @sanchez-gonzalo94
To clarify further:
- DataStore can sync data (if this is true, subscription should've worked otherwise sync engine will force datastore to work in local only mode)
observeQuerydoesn't receive event onUserWorkoutDatastoreupdate
My follow up questions:
- How do you mutate the model and to expect
observeQueryto receive an event on the update - When you mutate the model, did you right in matching value for the
ownerfield? (If you are mutate model not using DataStore APIs) - Are you using DataStore multiauth?
Yes, Datastore is syncing correctly , in fact when the app starts up the print function in the subscription (listen) executes perfectly.
Responding to your follow up questions:
- I mutate the model from Amplify UI.
- Since I mutate from Amplify UI, those fields are not present (they only appear in dynamodb).
- Yes,
@auth(rules: [{allow: private}, {allow: owner}].
More info to clarify, the real time subscription works perfectly if I remove the **owner-based scope**. That's why I get the feeling is something related to that.
the real time subscription works perfectly if I remove the owner-based scope
This gave me a clue, that the model you were mutating with Amplify UI, doesn't contain a matching owner field to your currently signed in user in the mobile App (by default is the user sub I think).
Can you check, after mutating in Amplify UI, is the record in DynamoDB contain correct owner field?
I'm not very familiar with Amplify UI but I thought it's just a UI library... Are you actually using Amplify API plugin to mutate models, or do you compose GraphQL document yourself?
So I found something interesting, I opened the console Amplify Studio (UI) and found out that apperently this is what it uses to update the records.
{
"aws_project_region": "us-east-1",
"aws_cognito_identity_pool_id": "us-east-1:poolID",
"aws_cognito_region": "us-east-1",
"aws_user_pools_id": "us-east-1_blank",
"aws_user_pools_web_client_id": "blank",
"aws_appsync_graphqlEndpoint": "https://endpoint.appsync-api.us-east-1.amazonaws.com/graphql",
"aws_appsync_region": "us-east-1",
"aws_appsync_authenticationType": "AWS_IAM"
}
So I update the private auth type to: @auth(rules: [{allow: owner}, {allow: private, provider: **iam**}] with the IAM role thinking that maybe that could be it. Sadly nothing.
This is the response I get from updating a record (network tab in dev console) in Amplify Studio. Also, dynamodb shows correctly the owner field.
{
"data":
{
"updateUserWorkout":
{
"id": "b4437755-8c18-407b-ab6d-93138af274cd",
"name": "e",
"datetime": "2022-07-10T13:13:00.000Z",
"status": "PENDING",
"videoKey": "hh",
"workoutType": "AMRAP",
"duration": 1,
"createdAt": "2022-07-10T22:13:28.054Z",
"updatedAt": "2022-07-10T22:19:10.669Z",
"_version": 5,
"_lastChangedAt": 1657491550707,
"_deleted": null
}
}
}
Responding your question: I update the model using the UI directly not composing any GraphQL document.
Maybe its something related to Amplify Studio? I tried updating from dynamodb as well but nothing.
What do you propose I should do in order to test if this is actually an Amplify Studio/AWS issue or something related to amplify-flutter ?
Hi @sanchez-gonzalo94 is your use case relying on following?
- Add/update record in Amplify Studio
- Expect amplify-flutter implemented mobile client to receive updates for above add/update with owner auth
If this is true, I doubt it's going to work...
Owner auth is per-user, meaning the records are tightly coupled with the owner user. This requires model creation is initiated from an end user of your App in order to make the auth scope work on syncing and subscription. When you operating on Amplify Studio, you are not add/update model by your end user, but your IAM role who is an admin.
Yes, my use case is that the user creates the record from the app then it syncs to the cloud and then from the backend with another auth type updates the given record and syncs back down to the end users app.
Something like: owner-and-static-group-combined but instead of a group of users from withing the app it should be from the backend.
The other weird thing is that if an owner-based record can be update from within Amplify Studio but the updates are not received if I stop and restart my app the model gets synced with the new updates.