I am trying to execute a simple GraphQL query in my Flutter project. The goal is to get a list of customers with a nested list of devices. However, the results are not being parsed properly and i found some inconsistency between appsync and my project appsync calls. I am pretty new to aws and so i am not familiar how to approach this problem the best way. It would be great if someone can guide me a little here :).
I have created a backend using Amplify Studio and imported it into my project. I created the models in my project with "amplify codegen models".
Here is the Schema:
type Customer @model @auth(rules: [{allow: public}]) {
id: ID!
devices: [Device] @hasMany(indexName: "byCustomer", fields: ["id"])
first_name: String
last_name: String
email: AWSEmail!
}
type Device @model @auth(rules: [{allow: public}]) {
id: ID!
sessions: [Session] @hasMany(indexName: "byDevice", fields: ["id"])
customer_id: ID @index(name: "byCustomer")
thing_name: String!
}
Running the desired query in appsync
query MyQuery {
listCustomers {
items {
id
email
first_name
last_name
devices {
items {
id
thing_name
customer_id
}
}
}
}
}
gives me this response, where devices is an object with the items property which is an array of devices:
{
"data": {
"listCustomers": {
"items": [
{
"id": "585a6b7e-e3f5-4cd6-9e7b-f1860f559e5c",
"email": "[email protected]",
"first_name": "Max",
"last_name": "Mustermann",
"devices": {
"items": [
{
"id": "ca7bf7f9-b0c7-4a83-a7cc-a7b7d0678db7",
"thing_name": "Device_002",
"customer_id": "585a6b7e-e3f5-4cd6-9e7b-f1860f559e5c"
},
{
"id": "24967d96-29b9-4ef9-b6d2-684002166a40",
"thing_name": "Device_003",
"customer_id": "585a6b7e-e3f5-4cd6-9e7b-f1860f559e5c"
}
]
}
},
{
"id": "fdcca2c9-ec12-4ce2-a439-15f14bc00d55",
"email": "[email protected]",
"first_name": "inautequiconsec",
"last_name": "mollitametmagnaaliq",
"devices": {
"items": [
{
"id": "520d9441-d026-45b0-9c3c-26f848e8e728",
"thing_name": "Device_001",
"customer_id": "fdcca2c9-ec12-4ce2-a439-15f14bc00d55"
}
]
}
}
]
}
}
}
Running the same query from my flutter project:
Future<void> _refreshCustomerList() async {
const listCustomers = 'listCustomers';
const graphQLDocument = '''query MyQuery {
$listCustomers {
items {
id
email
first_name
last_name
devices {
items {
id
thing_name
customer_id
}
}
}
}
}''';
final listCustomersRequest = GraphQLRequest<PaginatedResult<Customer>>(
document: graphQLDocument,
modelType: const PaginatedModelType(Customer.classType),
decodePath: listCustomers,
);
try {
final response =
await Amplify.API.query(request: listCustomersRequest).response;
if (response.hasErrors) {
safePrint('errors: ${response.errors}');
return;
}
final data = response.data;
final items = response.data?.items;
safePrint('response: $response');
safePrint('data: $data');
safePrint('items: $items');
setState(() {
// set _customerList
});
} on ApiException catch (e) {
safePrint('Query failed: $e');
}
}
results in this logs, where devices is not an object with items in it but an array of devices itself:
flutter: response: GraphQLResponse<PaginatedResult<Customer>> success: {
"items": [
{
"id": "585a6b7e-e3f5-4cd6-9e7b-f1860f559e5c",
"devices": [
{
"id": "ca7bf7f9-b0c7-4a83-a7cc-a7b7d0678db7",
"sessions": null,
"customer_id": "585a6b7e-e3f5-4cd6-9e7b-f1860f559e5c",
"thing_name": "Device_002",
"createdAt": null,
"updatedAt": null
},
{
"id": "24967d96-29b9-4ef9-b6d2-684002166a40",
"sessions": null,
"customer_id": "585a6b7e-e3f5-4cd6-9e7b-f1860f559e5c",
"thing_name": "Device_003",
"createdAt": null,
"updatedAt": null
}
],
"first_name": "Max",
"last_name": "Mustermann",
"email": "[email protected]",
"createdAt": null,
"updatedAt": null
},
{
"id": "fdcca2c9-ec12-4ce2-a439-15f14bc00d55",
"devices": [
{
"id": "520d9441-d026-45b0-9c3c-26f848e8e728",
"sessions": null,
"customer_id": "fdcca2c9-ec12-4ce2-a439-15f14bc00d55",
"thing_name": "Device_001",
"createdAt": null,
"updatedAt": null
}
],
"first_name": "inautequiconsec",
"last_name": "mollitametmagnaaliq",
"email": "[email protected]",
"createdAt": null,
"updatedAt": null
}
],
"nextToken": null
}
flutter: data: Instance of 'PaginatedResult<Customer>'
flutter: items: [Customer {id=585a6b7e-e3f5-4cd6-9e7b-f1860f559e5c, first_name=Max, last_name=Mustermann, [email protected], createdAt=null, updatedAt=null}, Customer {id=fdcca2c9-ec12-4ce2-a439-15f14bc00d55, first_name=inautequiconsec, last_name=mollitametmagnaaliq, email=busi[email protected], createdAt=null, updatedAt=null}]
The problem now is, that those devices are not getting parsed properly to be in the Customer Object as seen in the logs. The generated Customer.fromJson looks like this:
Customer.fromJson(Map<String, dynamic> json)
: id = json['id'],
_devices = json['devices'] is List
? (json['devices'] as List)
.where((e) => e?['serializedData'] != null)
.map((e) => Device.fromJson(
new Map<String, dynamic>.from(e['serializedData'])))
.toList()
: null,
_first_name = json['first_name'],
_last_name = json['last_name'],
_email = json['email'],
_createdAt = json['createdAt'] != null
? amplify_core.TemporalDateTime.fromString(json['createdAt'])
: null,
_updatedAt = json['updatedAt'] != null
? amplify_core.TemporalDateTime.fromString(json['updatedAt'])
: null;
I think the problem is, that for whatever reason the .fromJson function looks for a ‘serializedData’ but there is no property with that name in the response object. I tried getting rid of the check for serializedData but got multiple other errors.
I am really confused why the ‘amplify codegen models’ created the class this way and i am not sure if i should just edit the .fromJson method to a state where it works or if this will cause other issues down the line.
I also tried the call with ModelQueries.list. There i even dont get any devices in my response. I dont know why, and i am not sure if that may be part of the problem:
Future<void> _getCustomerList() async {
try {
final request = ModelQueries.list(Customer.classType);
final response = await Amplify.API.query(request: request).response;
final items = response.data?.items;
if (response.hasErrors) {
safePrint('errors: ${response.errors}');
return;
}
safePrint('response: $response');
safePrint('items: $items');
setState(() {
// // set _customerList
});
} on ApiException catch (e) {
safePrint('Query failed: $e');
}
}
Logs:
Reloaded 1 of 2701 libraries in 1.425ms (compile: 44 ms, reload: 619 ms, reassemble: 707 ms).
flutter: response: GraphQLResponse<PaginatedResult<Customer>> success: {
"items": [
{
"id": "585a6b7e-e3f5-4cd6-9e7b-f1860f559e5c",
"devices": null,
"first_name": "Max",
"last_name": "Mustermann",
"email": "[email protected]",
"createdAt": "2023-10-01T19:07:43.072000000Z",
"updatedAt": "2023-10-03T17:00:34.083000000Z"
},
{
"id": "fdcca2c9-ec12-4ce2-a439-15f14bc00d55",
"devices": null,
"first_name": "inautequiconsec",
"last_name": "mollitametmagnaaliq",
"email": "[email protected]",
"createdAt": "2023-10-01T19:07:43.125000000Z",
"updatedAt": "2023-10-01T19:07:43.125000000Z"
}
],
"nextToken": null
}
flutter: items: [Customer {id=585a6b7e-e3f5-4cd6-9e7b-f1860f559e5c, first_name=Max, last_name=Mustermann, [email protected], createdAt=2023-10-01T19:07:43.072000000Z, updatedAt=2023-10-03T17:00:34.083000000Z}, Customer {id=fdcca2c9-ec12-4ce2-a439-15f14bc00d55, first_name=inautequiconsec, last_name=mollitametmagnaaliq, [email protected], createdAt=2023-10-01T19:07:43.125000000Z, updatedAt=2023-10-01T19:07:43.125000000Z}]