-
Notifications
You must be signed in to change notification settings - Fork 273
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
Supports federation 2.3 in the router #2489
Supports federation 2.3 in the router #2489
Conversation
Some of the paths returned by the query planner may contain some "fragment", which are really meant to act as type conditions. That is, for some data like: ```json { "x": [ { "__typename": A, "a": 0 }, { "__typename": B, "a": 1 }, { "__typename": A, "a": 2 }, ] "y": 42 } ``` and a path `["x", "... on A", "a"]`, then the intend is that this selects the following data: ```json { "x": [ { "__typename": A, "a": 0 }, { "__typename": A, "a": 2 }, ] } ``` but skips the `B` entity in particular. That logic is currently not implemented, and while fragments in path are parsed, they are otherwise ignored (and so the code currently ends up selecting the `B` entity). The only place where such fragments may appear in paths currently is in deferred nodes, where the paths are used to select what should be in a particular defer response. I believe (I haven't taken the time to test it yet) that this mean the code may currently sometimes include data in a given deferred response that should be sent in a different response. This commit fix the code that handles fragments in path so that they are taken account as explained in the example above. Unfortunately, this doesn't quite fix the issue with deferred response mentioned above (it should in some cases, but not all of them) because the code currently filters responses _before_ it tries to apply those path selections, which means that in many cases the "__typename" fields are filtered out and thus cannot be used to decide if an object matches the path fragment or not (the code thus default to include the object to mimick the existing behaviour, but this may be incorrect in some cases). However, those fragments in path are heavily used in the changes introduced to the query planner by federation 2.3, so while this patch does not quite fix the defer issue, it is a step forward and is necessary in preparation for supporting federation 2.3.
This PR is technically on top of #2485, though that later PR is rebased on |
The query planner in Federation 2.3 adds a new concept of "data rewrites" for fetches in order to support both `@interfaceObject` and to support the fix for apollographql/federation#1257. Those "rewrites" describe simple updates that need to be performed either on the inputs (the "representations" passed to `_entities`; need to rewrite the `__typename` when sending queries to an `@interfaceObject`) or the output of a fetch (needed when a field has been aliased to permit the subgraph query to be valid, but that field needs to be "un-aliased" to its original name after the fetch). This commit implements those rewrites.
2a0aa0b
to
36651cc
Compare
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.
Looks good! This needs a merge from dev to resolve the conflicts with 09cff54 and then that will be good to go
schema | ||
@link(url: "https://specs.apollo.dev/link/v1.0") | ||
@link(url: "https://specs.apollo.dev/join/v0.3", for: EXECUTION) | ||
{ | ||
query: Query | ||
} | ||
|
||
directive @join__enumValue(graph: join__Graph!) repeatable on ENUM_VALUE |
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.
It's taking a lot of lines in our file, maybe for later we should refactor this and put all these schemas in separate files in testdata
directory and use include_str!
macro to have a cleaner file.
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.
Happy to change it if you prefer, it's fairly quick. I mostly followed the pattern of the previous tests in this file.
Though just for the conversion, I tend to find it easier to maintain tests when they are somewhat self-contained, and you don't have to navigate multiple files to understand what is going on. But it's probably more of a personal preference and not trying to push anything really.
apollo-router/src/json_ext.rs
Outdated
@@ -528,7 +665,10 @@ impl Path { | |||
} else if s == "@" { | |||
PathElement::Flatten | |||
} else { | |||
PathElement::Key(s.to_string()) | |||
s.strip_prefix("... on ").map_or_else( |
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.
Just a nit: that could be helpful to put "... on "
in a constant somewhere to avoid typo and forget the trailing whitespace somewhere
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.
Good call. Pushed the quick change.
I merged dev and took care of the conflict |
Looks like |
…oducted by `@interfaceObject` The introduction of `@interfaceObject` in federation 2.3 has for consequence that a subgraph (that uses an `@interfaceObject`) may return in its response a `__typename` that corresponds to an interface type in the supergraph (but which, locally to that subgraph, is an object type). The idea is that if that `__typename` is requested, then the query planner will ensure that another follow-up fetch will override that value so it maps to a proper object type. However, in some cases, that `__typename` is not queried, nor is there another reason to resolve the actual underlying implementation type of the underlying object (meaning that only fields of the interface are queried), and in that case the `__typename` may still point to the interface type when `format_response` is called. Unfortunately, that method currently nullify the whole object in such case, which is not the behaviour we want and was not caught in apollographql#2489.
…oducted by `@interfaceObject` The introduction of `@interfaceObject` in federation 2.3 has for consequence that a subgraph (that uses an `@interfaceObject`) may return in its response a `__typename` that corresponds to an interface type in the supergraph (but which, locally to that subgraph, is an object type). The idea is that if that `__typename` is requested, then the query planner will ensure that another follow-up fetch will override that value so it maps to a proper object type. However, in some cases, that `__typename` is not queried, nor is there another reason to resolve the actual underlying implementation type of the underlying object (meaning that only fields of the interface are queried), and in that case the `__typename` may still point to the interface type when `format_response` is called. Unfortunately, that method currently nullify the whole object in such case, which is not the behaviour we want and was not caught in apollographql#2489.
…oducted by `@interfaceObject` The introduction of `@interfaceObject` in federation 2.3 has for consequence that a subgraph (that uses an `@interfaceObject`) may return in its response a `__typename` that corresponds to an interface type in the supergraph (but which, locally to that subgraph, is an object type). The idea is that if that `__typename` is requested, then the query planner will ensure that another follow-up fetch will override that value so it maps to a proper object type. However, in some cases, that `__typename` is not queried, nor is there another reason to resolve the actual underlying implementation type of the underlying object (meaning that only fields of the interface are queried), and in that case the `__typename` may still point to the interface type when `format_response` is called. Unfortunately, that method currently nullify the whole object in such case, which is not the behaviour we want and was not caught in apollographql#2489.
… cases The introduction of `@interfaceObject` in federation 2.3 has for consequence that a subgraph (that uses an `@interfaceObject`) may return in its response a `__typename` that corresponds to an interface type in the supergraph (but which, locally to that subgraph, is an object type). The idea is that if that `__typename` is requested, then the query planner will ensure that another follow-up fetch will override that value so it maps to a proper object type. However, in some cases, that `__typename` is not queried, nor is there another reason to resolve the actual underlying implementation type of the underlying object (meaning that only fields of the interface are queried), and in that case the `__typename` may still point to the interface type when `format_response` is called. Unfortunately, that method currently nullify the whole object in such case, which is not the behaviour we want and was not caught in #2489.
… cases The introduction of `@interfaceObject` in federation 2.3 has for consequence that a subgraph (that uses an `@interfaceObject`) may return in its response a `__typename` that corresponds to an interface type in the supergraph (but which, locally to that subgraph, is an object type). The idea is that if that `__typename` is requested, then the query planner will ensure that another follow-up fetch will override that value so it maps to a proper object type. However, in some cases, that `__typename` is not queried, nor is there another reason to resolve the actual underlying implementation type of the underlying object (meaning that only fields of the interface are queried), and in that case the `__typename` may still point to the interface type when `format_response` is called. Unfortunately, that method currently nullify the whole object in such case, which is not the behaviour we want and was not caught in #2489.
The query planner in Federation 2.3 adds a new concept of "data rewrites" for fetches in order to support both
@interfaceObject
and to support the fix for apollographql/federation#1257.Those "rewrites" describe simple updates that need to be performed either on the inputs (the "representations" passed to
_entities
; need to rewrite the__typename
when sending queries to an@interfaceObject
) or the output of a fetch (needed when a field has been aliased to permit the subgraph query to be valid, but that field needs to be "un-aliased" to its original name after the fetch).This commit implements those rewrites.
Checklist
Complete the checklist (and note appropriate exceptions) before a final PR is raised.
Exceptions
Note any exceptions here
Notes
[^1]. It may be appropriate to bring upcoming changes to the attention of other (impacted) groups. Please endeavour to do this before seeking PR approval. The mechanism for doing this will vary considerably, so use your judgement as to how and when to do this.
[^2]. Configuration is an important part of many changes. Where applicable please try to document configuration examples.
[^3]. Tick whichever testing boxes are applicable. If you are adding Manual Tests:
- please document the manual testing (extensively) in the Exceptions.
- please raise a separate issue to automate the test and label it (or ask for it to be labeled) as
manual test