apollographql / apollo-client

:rocket:  A fully-featured, production ready caching GraphQL client for every UI framework and GraphQL server.
https://apollographql.com/client
MIT License
19.34k stars 2.66k forks source link

Why does QueryResult not contain extensions but FetchResult does? #11934

Closed adp-source closed 1 month ago

adp-source commented 2 months ago

I want to read response headers such as trace_id for debugging and return them in the response object. Doing something like response.extensions = { trace_id: '123' } in an ApolloLink middleware function works for mutation responses (FetchResult) but not query responses which return a QueryResult.

Why doesn't QueryResult contain the extensions object? How can I read headers from the request and put them in the response?

phryneas commented 2 months ago

Mutation responses are directly answered from a server request - but query results oftentimes don't even make a network request - if they can be answered from the cache, they are directly resolved from there.

In reality, every query (non-no-cache) network request makes it "through the cache" - if it cannot be answered from the cache, a request is made, that request fills the cache, and then the cache returns the result to your component.

During that process, the connection to the network request is lost - and you lose your extensions.

adp-source commented 2 months ago

Thanks for the response. I still don't get why you can't just put the headers or extensions object somewhere as cache.

I feel like this a common problem, that developers need an easy way to access headers. Currently to record the trace_id in the headers, I have to use an ApolloLink middleware and put them in a global or something?

Any better solutions?

phryneas commented 2 months ago

I still don't get why you can't just put the headers or extensions object somewhere as cache.

Because the cache is not filled by a single query. Imagine you make a query, and it gets fulfilled from the cache. But that data didn't make it into the cache via a single request, but is a union of data from three different requests, and these three different requests all had different extensions.

Which extensions do you return now? The extensions that are 25 minutes old and were part of a query that returned 80% of the data that is returned for the current query? Or the extensions from a request from 30 seconds ago that only updated 5% of the data?

Take it a step further: exactly the query that you want has been fulfilled 5 minutes ago. But since then, another overlapping query was made and some of it's data was updated. Which extensions do you return?

The problem with extensions is that they are related to a request, not to a specific piece of data. So your current approach of handling it in the link layer is the correct one. It cannot be handled on the data layer.

github-actions[bot] commented 1 month ago

We're closing this issue now but feel free to ping the maintainers or open a new issue if you still need support. Thank you!

github-actions[bot] commented 2 days ago

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. For general questions, we recommend using StackOverflow or our discord server.