ardatan / ardatan/graphql-tools
Delegate removes selection sets when nesting Top-Level Abstract Fields in a Mutation response
- Dominant language
- TypeScript
- Stars
- 5.4k
- Forks
- 830
- Avg merge
- 10h 59m
- Merged PRs (30d)
- 45
Description
Hi, we have a graphql API with the following structure
```GraphQL
interface Foo {
pk: ID
}
type Bar implements Foo {
pk: ID
bar: String
}
type Nested {
foo: Foo
}
type Query {
foo: Foo
nested: Nested
}
type MutationResponseType {
query: Query
}
type Mutation {
someMutation(pk: ID!): MutationResponseType
}
```
**Describe the bug**
When using the mutation with a Fragment on Query, fields of the Interface are removed when used on top level. I.e.
```graphQL
mutation SomeMutation {
someMutation(id: "234") {
query {
...MyFragment
}
}
}
fragment MyFragment on Query {
foo {
... on Bar {
pk
}
}
}
```
gets transformed to
```graphQL
mutation SomeMutation {
someMutation(id: "234") {
__typename
query {
__typename
...MyFragment
}
}
}
fragment MyFragment on Query {
foo {
__typename
}
}
```
This does not happen when either the Fragment is not on top level or the Interface is nested. I.e. the following work:
```graphQL
mutation SomeMutation {
someMutation(id: "234") {
query {
foo {
...NotTopLevel
}
...MyFragment
}
}
}
fragment NotTopLevel on Foo {
... on Bar {
pk
}
}
fragment Nested on Query {
nested {
foo {
... on Bar {
pk
}
}
}
}
```
**To Reproduce**
Steps to reproduce the behavior:
I tried to write a test in the repo but did not succeed with providing the right test-input.
However, with a working client on our actual production code I was able to debug into it and find out where it goes wrong for us:
In `wrapConcreteTypes` in `prepareGatewayDocument.ts`, you create new selections and set the type conditions. However, this type gets set to `MutationReturnType`.

This causes problems later down the line in `finalizeSelectionSet` where the fields are discarded, as the types do not match (sorry for the ugly screenshot, had to wipe our internal names). I _think_ , there should be the implementing type instead of the second Type, i.e. `Bar`.

When I comment out the `FIELD` visitor in `wrapConcreteTypes`, everything works as expected (well, for our small case).
Hope that helps even if I could not provide a minimum reproducible version.
**Expected behavior**
Valid attributes should not be discarded
**Environment:**
- `@graphql-tools/delegate`: 9.0.21
- NodeJS: LTS Gallium
Contributor guide
Research direction
Start in prepareGatewayDocument.ts, particularly wrapConcreteTypes and its FIELD visitor, then trace how the resulting selections are handled by finalizeSelectionSet. Reproduce the mutation and fragment shape from the issue, verify where the implementing type condition is lost, and confirm that valid fields such as Bar.pk are preserved without breaking the working nested cases.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend-api-design
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100