Cannot process a response that ignores @defer directives
- Dominant language
- Rust
- Stars
- 19k
- Forks
- 1.9k
- PR merge metrics
- No merged PRs in 30d
Description
It has been discovered that the Relay runtime currently comes with the expectation that fragments marked with the `@defer` directive are expected to be deferred. Even when the network returns its corresponding value. This leaves fragments marked with the directive to have an undefined value. As far as we can tell, it is due to [this function](https://github.com/facebook/relay/blob/main/packages/relay-runtime/store/RelayResponseNormalizer.js#L345) which bakes the assumption into the library.
This behavior seems to be against the [current specification](https://github.com/graphql/graphql-spec/pull/742/files#diff-30a69c5a5eded8e1aea52e53dad1181e6ec8f549ca2c50570b035153e2de1c43R2175-R2181), and the [original RFC](https://github.com/graphql/graphql-wg/blob/main/rfcs/DeferStream.md#:~:text=Therefore%2C%20GraphQL%20clients%20should%20be%20able%20to%20process%20a%20response%20that%20ignores%20the%20defer/stream%20directives.):
> ... GraphQL clients _must_ be able to process a response that ignores the `@defer` and/or `@stream` directives.
We had to make some larger changes to our execution engine to support defer. Having the ability to toggle the `defer` on the backend lets us roll out the changes slowly and fallback to previous codepaths in the event of regression. This is also a blocker for advanced usage cases in the future. For example, one thing we were considering was merging unnecessarily deferred fragments back into the initial response to the client. This would avoid having to do a pass over the store a second time when not necessary.
Is there a possible workaround or a relatively trivial way to support this behavior?
**Code Sample**
```jsx
function Screen() {
const query = useLazyLoadQuery(
graphql`
query ScreenQuery {
viewer {
name
}
...ScreenContent @defer(label: "ScreenContentFragment")
}
`,
{},
);
return (
);
}
function ScreenContent(props) {
const content = useFragment(
graphql`
fragment ScreenContent on Query {
newsArticles {
edges {
node {
title
}
}
}
}
`,
props.queryRef,
);
console.log(content); // <---- content is null
return
}
```
Response from the server:
```
{
"data": {
"viewer": {
"name": "Ozzie"
},
"newsArticles": {
"edges": [
{
"node": {
"title": "Hello World"
}
}
]
}
}
}
```
**Example Project**: https://github.com/kirkbyo/relay-use-fragment-defer
Contributor guide
Assessment
This issue has not been assessed yet.