Skip to content

Redundant calls to subschemas when the @canonical directive and inline fragments are used #1305

@JoergBastian

Description

@JoergBastian

Hello Hive maintainers,

I observed a behavior with the @graphql-tools/stitch library that doesn't make sense to me. I would appreciate if you could take a look at it and let me know if you consider this to be a bug.

In my scenario the library makes two requests to the same subschema for one incoming query where the second call appears to be redundant. In my tests this resulted in even wrong data returned by the gateway if the order of collections is not the exact same for the first and second subschema request.

Minimal Example

I attempted to reproduce it and assembled a minimal example showing this behavior here: https://github.com/JoergBastian/gql-stitching-redundant-calls-mre

The example with which I was able to reproduce this uses only one subschema. It consists of one subschema and one gateway, both using GraphQL Yoga. Stitching Directives from @graphql-tools/stitching-directives are used.

The behavior seems to be related to both the Query field box and the Box type using the @canonical directive. They are using this directive as in my real-life application the Box type would be extended by other subschemas.

SDL Excerpt:

type Query {
    box(id: ID!): Box @merge(keyField: "id") @canonical
}

type Box @canonical {
    id: ID!
    items(shuffle: Boolean): [Item]
}

Observed behavior

I execute the following query against the gateway:

{
  box(id: "1") {
    items {
      name,
      ...on Edible {
        calories
      }
    }
  }
}

The gateway logs two outgoing queries to the subschema:

Query #1: {
  __typename
  box(id: "1") {
    __typename
    id
    id
    items {
      __typename
      name
      ... on Edible {
        calories
      }
    }
  }
}
Query #2: query ($id: ID!) {
  __typename
  box(id: $id) {
    __typename
    id
    items {
      __typename
    }
  }
}

Looking at the second query, I fail to understand why it is made as all information queried should already be present in the first response.

The response is correct if the collection items is unchanged for the first and second call to the subschema. However, if the order of the items is changed between the first and second call, the types will be mixed up and fields missing that should be there.

Correct response
{
  "data": {
    "box": {
      "id": "1",
      "items": [
        {
          "name": "Apple",
          "calories": 95
        },
        {
          "name": "Banana",
          "calories": 105
        },
        {
          "name": "Cherry",
          "calories": 50
        },
        {
          "name": "Pen"
        }
      ]
    }
  }
}
Response when shuffeled
{
  "data": {
    "box": {
      "id": "1",
      "items": [
        {
          "name": "Pen",
          "calories": null
        },
        {
          "name": "Cherry",
          "calories": 50
        },
        {
          "name": "Banana",
          "calories": 105
        },
        {
          "name": "Apple"
        }
      ]
    }
  }
}

In the example, the Apple should have a calories field, the Pen shouldn't. If the schema is changed to require calories to not be null, the query will fail.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions