Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Model parsing fails for complex non-model types #4872

Closed
7 of 14 tasks
ww-daniel-mora opened this issue May 10, 2024 · 3 comments
Closed
7 of 14 tasks

Model parsing fails for complex non-model types #4872

ww-daniel-mora opened this issue May 10, 2024 · 3 comments
Assignees
Labels
bug Something is not working; the issue has reproducible steps and has been reproduced CLI Issues related to the Amplify CLI GraphQL API Issues related to the API (GraphQL) Category pending-release Issues that have been addressed in main but have not been released

Comments

@ww-daniel-mora
Copy link

ww-daniel-mora commented May 10, 2024

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
  • API (REST)
  • 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

  • iOS
  • Android
  • Web
  • macOS
  • Windows
  • 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}")
}
@khatruong2009 khatruong2009 added GraphQL API Issues related to the API (GraphQL) Category pending-triage This issue is in the backlog of issues to triage REST API Issues related to the API (REST) Category labels May 10, 2024
@khatruong2009
Copy link
Member

Hi @ww-daniel-mora, we are looking into the issue now and will get back to you when we hvae an update.

@Equartey
Copy link
Member

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.

@Equartey Equartey added Investigating and removed pending-triage This issue is in the backlog of issues to triage labels May 14, 2024
@Equartey Equartey self-assigned this May 14, 2024
@Equartey Equartey added pending-release Issues that have been addressed in main but have not been released CLI Issues related to the Amplify CLI and removed REST API Issues related to the API (REST) Category labels May 14, 2024
@NikaHsn NikaHsn added the bug Something is not working; the issue has reproducible steps and has been reproduced label May 16, 2024
@Equartey
Copy link
Member

Equartey commented Jun 7, 2024

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.

@Equartey Equartey closed this as completed Jun 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something is not working; the issue has reproducible steps and has been reproduced CLI Issues related to the Amplify CLI GraphQL API Issues related to the API (GraphQL) Category pending-release Issues that have been addressed in main but have not been released
Projects
None yet
Development

No branches or pull requests

5 participants