Search code examples
reactjsgraphqlapolloapollo-clientcontentful

How can I cache nested objects with Apollo Client?


I'm using the Contentful GraphQL API to fetch a collection of items, in this example football clubs.

query Clubs($limit: Int!, $skip: Int!) {
    clubCollection(limit: $limit, skip: $skip) {
        total
        items {
            name
            description
        }
    }
}

The structure of the response is:

clubCollection: {
  items: [{
    ... array of all the clubs
  }]
}

It looks like the Apollo InMemoryCache is only caching the full query in its ROOT_QUERY object. But not each individual club. The setup for the cache looks like this:

new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        clubCollection: concatContentfulPagination()
      },
    },
  },
})

Does anyone know how I can target the clubs in items so that I can cache each individual club?

EDIT: Thanks to the answer from @xadm I realised I did not need to extend the InMemoryCache like so:

new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        clubCollection: {
          items: { 
          
          },
          ...concatContentfulPagination()
        }
      },
    },
  },
})

But instead add it to the root of the typePolicies based on the type of the object, for me it is Club. When I added that it did work!

new InMemoryCache({
  typePolicies: {
    Club: {
      keyFields: ['name']
    },
    Query: {
      fields: {
        clubCollection: concatContentfulPagination()
      },
    },
  },
})

Solution

  • Items should have an id prop requested ... to be normalized - Apollo is normalizing cache GraphQL client

    It's required to cache entries/types/subtypes properly.

    https://graphql.org/learn/caching/

    It, unique key can be id, _id or customized key per type using typePolicies - customizing-identifier-generation-by-type.

    https://www.apollographql.com/docs/react/caching/cache-configuration/#default-identifier-generation

    In this case (no queryable id prop inside items), you should check in API (docs/specs/schema or explore network response body - __typename prop of items object) the type of club items entries (probably Club) and customize cache policies like:

    new InMemoryCache({
      typePolicies: {
        Club: {
          keyFields: ['name']
        },
    

    ... assuming name is unique.