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

Why isn't swift returning my 1:m model data? #376

Closed
mreaybeaton opened this issue Apr 2, 2020 · 7 comments
Closed

Why isn't swift returning my 1:m model data? #376

mreaybeaton opened this issue Apr 2, 2020 · 7 comments
Labels
question A question about how to use an existing feature

Comments

@mreaybeaton
Copy link

I have a 1:m relationship, but when I query the User to get all the associated posts, I am not getting back any posts.

Schema:

type User @model {
  id: ID!
  fullName: String!
  emailAddress: String!
  posts: [Post] @connection(name: "UserPostConnection")
}

type Post @model {
  id: ID!
  text: String!
  user: User @connection(name: "UserPostConnection")
  createdAt: String
  updatedAt: String
}

Query:
query {
	getUser(id: "879db4f2-1dad-47b9-b70d-8bca15bf2549") {
	  id 
    posts {
      items {
        id
      }
    }
	}
}

Output:
{
  "data": {
    "getUser": {
      "id": "879db4f2-1dad-47b9-b70d-8bca15bf2549",
      "posts": {
        "items": [
          {
            "id": "04c4b571-6e92-4745-9a40-1a67a9d49d77"
          },
          {
            "id": "0f44fe6e-4e15-4a8c-b591-555e8fa1f60e"
          },
          {
            "id": "60c18c40-fea3-4ff3-8b21-df6857703dd2"
          }
        ]
      }
    }
  }
}
        let queryInput = GetUserQuery(id: "879db4f2-1dad-47b9-b70d-8bca15bf2549")
        appSyncClient?.fetch(query: queryInput, cachePolicy: .fetchIgnoringCacheData) { (result, error) in
            print(result?.data?.getUser?.posts)
        }

output:

Optional(AWSStackSocial.GetUserQuery.Data.GetUser.Post(snapshot: ["__typename": Optional("ModelPostConnection"), "nextToken": nil]))

Whereas if I run this ListPosts I can see all the posts. As you can see from the grapql queries, the data is associated, so I am unsure what I am doing wrong?

@palpatim palpatim added AppSync question A question about how to use an existing feature labels Apr 3, 2020
@dgaeta
Copy link

dgaeta commented Apr 14, 2020

Facing the same issue, I have increased the maximum depth to 8 and I still see nil on "items" from the iOS client.
When I go into the AppSync console and query on the User, I am able to see the items data as expected, but from the iOS client I see nil.

@mreaybeaton
Copy link
Author

Facing the same issue, I have increased the maximum depth to 8 and I still see nil on "items" from the iOS client.
When I go into the AppSync console and query on the User, I am able to see the items data as expected, but from the iOS client I see nil.

Hi dgaeta, after A LOT of research, it isn't exactly clear, but I have worked out how it needs to be done.

The cli will create a graphql folder in your main xcode project, in here you will find the queries.graphql, mutations.graphql etc, and from here the cli generates the API.swift file that you can use to query the data directly from swift. What you need to do is create your OWN graphql file in this folder, with your queries that you use in AWS AppSync console.

So as an example, my original post above referenced the above code that would get all the post items associated with a user.

query getPosts {
	getUser(id: "879db4f2-1dad-47b9-b70d-8bca15bf2549") {
	  id 
           posts {
                items {
                   id
              }
         }
    }
}

this would need to be added to your myqueriesfile.graphql file that you have added to the graphql folder in your main xcode project.

But this query isn't ready to be used yet, you need to make a modification so that you can use the id, so the above would look like:

query getPosts ($id: String) {
	getUser(id: $id) {
	  id 
           posts {
              items {
                    id
             }
       }
   }
}

Once you have your query in your file, you need to regenerate the code, so I think you can either do amplify codegen or amplify push, and the cli will generate this method in your API.swift. Once that is done, you can then access the items :)

Let me know if that isn't clear.

@lawmicha
Copy link
Member

lawmicha commented Apr 14, 2020

hi @mickeysox, thanks for sharing your research for others to learn from. I could not reproduce the issue with missing posts when retrieving the user.

  1. I ran amplify add api and used your schema with the User and Post model
  2. amplify push and chose these
? Do you want to generate code for your newly created GraphQL API Yes
? Enter the file name pattern of graphql queries, mutations and subscriptions graphql/**/*.graphql
? Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions Yes
? Enter maximum statement depth [increase from default if your schema is deeply nested] 2
? Enter the file name for the generated code API.swift
  1. amplify console api, went to the Queries tab of the AppSync console, created a user with id "111" and a post with id "222" which has a postUserId = "111". When i query for the user, i can confirmed that the data is there

  2. over in the xcode project, i am using AppSyncClient 3.1.0, and the API.Swift that was generated, contains

