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

[Feedback]Make a GraphQL request for a nested query #663

Closed
mrtom opened this issue Jun 7, 2020 · 8 comments
Closed

[Feedback]Make a GraphQL request for a nested query #663

mrtom opened this issue Jun 7, 2020 · 8 comments
Labels
api Issues related to the API category feature-request Request a new feature follow up Requires follow up from maintainers

Comments

@mrtom
Copy link

mrtom commented Jun 7, 2020

Page: /lib/q/platform/ios

Feedback:

Hi there!

I'm trying to update a fairly straightforward app from the old Amplify SDK to the new Amplify Library. The docs don't have any migration guide sadly.

One thing that isn't at all clear is how you go about using custom queries with the API exposed by the library. The docs show how to fetch a single or list of a model, but not how to make a GraphQL request for, say, a nested query.

Please could you advise?

Many thanks!

@swaminator swaminator changed the title [Feedback]Migrating from the SDK to the new AP [Feedback]Make a GraphQL request for a nested query Jun 16, 2020
@mrtom
Copy link
Author

mrtom commented Jun 16, 2020

Thanks for clarifying the request @swaminator.

To add another (very related) query: By using custom queries I'm wanting to fetch nested objects with a single HTTP request but also wanting to avoid over-fetching of data by allowing engineers on the client side to specify which subset of fields they require.

Thanks!

@lawmicha
Copy link
Contributor

lawmicha commented Jul 22, 2020

Hi @mrtom, we have some ideas to provide a migration strategy for customers using AppSync SDK to Amplify API plugin. It may involve exensions that translate the code generated classes in AppSync over to the Amplify's GraphQLRequest so I'm thinking that we can better track this if I transfer the issue over to the Amplify iOS repo.

@lawmicha lawmicha transferred this issue from aws-amplify/docs Jul 22, 2020
@lawmicha lawmicha added the api Issues related to the API category label Jul 22, 2020
@lawmicha
Copy link
Contributor

To add another (very related) query: By using custom queries I'm wanting to fetch nested objects with a single HTTP request but also wanting to avoid over-fetching of data by allowing engineers on the client side to specify which subset of fields they require.

I believe a custom query where you pass a custom selection set is the first step to getting a subset of fields required on the client side. Are you constructing a GraphQLRequest with the graphql document containing customized selection set?

Then what is the responseType used when deserializing the response data? Are you using the Model classes generated from amplify codegen models or are you using an hand crafted Codable types that contain a subset of the fields?

@lawmicha lawmicha added enhancement documentation Documentation improvements labels Jul 22, 2020
@mrtom
Copy link
Author

mrtom commented Jul 27, 2020

I had imagined that a code gen step could/would be run that would generate models for a specific query, but in a strongly typed language like Swift it can be difficult to do well.

There are three approaches that I feel you could consider. Let's imagine you have a GraphQL schema like so, with a user and a post, and a many-to-many connection between users and posts.

type User
  @model
{
  id: ID!
  username: String!
  sub: String!
  posts: [UserPost] @connection(keyName: "byUser", fields: ["id"])
  createdAt: AWSDateTime!
}

type Post
  @model
{
  id: ID!
  associated: [UserPost] @connection(keyName: "byPost", fields: ["id"])
  title: String!
  body: String!
  createdAt: AWSDateTime!
}

type UserPost
  @model
  @key(name: "byUser", fields: ["userPostUserId", "userPostPostId"])
  @key(name: "byPost", fields: ["userPostPostId", "userPostUserId"])
{
  id: ID!
  user: User! @connection(fields: ["userPostUserId"])
  userPostUserId: ID!
  post: Post! @connection(fields: ["userPostPostId"])
  userPostPostId: ID!
  createdAt: AWSDateTime!
}

You may want to get a list of posts by created date or whatever and just render the the authors name next to each post. So you may create a GraphQL query like (haven't created this IRL, so may not be perfect):

query postsByCreatedAtQuery(input: { limit: 25} ) {
  posts {
    items {
       post {
         id
         title
         body
         createdAt
         associated {
           items {
             user {
               username
             }
           }
         }
       }
    }
  }
}

So here, you have a query that gets all the fields for the Post type, but only one field (the username) for the associated users.

I think you have three options:

  1. Codegen a type called postsByCreatedAtQuery_user, which is specific to the user fetched for this query and only gives the developer access to the username field on that type. This is essentially how the Amplify SDK worked I believe.
  2. Code gen a single User type but make all fields optional. This sucks for a bunch of reasons (not least that you're not respecting the optionality of types from the GraphQL schema). It is simpler for new developers to understand, but on a larger codebase can be tricky for people to figure out what data has been fetch and what has not.
  3. Create a new type, MUST_FETCH. And each code gen'd model now has fields that are a union type of some sort, i.e. username can be of type String | MUST_FETCH (a bit like a result type I suppose). You can now return your User model in this case, but all fields other than username are set to MUST_FETCH and if the code tries to read from them the code throws an error (in development at least), essentially indicating to the developer than they need to add the field to their GraphQL query.

You could also add some linting/static analysis to ensure that only fields which have been fetched are accessed. Relay does this for example, but requires adding fragments for each component. This doesn't work very well with UIKits programming model, but would work very well with SwiftUI.

@lawmicha lawmicha added feature-request Request a new feature follow up Requires follow up from maintainers and removed enhancement labels Jul 8, 2021
@lawmicha lawmicha added the p3 label Jun 8, 2022
@harsh62 harsh62 removed the documentation Documentation improvements label May 9, 2023
@thisisabhash
Copy link
Member

Hello,

We have an example to create custom GraphQL requests for nested data queries through the custom selection set feature.
https://docs.amplify.aws/cli/migration/lazy-load-custom-selection-set/#custom-selection-sets

Let us know if this works for you.

@armenr
Copy link

armenr commented Dec 23, 2023

@thisisabhash - How would this look for TypeScript/JavaScript? I've been after this for so, so long!

@thisisabhash
Copy link
Member

@armenr Please open an issue in the JS repo with your question: https://github.com/aws-amplify/amplify-js

@armenr
Copy link

armenr commented Dec 23, 2023

I'm good. I figured it out myself. Thanks for the quick instructions to open issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api Issues related to the API category feature-request Request a new feature follow up Requires follow up from maintainers
Projects
None yet
Development

No branches or pull requests

5 participants