Closed printSamuel closed 4 months ago
Hi @printSamuel, I think this is a misunderstanding of how to integrate customType
into a backend. Lets walk through how you can achieve your end goal:
The goal is to develop a Flutter app that uses a single-table design for the backend.
The previous approach is flawed, because as you mentioned there is no backend generated to store your custom type.
Amplify maps every Model to a DynamoDB table 1:1. In order to get a single table, with multiple custom types, you should have them live under the same model. This will allow use of the API model helpers, ie ModelMutations
, to create GraphQL requests to mutate data. You can find an example of that on our documentation page and here is an example to tie back to your original schema:
a.schema({
MyModel: a.model({
SuEItem: a.customType({
PK: a.string().required(),
SK: a.string().required(),
author: a.string().required(),
title: a.string(),
content: a.string(),
}),
// Other properties & custom types
foo: a.string(),
}),
});
In this example, your top level Model becomes MyModel
. Which will have a corresponding DynamoDB table created. It will also have your custom type SuEItem
as a property, ie MyModel.SuEItem
. This property will not have a DynamoDB table created for it. This pattern will enable code gen to create the proper interface mapping for use with ModelMutations.create()
.
Let me know if that satisfies your use case. We're here to help and answer questions.
Thanks for the reply. Overall, I am satisfied with the outcome. However, I won't be using your idea directly. Still, your suggestion provided me with valuable knowledge.
In case anyone is interested in my final solution, here is a step-by-step guide on how I achieved the desired result based on your input:
Initially, your suggestion resulted in this:
However, my goal was to achieve something like this:
To reach my goal, I deleted the Amplify-generated resolvers and created my own. This approach allowed me to achieve my desired outcome, but it was quite challenging. Every subtype(or model inside MyModel) required another if-else branch, making querying VERY difficult. The main issue was that I couldn't write different resolvers and had to manage everything within one resolver to work with all my subtypes(or models inside MyModel).
Now, I don't use ModelMutations.create() in the frontend. Instead, I make GraphQL queries. This change means I don't need custom types(or models inside MyModel) to be part of the same model, and it's fine if they don't extend amplify_core.Model. I can handle the GraphQL response and convert everything into the Amplify-generated model myself.
My final:
My resouce.ts schema:
const schema = a.schema({
Todo: a
.model({
content: a.string(),
})
.authorization((allow) => [allow.guest()]),
Mytesting: a.customType({
PK: a.string().required(),
SK: a.string().required(),
firstname: a.string(),
}),
//add more models here...
//write custom resolvers
getMytesting: a
.query()
.arguments({
PK: a.string().required(),
SK: a.string().required(),
})
.returns(a.ref("Mytesting"))
.authorization(allow => [allow.publicApiKey()])
.handler(
a.handler.custom({
dataSource: "ExternalTableDataSource",
entry: "./getMytesting.js",
})
),
//addMytesting...
//deleteMytesting...
//add resolvers for any other type you might create
});
getMytesting.js:
import * as ddb from "@aws-appsync/utils/dynamodb";
//this code might not be the final you want...
export function request(ctx) {
return ddb.get({ key: { PK: ctx.args.PK, SK: ctx.args.SK } });
}
export const response = (ctx) => ctx.result;
backend.ts (Note: You need to manually create the DynamoDB table via the dashboard first. I named mine "SingleTable." If you choose a different name, make sure to replace "SingleTable" with your table's name in the following steps..
import { defineBackend, defineData } from "@aws-amplify/backend";
import { auth } from "./auth/resource";
import { data } from "./data/resource";
import { aws_dynamodb } from "aws-cdk-lib";
export const backend = defineBackend({
auth,
data,
});
const externalDataSourcesStack = backend.createStack("MyExternalDataSources");
const externalTable = aws_dynamodb.Table.fromTableName(
externalDataSourcesStack,
"MyExternalTable",
"SingleTable"
);
backend.data.addDynamoDbDataSource(
"ExternalTableDataSource",
externalTable
);
Frontend-Code:
String a = "pmkey";
String b = "pmkey";
final request = GraphQLRequest(
document: '''
query MyQuery(\$PK: String!, \$SK: String!) {
getMytesting(PK: \$PK, SK: \$SK) {
PK
SK
firstname
}
}
''',
variables: {'PK': a, 'SK': a},
);
final response =
await Amplify.API.query(request: request).response;
// final todos = response.data?.items;
// if (todos == null) {
// safePrint('errors: ${response.errors}');
// }
safePrint("response: $response");
Map<String, dynamic> jsonMap = json.decode(response.data!);
safePrint("JsonMap: $jsonMap");
Map<String, dynamic> nestedJson = jsonMap['getMytesting'];
//xxx.fromJson method is generated from modelgen
Mytesting mytest = Mytesting.fromJson(nestedJson);
safePrint("mytest: $mytest");
safePrint(mytest.firstname);
} catch (e) {
print("Error: $e");
}
Description
The goal is to develop a Flutter app that uses a single-table design for the backend. Following the recommendations in the documentation, instead of defining the model like this:
I do it like:
Using 'a.customType()' ensures that Amplify does not generate resolvers or create a DynamoDB table for this specific model, which is exactly what I want.
Model generation and publishing work without errors. However, when attempting to use the generated model in the flutter frontend, I encounter an issue: the generated model does not extend amplify_core.Model. Therefore I have red lines:
final request = ModelMutations.create(todo);
Should it not extend Model, or is there a misunderstanding or a bug?
Categories
Steps to Reproduce
Create flutter project with amplify gen2
In your resource.ts file add:
Run npx ampx sandbox --outputs-format dart --outputs-out-dir lib --outputs-version 0
Run npx ampx generate graphql-client-code --format modelgen --model-target dart --out /Users/YOUR-DESIRED-PATH
Screenshots
When using: a.model()
When using: a.customType()
Platforms
Flutter Version
3.22.0
Amplify Flutter Version
2.1.0
Deployment Method
Amplify CLI + Custom Pipeline
Schema
No response