public final class GetUserQuery: GraphQLQuery {
  public static let operationString =
    "query GetUser($id: ID!) {\n  getUser(id: $id) {\n    __typename\n    id\n    fullName\n    emailAddress\n    posts {\n      __typename\n      items {\n        __typename\n        id\n        text\n        createdAt\n        updatedAt\n      }\n      nextToken\n    }\n  }\n}"

This looks correct to me as the selection set contains items corresponding to the posts in the User.
5. Retrieving the user gives me the posts back

appSyncClient?.fetch(query: getQuery) { (result, error) in
            if error != nil {
                print(error?.localizedDescription ?? "")
                return
            }
            print(result)
            print(result?.data?.getUser?.posts)
}

I am currently using amplify CLI 4.12.0

Which version of Amplify CLI are you using?
Which version of AppSyncClient are you using?
Can you verify that you are setting the maximum statement depth to 2?
What do you see as the operationString for GetUserQuery in API.swift? This determines what comes back in the response from the service, and should deserialize properly

@lawmicha lawmicha added the requesting info Further information is needed before this is actionable label Apr 14, 2020
@mreaybeaton
Copy link
Author

Hi @lawmicha

Thank you very much for your feedback, that makes absolute sense what you are suggesting, it seemed odd this wasn't something that worked out of the box.

I have created a brand new project and followed your exact suggestions, but it hasn't worked. My GetUser is as follows:

public final class GetUserQuery: GraphQLQuery {
  public static let operationString =
    "query GetUser($id: ID!) {\n  getUser(id: $id) {\n    __typename\n    id\n    fullName\n    emailAddress\n    posts {\n      __typename\n      nextToken\n    }\n  }\n}"

Which doesn't display the items under posts. Just to confirm, this was based on entering the Maximum depth of 2, as you have suggested. However if I run amplify codegen configure and change it to 3, my output is...

public final class GetUserQuery: GraphQLQuery {
  public static let operationString =
    "query GetUser($id: ID!) {\n  getUser(id: $id) {\n    __typename\n    id\n    fullName\n    emailAddress\n    posts {\n      __typename\n      items {\n        __typename\n        id\n        text\n        createdAt\n        updatedAt\n      }\n      nextToken\n    }\n  }\n}"

from the generated queries.graphql file

# this is an auto generated file. This will be overwritten
query GetUser($id: ID!) {
  getUser(id: $id) {
    id
    fullName
    emailAddress
    posts {
      items {
        id
        text
        createdAt
        updatedAt
      }
      nextToken
    }
  }
}

The changes I have made...

~/Documents/Development/AWSTesting master*
❯ amplify codegen configure
? Enter the file name pattern of graphql queries, mutations and subscriptions graphql/**/*
.graphql
? Enter the file name for the generated code API.swift
? Enter maximum statement depth [increase from default if your schema is deeply nested] 2

~/Documents/Development/AWSTesting master* 8s
❯ amplify codegen
✔ Generated GraphQL operations successfully and saved at graphql
✔ Code generated successfully and saved in file API.swift

~/Documents/Development/AWSTesting master*
❯ amplify codegen configure
? Enter the file name pattern of graphql queries, mutations and subscriptions graphql/**/*
.graphql
? Enter the file name for the generated code API.swift
? Enter maximum statement depth [increase from default if your schema is deeply nested] 3

~/Documents/Development/AWSTesting master* 14s
❯ amplify codegen
✔ Generated GraphQL operations successfully and saved at graphql
✔ Code generated successfully and saved in file API.swift

~/Documents/Development/AWSTesting master*
❯ 

I find it strange that 2 isn't enough? In answer to your questions:

Which version of Amplify CLI are you using? 4.17.2
Which version of AppSyncClient are you using? 3.1.0 (although I never installed the pods for this)
Can you verify that you are setting the maximum statement depth to 2? (as above, 2 doesn't work, 3 does)
What do you see as the operationString for GetUserQuery in API.swift? This determines what comes back in the response from the service, and should deserialize properly (as above)

Any thoughts? Thank you so much for your reply, I really appreciate it.

@lawmicha
Copy link
Member

thanks for details, I would expect a max depth of 2 to be generating the correct selection set. since it was working in 4.12.0 (version I used) then there may have been a change that was introduced. i've opened an issue over in the CLI repo https://github.com/aws-amplify/amplify-cli/issues/3971

@lawmicha lawmicha removed the requesting info Further information is needed before this is actionable label Apr 15, 2020
@mreaybeaton
Copy link
Author

Thanks @lawmicha I appreciate that. The good news is that the code is being generated as I originally expected and no further queries are necessary to retrieve the lower levels. Albeit unintuitive to have 3 levels instead of 2. Thank you again for your support, it did feel like a hack to have to manually generate the query!. Hopefully the guys can clarify on the bug report.

@atierian
Copy link
Member

atierian commented Dec 7, 2023

Please refer to this comment aws-amplify/amplify-codegen#23 (comment) for a workaround.

@atierian atierian closed this as completed Dec 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question A question about how to use an existing feature
Projects
None yet
Development

No branches or pull requests

5 participants