-
Notifications
You must be signed in to change notification settings - Fork 10
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
Federated queries are not correctly resolved if one of subgraphs is unavailable #177
base: main
Are you sure you want to change the base?
Conversation
7bb64ac
to
46e2791
Compare
Thanks for creating the PR, we'll look into it but it seems something is wrong with your setup. |
46e2791
to
81ad9fa
Compare
Hello @ardatan, |
const result: FormattedExecutionResult = await response.json(); | ||
|
||
expect(response.status).toBe(200); | ||
expect(result.data).toMatchObject(unexpectedData); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ardatan This is interesting. If this test runs on Bun, it correctly receive expectedNullableData
mentioned above. 🤔 https://github.com/graphql-hive/gateway/actions/runs/12004650429/job/33463064378?pr=177#step:4:1519
81ad9fa
to
fd79091
Compare
Hello @ardatan, |
fd79091
to
eaeff3c
Compare
After taking another look at the issue, I noticed few things; If Subgraph 2 is down, subgraph2 field should be null with errors not Because; {
testNestedField: {
subgraph1: {
testSuccessQuery: {
id: 'user1',
email: '[email protected]',
sub1: true,
},
},
subgraph2: {
testSuccessQuery: null
},
},
} This means |
I understand your deduction, but I don't think it's correct in this case. If I run the same tests against a real Apollo Gateway, the result is correct in my opinion, or rather it behaves as the GraphQL specification says https://spec.graphql.org/draft/#sel-GAPHRPTPCAACEzBg6S
And the first non-nullable field is always However, if I run the tests against GraphQL Yoga (used as a gateway), it behaves differently and in my opinion incorrectly as you can see in the tests. |
Let's think of an example outside Federation then; We have a following schema; type Query {
foo: Foo
}
type Foo {
bar: Bar
}
type Bar {
id: ID
} and we have the following resolvers; const resolvers = {
Query: {
foo: () => ({})
},
Foo: {
bar: () => null,
},
Bar: {
id: () => 'BAR_ID'
}
} What do you expect when you make the following request? {
foo {
bar {
id
}
}
} This one right? because {
"data": {
"foo": {
"bar": null
}
}
} When we go back to our example, |
Imagine a simple federated query:
If subraph2 is unavailable, the query should be resolved as follows:
In case of a subgrah2 outage, Apollo Gateway will resolve the above-mentioned query exactly as shown in the example. Unfortunately, GraphQL Yoga used as gateway does not work properly in this case and the result is also strangely affected by non/nullable parent fields even if the actual query result has always nullable type.
I didn't find the exact location where the problem occurs, but I would guess that it's somewhere in the
@graphql-tools/executor-http
package.Explanation of the tests which can be found in this PR.
The first two test cases in
describe('EXPECTED RESPONSE - EVERYTHING OK')
when subgraph2 actually returns an error from its resolver return the expected response. These are just example tests of how it should work and result should be the same even if the subgrah2 is down.The other 4 test cases in
describe('UNEXPECTED RESPONSE - FAILING TESTS')
when subgraph2 is actually unavailable always return a different and wrong response.test
subgraph2_Nullable.testErrorQuery - subgraph2 is unavailable
data
anderrors
got completely lost somewhere along the waytest
subgraph2_NonNullable.testErrorQuery - subgraph2 is unavailable
data
and wrong error due to NonNullable "parent" field (GQL result type oftestErrorQuery
is actually nullable)test
subgraph2_Nullable.testErrorQuery only - subgraph2 is unavailable
data
, but the error is almost correct. Only errorpath
is incomplete and should be['testNestedField', 'subgraph2_Nullable', 'testErrorQuery']
test
subgraph2_NonNullable.testErrorQuery only - subgraph2 is unavailable
data
, but the error is almost correct. Only errorpath
is incomplete and should be['testNestedField', 'subgraph2_NonNullable', 'testErrorQuery']