apollographql / apollographql/federation
[gateway] 🐞 Field resolves to null when combining fragments on interfaces and implementations
- Dominant language
- TypeScript
- Stars
- 725
- Forks
- 276
- Avg merge
- 1h 47m
- Merged PRs (30d)
- 1
Description
### Packages
- `@apollo/gateway@0.14.1`
- `@apollo/federation@0.14.1`
### Summary
This issue only exists in the gateway, executing the same query against graphql server yields expected result. The issue is, queried fields return a null value when combining multiple fragments on the interface and its implementations, even though there is a non-null value resolved by the underlying service.
#### Extension to product schema of [federation-demo](https://github.com/apollographql/federation-demo/blob/master/services/products/index.js#L9)
```gql
type Product @key(fields: "upc") {
upc: String!
name: String
price: Int
weight: Int
someProp: ISomeProp # <-- New property
}
type ChildProp {
value: String
}
interface ISomeProp {
childProp: ChildProp
}
type SomeProp_IMPL_1 implements ISomeProp {
childProp: ChildProp
IAM_IMPL_1: Boolean
}
type SomeProp_IMPL_2 implements ISomeProp {
childProp: ChildProp
IAM_IMPL_2: Boolean
}
```
#### Query example
```gql
query {
topProducts(first: 2) {
someProp {
...Frag_SomeProp_IMPL_1
...Frag_ISomeProp
}
}
}
fragment Frag_ISomeProp on ISomeProp {
...Frag_ISomeProp2
}
fragment Frag_SomeProp_IMPL_1 on SomeProp_IMPL_1 {
IAM_IMPL_1
...Frag_ISomeProp2
}
fragment Frag_ISomeProp2 on ISomeProp {
... on SomeProp_IMPL_2 {
IAM_IMPL_2
childProp {
...Frag_ChildProp
}
}
__typename
}
fragment Frag_ChildProp on ChildProp {
__typename
value
}
```
#### Result from gateway
```json
{
"data": {
"topProducts": [
{
"someProp": {
"IAM_IMPL_2": null,
"childProp": null,
"__typename": "SomeProp_IMPL_2"
}
},
{
"someProp": {
"IAM_IMPL_2": null,
"childProp": null,
"__typename": "SomeProp_IMPL_2"
}
}
]
}
}
```
#### Result from product service
```json
{
"data": {
"topProducts": [
{
"someProp": {
"IAM_IMPL_2": true,
"childProp": {
"__typename": "ChildProp",
"value": "childProp value"
},
"__typename": "SomeProp_IMPL_2"
}
},
{
"someProp": {
"IAM_IMPL_2": true,
"childProp": {
"__typename": "ChildProp",
"value": "childProp value"
},
"__typename": "SomeProp_IMPL_2"
}
}
]
}
}
```
### Expected behaviour
Queried fields using fragments should resolve to the actual value instead of null.
### Actual behaviour
Queried fields using fragments are resolved to null.
### Steps to reproduce
- Clone Repository: https://github.com/01alchemist/federation-demo
- `npm install`
- `npm run start-services`
- Open a new terminal
- `npm run start-gateway`
- Execute example query on http://localhost:4000/
- Execute example query on http://localhost:4003/
- Both should return the same result but it's different.
Contributor guide
Research direction
Reproduce the query using the federation-demo extension in services/products/index.js, running the services and gateway at the documented endpoints, then compare the gateway response with the product service response. Trace how the gateway combines fragments on ISomeProp and its implementations; done means the gateway returns the resolved IAM_IMPL_2 and childProp values instead of null.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- graphql, 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