Supergraph handler fails with same field name
nk-coding opened this issue · comments
Issue workflow progress
Progress of the issue based on the
Contributor Workflow
- 1. The issue provides a reproduction available on
Github,
Stackblitz
or
CodeSandbox
Make sure to fork this template and run
yarn generate
in the terminal.Please make sure Mesh package versions under
package.json
matches yours.
- 2. A failing test has been provided
- 3. A local solution has been provided
- 4. A pull request is pending review
Describe the bug
Using the supergraph handler, if two fields on different types on the same subgraph have the same signature and are fetched identically, an error (Cannot return null for non-nullable field [...]
occurs
To Reproduce Steps to reproduce the behavior:
- Clone https://github.com/nk-coding/graphql-mesh-supergraph-bug
- Start the server
npm install npm start
- Open the browser and go to
http://localhost:4000/graphql
- Run the following query:
query { products(first: 1) { id name discounts { id } categories { id discounts { id } } } }
- You will receive the following error:
{ "data": { "products": [ null ] }, "errors": [ { "message": "Cannot return null for non-nullable field Category.discounts.", "path": [ "products", 0, "categories", 0, "discounts" ] } ] }
Expected behavior
Not getting the error and instead getting the data
Environment:
- OS: Windows 11
- @graphql-mesh/cli: 0.89.4,
- @graphql-mesh/supergraph: 0.2.4,
- graphql: 16.8.1
- NodeJS: v18.19.0
Additional context
After some debugging, I found out that the error most likely has something to do getLoader
Tldr: is seems like both Product.discounts
and Category.discounts
seem to use the same dataloader, maybe due to wrong cache key
First, when enabling debug logging, I see the following requests:
[start-services] [start-gateway-delayed] Executing DISCOUNT with args: {
[start-services] [start-gateway-delayed] document: 'query ($_v0_representations: [_Any!]!) {\n' +
[start-services] [start-gateway-delayed] ' __typename\n' +
[start-services] [start-gateway-delayed] ' _entities(representations: $_v0_representations) {\n' +
[start-services] [start-gateway-delayed] ' ... on Product {\n' +
[start-services] [start-gateway-delayed] ' __typename\n' +
[start-services] [start-gateway-delayed] ' id\n' +
[start-services] [start-gateway-delayed] ' discounts {\n' +
[start-services] [start-gateway-delayed] ' id\n' +
[start-services] [start-gateway-delayed] ' }\n' +
[start-services] [start-gateway-delayed] ' }\n' +
[start-services] [start-gateway-delayed] ' __typename\n' +
[start-services] [start-gateway-delayed] ' }\n' +
[start-services] [start-gateway-delayed] '}',
[start-services] [start-gateway-delayed] variables: { _v0_representations: [ [Object] ] }
[start-services] [start-gateway-delayed] }
[start-services] [start-gateway-delayed] Executing DISCOUNT with args: {
[start-services] [start-gateway-delayed] document: 'query ($_v0_representations: [_Any!]!) {\n' +
[start-services] [start-gateway-delayed] ' __typename\n' +
[start-services] [start-gateway-delayed] ' _entities(representations: $_v0_representations) {\n' +
[start-services] [start-gateway-delayed] ' ... on Product {\n' +
[start-services] [start-gateway-delayed] ' __typename\n' +
[start-services] [start-gateway-delayed] ' id\n' +
[start-services] [start-gateway-delayed] ' discounts {\n' +
[start-services] [start-gateway-delayed] ' id\n' +
[start-services] [start-gateway-delayed] ' }\n' +
[start-services] [start-gateway-delayed] ' }\n' +
[start-services] [start-gateway-delayed] ' __typename\n' +
[start-services] [start-gateway-delayed] ' }\n' +
[start-services] [start-gateway-delayed] '}',
[start-services] [start-gateway-delayed] variables: { _v0_representations: [ [Object] ] }
[start-services] [start-gateway-delayed] }
Note that the first one should be for Product.discounts
, while the second one should be for Category.discounts
.
Even though the second one should be for the Discount entity, however it still does ... on Product
, thus no data is returned and the error occurs.
With some debugging, I found out that both use the data loader under the cache key
_entities{
discounts {
id
}
}
(and the cache map is also the same). I suspect that this causes both using the same data loader, and thus the second one uses the wrong query.
When I provide an alias for one of the two discount fields, it starts working, and two different data loaders are used.
I think this could potentially be fixed by including the "parent" type name (I mean Product/Category in the example) in the cache key, however I do not have sufficient knowledge of this project to be sure.
This might fix it;
ardatan/graphql-tools#5998
Could you try it by adding @graphql-tools/batch-delegate
as 9.0.2-alpha-20240319205135-b2f28663ded1506586af727ffda76b36e3016094
to resolutions
in your package.json file?
Thanks for the issue!
works as expected, thx