ardatan / ardatan/graphql-tools

Stitching returns null object when no field is offered by original object

Open
#4,514 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
5.4k
Forks
830
Avg merge
10h 59m
Merged PRs (30d)
45

Description

### Issue workflow progress

_Progress of the issue based on the [Contributor Workflow](https://github.com/the-guild-org/Stack/blob/master/CONTRIBUTING.md#a-typical-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 the GraphQL Tools 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**

When making a query that original object contributes no field to `selections`, the resulting object is null, and no query is being made to delegate graphql server.

This case occurs when
- there is no `ID!` field(s) required to query delegate schema, i.e. a global object, possibly related to use case of #4336, and
- there is no field offered by original object (no field at step 2)

![image](https://user-images.githubusercontent.com/20808792/172420867-90ad3fb4-fd63-491e-ad9e-cecbbd4b2a4c.png)

**To Reproduce**
Steps to reproduce the behavior:

`
cd gateway
npm i
pip install awscli aws-sam-cli
sam local start-api -t ./local.yml -l message.log --host 0.0.0.0 -p 3000
`

https://github.com/flyingmilktea/graphql-bug-reproduce/tree/no-query-at-origin-remote-null-v1

In the scenario, fields named `zero*` is offered by 0-th schema, named `one*` is offered by 1-st schema, stitched together

Query:
```graphql
{
zeroUser {
oneValue
}
oneUser {
zeroValue
}
}
```

```json
{
"data": {
"zeroUser": null,
"oneUser": null
}
}
```

**Expected behavior**

Correct result:
```json
{
"data": {
"zeroUser": {
"oneValue": "1: User: query"
},
"oneUser": {
"zeroValue": "0: User: query"
}
}
}
```

**Environment:**

- OS: Linux 4.18.0-372.9.1.el8.x86_64
- "@graphql-tools/graphql-file-loader": "^7.3.14",
- "@graphql-tools/load": "^7.5.13",
- "@graphql-tools/schema": "^8.3.13",
- "@graphql-tools/stitch": "^8.6.12",
- "@graphql-yoga/node": "^2.8.0",
- "@vendia/serverless-express": "^4.8.0",
- NodeJS: v14.19.3

**Additional context**

https://github.com/ardatan/graphql-tools/blob/8b631980bdf0e18c1504ca56f7799befe2f31e8b/packages/delegate/src/finalizeGatewayRequest.ts#L368-L371

When the original object (step 2) does not require an ID, and there is no field offered by object's original schema, all selections will be filtered out, resulting in `selections.length === 0` for gateway schema.

In the case of schema stitching, it cannot be assumed that the node without selections at the gateway is safe to delete, the result of empty array is only due to the fact that all fields being offered by delegate schemas, thus has to continue onto step 4 onward to retrieve the correct result.

Here is a workaround for your reference.
```js
if (selections == null ) {
return null;
} else if (selections.length === 0){
selections.push({"kind":"Field","name":{"kind":"Name","value":"__typename"},"arguments":[],"directives":[]})
}
```
Personally I don't consider it a fix, what it does is just adding `__typename` when the array is empty.
Afaik in a valid query, a non-primitive field must at least have 1 subfield selection, thus this would not happen without stitching and filtering.

E.g.:
```graphql
# Invalid
{
zeroUser {
# type User without any subfield selected
}
}

# Valid
{
zeroUser {
__typename
}
}
```

Again thanks @Abbywpy for testing the issue

Contributor guide

Open the contributing guide

Research direction

Start with packages/delegate/src/finalizeGatewayRequest.ts around lines 368-371, then run the linked reproduction from the no-query-at-origin-remote-null-v1 branch using the gateway setup described. Verify the empty-selection case produces the expected delegated values instead of null, and add coverage for both zeroUser and oneUser behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
graphql, typescript
Domain
api, backend-api-design
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.