amplify-flutter
amplify-flutter copied to clipboard
Model parsing fails for complex non-model types
Description
With amplify cli version 12.12.0 model parsing does not populate the value in any complex non-model types. The properties of any complex non-model type will be null.
Categories
- [ ] Analytics
- [X] API (REST)
- [X] API (GraphQL)
- [ ] Auth
- [ ] Authenticator
- [ ] DataStore
- [ ] Notifications (Push)
- [ ] Storage
Steps to Reproduce
Given a schema that contains a complex non-model type
type MyModel @model @auth(rules: [{allow: owner}]) {
id: ID!
owner: String
token: MyToken
}
type Token {
externalId: String!
value: String!
}
When calling AppSync and setting the model type:
const decodePath = 'getMyModel';
final graphQLDocument = '''
query GetMyModel(\$id: ID!) {
$decodePath(id: \$id) {
id
owner
token {
externalId
value
}
}
}
''';
final result = await Amplify.API.query(
request: GraphQLRequest<MyModel>(
modelType: const MyModel.classType,
document: graphQLDocument,
decodePath: decodePath,
).response;
Complex non model types (e.g. Token) will not have their properties populated, i.e result.data.token.value == null
would be true in the above example.
This break was introduces with CLI version 12.12.0 and worked prior to this version.
Screenshots
No response
Platforms
- [X] iOS
- [X] Android
- [X] Web
- [X] macOS
- [X] Windows
- [X] Linux
Flutter Version
3.19.6
Amplify Flutter Version
1.7.0
Deployment Method
Amplify CLI
Schema
type Wallet @model @auth(rules: [{ allow: owner }]) {
id: ID!
owner: String @auth(rules: [{ allow: owner, operations: [create, read, delete] }]) @index
profiles: [Profile]! @hasMany
activeProfile: Profile @hasOne
financialInstitutions: [FinancialInstitution] @hasMany
xpub: String!
baseDerivationPath: String! # should be constent across wallets but here for the sake of consistency
nextChildIndex: Int!
}
type UserData @model @auth(rules: [{ allow: owner }]) {
id: ID!
owner: String @auth(rules: [{ allow: owner, operations: [create, read, delete] }]) @index
plainTextData: PlainTextData
securedData: String!
securedDocuments: [SecuredDocument] @hasMany
xpub: String!
baseDerivationPath: String! # The base derivation path for user documents under this account
nextChildIndex: Int!
}
type FinancialInstitutionData @model @auth(rules: [{allow: private, provider: userPools}, {allow: private, provider: iam}]) {
id: ID!
logo: String
name: String! @index
externalId: String
searchId: String! @index
}
type FinancialInstitution @model @auth(rules: [{allow: owner}, {allow: private, provider: iam}]) {
id: ID!
owner: String @auth(rules: [{ allow: owner, operations: [create, read, delete] }]) @index(sortKeyFields: ["searchId"])
name: String!
accounts: [Account] @hasMany
accessTokens: [AccessToken] @hasMany
wallet: Wallet! @belongsTo
financialInstitutionData: FinancialInstitutionData! @hasOne
externalId: String
searchId: String!
products: [String]
xpub: String!
baseDerivationPath: String!
nextChildIndex: Int!
createdAt: AWSDateTime!
updatedAt: AWSDateTime!
}
type Account @model @auth(rules: [{ allow: owner }, {allow: private, provider: iam}]) {
id: ID!
owner: String @auth(rules: [{ allow: owner, operations: [create, read, delete] }])
nativeId: String
name: String!
mask: String
facts: [AccountFact] @hasMany
secretFacts: String
pendingFacts: String
type: String!
documents: [FinancialDocument] @hasMany
financialInstitution: FinancialInstitution! @belongsTo
xpub: String!
baseDerivationPath: String! # The base derivation path for documents under this account
nextChildIndex: Int!
updatedAt: AWSDateTime!
}
type SecuredDocument @model @auth(rules: [{ allow: owner }, {allow: private, provider: iam}]) {
id: ID!
owner: String @auth(rules: [{ allow: owner, operations: [create, read, delete] }]) @index(sortKeyFields: ["createdAt"])
derivationPath: String!
effectiveDate: AWSDate!
name: String
s3Key: String!
sha256: String!
size: Int!
type: DocumentType!
createdAt: AWSDateTime!
}
type FinancialDocument @model @auth(rules: [{ allow: owner }, {allow: private, provider: iam}]) {
id: ID!
owner: String @auth(rules: [{ allow: owner, operations: [create, read, delete] }])
externalId: String
name: String
sha256: String!
securedDocument: SecuredDocument! @hasOne
account: Account! @belongsTo
}
type AccessToken @model @auth(rules: [{ allow: owner }, {allow: private, provider: iam}]) {
id: ID!
owner: String @auth(rules: [{ allow: owner, operations: [create, read, delete] }]) @index
externalId: String! @index
type: TokenType!
flinksToken: FlinksToken
plaidToken: PlaidToken
financialInstitutionAccessTokensId: ID! @index(name: "accessTokenByDate", queryField: "accessTokenByDate", sortKeyFields: ["createdAt"])
financialInstitution: FinancialInstitution! @belongsTo
createdAt: AWSDateTime!
}
type Profile @model @auth(rules: [{ allow: owner }]) {
id: ID!
owner: String @auth(rules: [{ allow: owner, operations: [read, delete] }])
name: String!
wallet: Wallet! @belongsTo
sharePackageReports: [SharePackageReport] @hasMany
}
type ProfileLink @model @auth(rules: [{ allow: owner }, {allow: private, provider: iam}]) {
id: ID!
owner: String @auth(rules: [{ allow: owner, operations: [read, delete] }])
financialInstitution: FinancialInstitution! @hasOne
profile: Profile! @hasOne
profileLinkFinancialInstitutionId: ID!
profileLinkProfileId: ID! @index(name: "byProfileAndFI", sortKeyFields: ["profileLinkFinancialInstitutionId"], queryField: "profileLinksByProfileAndFI")
}
type AccountFact @model @auth(rules: [{ allow: owner }, { allow: private, provider: iam }]) {
id: ID!
owner: String @auth(rules: [{ allow: owner, operations: [read, delete] }])
key: String!
value: String!
account: Account! @belongsTo
}
type AssetReportJob @model @auth(rules: [{ allow: owner }, { allow: private, provider: iam }]) {
id: ID!
owner: String @auth(rules: [{ allow: owner, operations: [read, delete] }])
status: JobStatus!
externalId: String! @index
message: String
token: String
s3Bucket: String!
createdAt: AWSDateTime!
updatedAt: AWSDateTime!
lastReportId: String
financialInstitution: FinancialInstitution! @hasOne
assetReportJobFinancialInstitutionId: ID! @index(name: "assetReportJobByFI", queryField: "assetReportJobByFI", sortKeyFields: ["updatedAt"])
}
type SharePackageReport @model @auth(rules: [{ allow: owner }, { allow: private, provider: iam }]) {
id: ID!
owner: String @auth(rules: [{ allow: owner, operations: [read, delete] }])
profile: Profile! @belongsTo
generalInfo: SharePackageGeneralInfo!
identityData: SharePackageIdentityData
createdAt: AWSDateTime!
updatedAt: AWSDateTime!
profileSharePackageReportsId: ID! @index(name: "byProfile", sortKeyFields: ["createdAt"], queryField: "sharePackageReportsByProfile")
}
type ShareReportDocumentLink @model @auth(rules: [{ allow: owner }, {allow: private, provider: iam}]) {
id: ID!
owner: String @auth(rules: [{ allow: owner, operations: [read, delete] }])
financialDocument: FinancialDocument! @hasOne
report: SharePackageReport! @hasOne
shareReportDocumentLinkFinancialDocumentId: ID!
shareReportDocumentLinkReportId: ID! @index(name: "shareReportDocumentLinksByReportAndDocument", sortKeyFields: ["shareReportDocumentLinkFinancialDocumentId"], queryField: "shareReportDocumentLinksByReportAndDocument")
}
type SharePackageGeneralInfo {
packageName: String!
recipient: String! # API provider or recipient's email address domain
securedRecipientEmail: String # The secured recipient email if shared via email
selectedCategories: [SharePackageCategory]
}
type SharePackageIdentityData {
securedData: String!
securedDocumentsIds: [String]
}
enum SharePackageCategory {
identity
income
bank
investment
tax
creditAndLoan
}
enum JobStatus {
pending # not ready for processing
ready # ready for processing
processing # processing
completed # completed successfully
failed # failed
}
enum ItemStatus {
OK
ACCESS_NOT_GRANTED
INSTANT_MATCH_FAILED
INSUFFICIENT_CREDENTIALS
INVALID_CREDENTIALS
INVALID_MFA
INVALID_OTP
INVALID_PHONE_NUMBER
INVALID_SEND_METHOD
INVALID_UPDATED_USERNAME
ITEM_CONCURRENTLY_DELETED
ITEM_LOCKED
ITEM_LOGIN_REQUIRED
ITEM_NOT_FOUND
ITEM_NOT_SUPPORTED
MFA_NOT_SUPPORTED
NO_ACCOUNTS
NO_AUTH_ACCOUNTS
NO_INVESTMENT_ACCOUNTS
NO_INVESTMENT_AUTH_ACCOUNTS
NO_LIABILITY_ACCOUNTS
PRODUCT_NOT_ENABLED
PRODUCT_NOT_READY
PRODUCTS_NOT_SUPPORTED
USER_INPUT_TIMEOUT
USER_SETUP_REQUIRED
}
enum TokenType {
plaid
flinks
}
enum DocumentType {
financialStatement
payStub
identity
tax
form1099
w2
other
}
type PlaidToken {
accessToken: String!
itemId: String!
status: ItemStatus
institutionId: String
institutionName: String
}
type FlinksToken {
loginId: String!
institution: String!
}
type PlainTextData {
incomeUser: IncomeUser!
firstName: String
financialGoals: [FinancialGoal]
}
enum FinancialGoal {
realEstate
rentingAHome
wealthPlanning
}
type IncomeUser {
id: String!
token: String!
}
type UpdateStatementsResponse {
statusCode: Int!
updateResult: UpdateResult!
}
type ExchangeTokenResponse {
statusCode: Int!
accessTokenId: String!
fiExternalId: String!
fiId: String!
}
type GetExternalInstitutionIdResponse {
statusCode: Int!
institutionId: String!
}
type CreateIncomeUserResponse {
id: String!
token: String!
}
input UpdateStatementsInput {
accessTokenId: String!
s3Bucket: String!
fiId: String!
}
input ExchangeTokenInput {
institutionId: String
institutionName: String
nextFIIndex: Int!
nextFIXpub: String!
profileId: String!
publicToken: String!
walletId: String!
}
input NewLinkTokenInput {
products: [String]
optionalProducts: [String]
incomeUserToken: String
accessTokenId: String
packageName: String!
}
input CreateCustomFIInput {
accountSubtype: String!
accountType: String!
institutionName: String!
isTax: Boolean!
logo: String
nextFIIndex: Int!
nextFIXpub: String!
products: [String]!
profileId: String!
walletId: String!
}
type CreateCustomFIResponse {
statusCode: Int!
financialInstitution: FinancialInstitution!
}
input GetPayrollDataInput {
incomeUserToken: String!
s3Bucket: String!
}
input NewAssetReportJobsInput {
fiIds: [String]!
s3Bucket: String!
}
type NewAssetReportJobsResponse {
jobs: [AssetReportJob]!
updateResults: [UpdateResult]!
}
type GetPayrollDataResponse {
statusCode: Int!
accounts: Int!
documents: Int!
}
input RefreshDataInput {
profileId: String
fiId: String
}
type UpdateResult {
financialInstitutionId: String!
accountsUpdated: Int!
documentsUpdated: Int!
accessTokenId: String
accessTokenStatus: ItemStatus
}
type RefreshDataResponse {
statusCode: Int!
updateResults: [UpdateResult]!
}
input GenerateUserHmacInput {
userId: String!
}
type GenerateUserHmacResponse {
hmacWeb: String!
hmacAndroid: String!
hmacIos: String!
}
type Mutation {
newLinkToken(input: NewLinkTokenInput!): String! @function(name: "newLinkToken-${env}")
exchangeToken(input: ExchangeTokenInput!): ExchangeTokenResponse! @function(name: "exchangeToken-${env}")
updateStatements(input: UpdateStatementsInput!): UpdateStatementsResponse! @function(name: "updateStatements-${env}")
createIncomeUser: CreateIncomeUserResponse! @function(name: "createIncomeUser-${env}")
createCustomFI(input: CreateCustomFIInput!): CreateCustomFIResponse! @function(name: "createCustomFI-${env}")
getPayrollData(input: GetPayrollDataInput!): GetPayrollDataResponse! @function(name: "getPayrollData-${env}")
newAssetReportJobs(input: NewAssetReportJobsInput!): NewAssetReportJobsResponse! @function(name: "newAssetReportJobs-${env}")
refreshData(input: RefreshDataInput!): RefreshDataResponse! @function(name: "refreshData-${env}")
generateUserHmac(input: GenerateUserHmacInput!): GenerateUserHmacResponse! @function(name: "generateUserHmac-${env}")
}
Hi @ww-daniel-mora, we are looking into the issue now and will get back to you when we hvae an update.
Hi @ww-daniel-mora, sorry to hear you ran into this issue. Thank you for the detailed reproduction steps.
I've opened a PR to address this on the CLI side.
Also note this workflow is already working in Amplify Flutter 2.0, however we are still working on the full migration guide from 1.X. Stay on the lookout for updates on when it's available.
In the meantime, you can downgrade your CLI version to unblock any issue. npm install -g @aws-amplify/[email protected]
I will update you when the fix becomes available.
Hi @ww-daniel-mora, thank you for your patience.
A fix for this issue in Amplify Flutter V1 has been released in Amplify CLI 12.12.2
. Please update your CLI and regenerate models to consume the fix.
I'm going to close this as resolved. If you have any additional issues, don't hesitate to reach out.