Open atomheartother opened 1 year ago
The more I poke at this bug the more I lean towards implementation error. It's happening for some data types but not all, so it's likely depending on some unknown implementation detail my example above would not reproduce the bug. I'll try and find the time to make a reproducible example and get back to this report, but if someone can provide any insight as to what the problem might be from this error message I'd be grateful.
Hi @atomheartother, thanks for raising this issue! We're looking into this now to see if it's an implementation problem or a bug -- which version of the Federation 2.3 spec are you using (importing via @link
)? We did release some patch updates that solved similar bugs (trying to deduce if it's the same one) in version 2.3.2, so I'd recommend using that version. I know you're using 2.3.2 of @apollo/subgraph
, which is great.
@korinne Thanks for the quick reply :)
I'm using 2.3 like so (2.3.2 isn't a valid spec version to @link
against as far as I understand it):
extend schema
@link(
url: "https://specs.apollo.dev/federation/v2.3"
import: [
"@key"
"@tag"
"@shareable"
"@inaccessible"
"@override"
"@external"
"@provides"
"@requires"
"@interfaceObject"
]
)
This is in both subgraphs. In the router I had this in my supergraph-config.yaml
: federation_version: =2.3.0
I updated it to =2.3.2
just now to no avail.
Oh you're completely right about the @link
-- sorry about that, too early in the morning :) . One last question for you -- are you using managed Federation with Apollo Studio, or rover supergraph compose
? If using the latter, it's very easy to forget to recompose once you bump the version.
Either way, we've added this to our backlog to investigate asap, and thanks again for the extra information!
It's local composition with rover supergraph compose
, but I did triple-check that i had done that and restarted my router before replying 😄 The supergraph was simply left unchanged after upgrading to =2.3.2
and re-composing so it should have had no effect anyway.
Like I said I'm still pretty sure this is an implementation error but it's hard to pin down where I went wrong...
Alright cool, thank you for the extra information -- I've forgotten to recompose before so it's always good to check haha. Looking into it, and will get back to you shortly. It could be implementation specific, but it's always good for us to dive into any issues. Thanks again for reaching out!
@atomheartother Hey there, do you happen to have that repro available for us? We can try to reproduce on our end, but it would be great to look at what you have. Thanks!
@korinne I'm afraid I'm extremely busy at the moment, but I'll try and figure something out reasonably soon.
I however have been poking at and tweaking my schema and I've found that the error only occurs when the interface's federated field has an @external dependency. Here's a simplified schema of my error case:
# limit.graphql
## Limit only has those two implementations
interface Limit @key(fields: "id") {
id: ID!
strategyId: ID!
}
type StandaloneLimit implements Limit @key(fields: "id") {
id: ID!
strategyId: ID!
}
type ProfileLimit implements Limit @key(fields: "id") {
id: ID!
strategyId: ID!
}
# Federated
type Strategy @interfaceObject @key(fields: "id") {
id: ID!
limits: [Limit!]!
}
#strategy.graphql
interface Strategy @key(fields: "id") {
id: ID!
}
type XStrategy implements Strategy @key(fields: "id") {
id: ID!
}
type YStrategy implements Strategy @key(fields: "id") {
id: ID!
}
# Federated
type Limit @interfaceObject @key(fields: "id") {
id: ID!
strategyId: Int! @external
strategy: Strategy! @requires(fields: "strategyId")
}
query test {
# Doesn't work
limits {
...on StandaloneLimit {
strategy {id}
}
}
# Doesn't work
limits {
...on ProfileLimit {
strategy {id}
}
}
# Works
limits {
strategy {id}
}
# Works
limits {
...on StandaloneLimit {
strategy {id}
}
...on ProfileLimit {
strategy {id}
}
}
# Doesn't work (this queries a Limit which we know is a StandaloneLimit)
limit(id: "001a5bea-dd8b-4bbc-836a-6bf676fa20be") {
...on ProfileLimit {
strategy {id}
}
}
# Works
strategies {
...on XStrategy {
limits {id}
}
}
# Works
strategies {
...on YStrategy {
limits {id}
}
}
# Works (id:10 is an XStrategy)
strategy(id: "10") {
...on YStrategy {
limits {id}
}
}
}
I also doubt this is linked but the schema version differs in other schemas (these two are v2.3, but they are being composed with other schemas which are still on 2.0).
I'm experiencing a similar issue and my investigation showed me that the query planner is over-fetching on conditional fragments.
While over-fetching in itself is an issue, worse thing is, it tries to fetch __typename
from reviews graph @interfaceObject
which does not match with the one resolved by the products graph, so it returns null since __typename
do not match.
I think it is closely related to this issue https://github.com/apollographql/federation/issues/2759
Introduction
I'm trying to get a complex graphql server running using Federation spec v2.3 as interfaces are an integral part of the data, which for the most part works, but I've encountered a pesky bug. I"m not sure if it is a subgraph bug, a router bug or an implementation error on my part (as
interfaceObject
is still not very documented).In short it seems like when you use an inline fragment to specify an interface's implementation, you can confuse other subgraphs when you query the fields they've contributed to the interface.
The setup
And let's say you share this interface with the "reviews" subgraph:
Let's say for the sake of brevity you have resolvers for everything and
__resolveReference
s for all your entities.The bug
Assuming
products
returns both Bikes and Books, this query will break:It will print an error along the lines of:
When you'd expect it to return a mix of empty objects (the Bikes) and Books with their attached reviews. After some investigating, this is due to the fact that the Bikes returned by
products
aren't being queried forreviews
. Somehow that breaks federation.Similarly this will break:
Example of working similar queries
This works and returns reviews for all products:
This also effectively produces the same output:
Even this works and also produces the same output:
Package versions
I'm using the router docker image v1.10.3 with
@apollo/server
4.3.3 and@apollo/subgraph
2.3.2.