Description
Hello!
First, thank you for creating this Gateway.
I'm creating this issue for something I think I've found that's a bug behavior when running GraphGate against some federated services.
For context, I'm using the services under Apollo's Federation Demo
which consist of 4 services: [accounts,reviews,products,inventory].
Here's the query I'm using
query topProds {
topProducts(first: 1) {
upc
inStock
shippingEstimate
}
}
And for context, the shippingEstimate field is declared on the Inventory service extending the Product type and depends on the price
and weight
field on Product Type.
shippingEstimate: Int @requires(fields: "price weight")
Bug
I noticed the entity resolver for the Inventory service was receiving an object that only has the __typename
and upc
from graphgate when I selected the shippingEstimate
.
{ __typename: 'Product', upc: '1' }
In contrast, when I run the same query but through Apollo's Node Gateway,
the Inventory service receives the price and weight as expected since they are labeled required by shippingEstimate
.
{ __typename: 'Product', upc: '1', price: 899, weight: 100 }
Interestingly, I noticed this only happens when I select more than 1 field that come from the Inventory service(inStock
).
Ex: When I use this query,
query topProds {
topProducts(first: 1) {
upc
shippingEstimate
}
}
graphgate sends the full expected object
{ __typename: 'Product', price: 899, upc: '1', weight: 100 }
Since price and weight are missing, the resolver for shippingEstimate
can't resolve.
Expected Behavior
Graphgate should send the Inventory service the price
and weight
field that are required for the shippingEstimate
field.
Actual Behavior
In some situations, the required fields are missing in the object sent to the Federated service.
Steps to Reproduce the Problem
-
Clone Apollo's federation demo, run
npm install
and thennpm run start-services
-
Configure graphgate with the following toml config.
bind = "0.0.0.0:8000" forward_headers = [] [jaeger] agent_endpoint = "127.0.0.1:6831" service_name = "graphgate" [[services]] name = "accounts" addr = "127.0.0.1:4001" query_path = "/" subscribe_path = "/" introspection_path = "/" websocket_path = "/" [[services]] name = "reviews" addr = "127.0.0.1:4002" [[services]] name = "products" addr = "127.0.0.1:4003" [[services]] name = "inventory" addr = "127.0.0.1:4004"
-
Run the following query
query topProds { topProducts(first: 1) { upc inStock shippingEstimate } }
Your data should have an error.
{
"data": {
"topProducts": [
{
"upc": "1"
}
]
},
"errors": [
{
"message": "Int cannot represent non-integer value: NaN",
"path": [
"topProducts",
0,
0,
"shippingEstimate"
]
}
]
}
Specifications
- GraphGate Version: 0.5.1
- Platform:
MacOS Catalina
- Federation Demo Commit Hash:
e24d9aca9d7a8fe9490ab53efeddc2ef8152f4a1
- Node Version:
v14.17.0
- NPM Version:
7.14.0
Additional details.
I captured 3 print outs of Query plans.
The first one is the Query Plan from Apollo's Node Gateway.
_query_plan_node_gateway.txt
This query plan is from GraphGate. I got it by adding this println!("{:#?}", plan);
to shared_route_table.rs#169.
In this query plan, the RequiredRef {
in the first fetchNode
only has upc
.
_query_plan_graphgate_missing_fields.txt
And lastly, this GraphGate query plan print out is when I don't query for the inStock
field. Notably, the required RequiredRef {
now has price
and weight
, and upc
.
_query_plan_graphgate_has_price_weight.txt
Thanks! Please let me know if there's any other info I can provide that can help recreate the bug or invalidate this issue.