I am sharing what is hopefully the simplest possible example of queries resulting in union types using both vanilla graphql
and apollo-client
with heuristic fragment matcher. HFM does not seem to work for disambiguating unions as described in the docs:
By default, Apollo Client's cache will use a heuristic fragment matcher, which assumes that a fragment matched if the result included all the fields in its selection set, and didn't match when any field was missing.
https://www.apollographql.com/docs/react/advanced/fragments/
Intended outcome:
Using apollo-client
with heuristic fragment matcher should be sufficient for distinguishing the constituent types of a union type in a graphql result where the constituent types share no field names. Specifically with respect to my reproduction, the output of the program should be quiet of warnings, and the values of result1
and result2
coming from graphql
and apollo-client
packages respectively should be structurally equal.
Actual outcome:
Heuristic fragment matcher outputs warnings when it should be up to the task it is being used for, and the query result when using ApolloClient with heuristic fragment matcher is null
.
How to reproduce the issue:
Get the three files in this gist with your gist-getting means:
https://gist.github.com/dvisztempacct/44ce39796b8ad62ded68797f59a786f9
Install dependencies and run:
node ./index
Versions
(Perhaps better package versions are available in yarn.lock
file in the gist)
npx: installed 1 in 1.135s
System:
OS: Linux 4.18 Pop!_OS 18.04 LTS
Binaries:
Node: 10.9.0 - ~/.nvm/versions/node/v10.9.0/bin/node
Yarn: 1.12.1 - ~/.nvm/versions/node/v10.9.0/bin/yarn
npm: 6.2.0 - ~/.nvm/versions/node/v10.9.0/bin/npm
Browsers:
Firefox: 67.0
npmPackages:
apollo-cache-inmemory: ^1.6.0 => 1.6.0
apollo-client: ^2.6.0 => 2.6.0
apollo-link: ^1.2.11 => 1.2.11
apollo-link-error: ^1.1.10 => 1.1.10
apollo-link-http: ^1.5.14 => 1.5.14
apollo-link-schema: ^1.2.2 => 1.2.2
+1
Thanks for reporting this @dvisztempacct. Unfortunately, our only course of action for now is to update the docs to make sure it's clear that the default (heuristic) fragment matcher can't be used accurately with unions or interfaces. The reason for this is that to fix the heuristic fragment matcher so that it works with unions and interfaces, will be a breaking change. This is because of the design decision outlined here:
The code is always attempting to match (2. from the comment), which means that fragments that shouldn't match specific types in a union for example, are always attempted to be matched (which leads to the Missing field X in X
error, because the fragment includes a field that doesn't exist in the type it's trying to match against, but really shouldn't be).
I'll flag this as something we should look into for Apollo Client 3.0, but for now your best bet is to use the IntrospectionFragmentMatcher
as outlined in the Fragments on unions and interfaces section of the docs.
I'll get the docs updated accordingly. Thanks!
Hi @hwillson thanks for updating the documentation.
I took a look at your PR and I notice that fragments.md
still reads:
By default, Apollo Client's cache will use a heuristic fragment matcher, which assumes that a fragment matched if the result included all the fields in its selection set
In what other situations do fragments need to be matched other than subtype disambiguation of interface and union types?
Thanks again!
You can use Apollo heuristic fragment matcher facility with Unions, BUT you must separate each fragment on it's own query or mutation. (i.e. you can't use on
operator).
It's your call.
@0zkr1 for clarity could you show an example of what can't be done with HFM and how to formulate it in a way that works? Thanks!
Most helpful comment
@0zkr1 for clarity could you show an example of what can't be done with HFM and how to formulate it in a way that works? Thanks!