ChilliCream / graphql-platform

Welcome to the home of the Hot Chocolate GraphQL server for .NET, the Strawberry Shake GraphQL client for .NET and Banana Cake Pop the awesome Monaco based GraphQL IDE.
https://chillicream.com
MIT License
5.24k stars 744 forks source link

Query issued to Fusion Gateway only returns from one subgraph #6490

Open wdorsett84 opened 1 year ago

wdorsett84 commented 1 year ago

Is there an existing issue for this?

Product

Hot Chocolate

Describe the bug

I have two subgraphs that I use fusion on to compose into gateway.fsp. When I try to query the gateway with fields from both subgraphs, only one subgraph returns results.

One subgraph has a schema as:

schema {
  query: Query
}

type Query {
  users: [User!]
}

type User {
  id: Int!
  name: String!
  birthdate: String
  username: String!
}

with a config as follows:

{"subgraph":"account","http":{"baseAddress":"http://localhost:5025/graphql"}}

and the other has schema as:

schema {
  query: Query
}

type Author {
  id: Int!
  name: String!
  reviews: [Review!]!
}

type Query {
  authors: [Author!]
}

type Review {
  id: Int!
  body: String!
  stars: Int!
  productId: Int!
  authorId: Int!
  author: Author!
}

with a config as follows:

{"subgraph":"review","http":{"baseAddress":"http://localhost:5026/graphql"}}

I also have a schema extensions file as follows:

extend schema 
    @rename(coordinate: "Author", newName: "User")
    @rename(coordinate: "Query.authors", newName: "users")
{

}

I am able to pack both subgraphs appropriately and compose the gateway. I run the query:

{
  users {
    name,
    birthdate,
    reviews {
      body
    }
  }
}

but the response is as follows (including execution plan):

The query plan is as below but only one subgraph resolves

{
  "data": {
    "users": [
      {
        "name": "Ada Lovelace",
        "reviews": []
      },
      {
        "name": "Alan Turing",
        "reviews": []
      }
    ]
  },
  "extensions": {
    "queryPlan": {
      "document": "{ users { name birthdate reviews { body } } }",
      "rootNode": {
        "type": "Sequence",
        "nodes": [
          {
            "type": "Parallel",
            "nodes": [
              {
                "type": "Resolve",
                "subgraph": "review",
                "document": "query fetch_users_1 { users: authors { name reviews { body } } }",
                "selectionSetId": 11
              },
              {
                "type": "Resolve",
                "subgraph": "account",
                "document": "query fetch_users_2 { birthdate }",
                "selectionSetId": 12
              }
            ]
          },
          {
            "type": "Compose",
            "selectionSetIds": [
              11,
              12
            ]
          }
        ]
      }
    },
    "queryPlanHash": "A0AEF480A12864E2D68ABF2FDF5C4787577989ED"
  }
}

According to execution plan only one subgraph actually resolves. Any idea what I am doing wrong? I believe the resolvers are set up appropriately but any insight would be appreciated.

Steps to reproduce

  1. Create a folder with above schema file and subgraph config.
  2. dotnet tool restore (Note, I am using HotChocolate.Fusion.CommandLine version 13.4.0)
  3. dotnet fusion subgraph pack -w ./subgraphs/account
  4. dotnet fusion subgraph pack -w ./subgraphs/reviews
  5. dotnet fusion compose -p ./fusion-gateway/gateway.fgp -s ./subgraphs/account
  6. dotnet fusion compose -p ./fusion-gateway/gateway.fgp -s ./subgraphs/account
  7. Repo can be found here

Relevant log output

No response

Additional Context?

No response

Version

13.4.0

tobias-tengler commented 1 year ago

You don't seem to have any way to resolve a user by a key (for example Id) in either subgraph. How should the engine know where to go on the other subgraph to resolve the birthdate for example? Do both authors and users return a list where each user item is at the same index? I don't think that's something Fusion would or should be able to handle. @michaelstaib what do you think?

This query plan step on the other hand seems to be just wrong and it should've just failed in the compose step IMO:

{
  "type": "Resolve",
  "subgraph": "account",
  "document": "query fetch_users_2 { birthdate }",
  "selectionSetId": 12
}

I think your best bet is to just introduce fields like authorsByIds(ids: [Int!]!) and authorById(id: Int!) on each subgraph. With the latest 13.6 preview version you also shouldn't have to annotate anything and it should just work. Your Ids are also not of the ID type - I'm not sure if Fusion just goes by the field name to determine if something is an Id. If things don't work as expected, consider using the ID scalar (it would be good in general).

michaelstaib commented 1 year ago

13.6 is focusing on these things. It should be a composition error. Also there is a way to resolve it with two queries from the top. If you want to get it to work with 13.5 you need entity resolvers.

wdorsett84 commented 1 year ago

@tobias-tengler thank you. I will try adding resolvers that return by id. Is that what is meant by entity resolvers @michaelstaib ? Having a type on a schema that returns one type?

Also is there a way to specify multiple fields as an ID type?

byme8 commented 1 year ago

I had the same issue with the following schemas: System Subgraph

type Query {
  listingsByIds(ids: [ID!]!): [Listing!]!
}

type Listing {
  id: ID!
  price: Float!
}

Search Subgraph


type Query {
  listingsByIds(ids: [ID!]!): [Listing!]!
}

type Listing {
  id: ID!
  address: String!
}

Merged:

type Query {
  listingsByIds(ids: [ID!]!): [Listing!]!
}

type Listing {
  address: String!
  id: ID!
  price: Float!
}

I can get only one of the subgraph at the same time. When I added listingById(id: ID!): Listing it started working as expected. However, it was not really straight forward and from logical perspective it should not be an error because both subgraphs have listingsByIds(ids: [ID!]!): [Listing!]! and we can execute them just with different field selection.