Apollo-client: Heuristic Fragment Matcher Fails Unions

Created on 4 Jun 2019  路  5Comments  路  Source: apollographql/apollo-client

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

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!

All 5 comments

+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:

https://github.com/apollographql/apollo-client/blob/ec167e9ba7ed94e902438e952316bfcfe8873b38/packages/apollo-cache-inmemory/src/fragmentMatcher.ts#L77-L81

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!

Was this page helpful?
0 / 5 - 0 ratings