Apollo cache only contains `id` and `__typename` for all items

I can see that the API is correctly returning all fields in the query, but the cache only contains the id and __tyepname field for all items. Using fetchPolicy: "no-cache" works fine. Googling is leading me nowhere. Any help here would be appreciated.

Would you mind sharing some of your code? What does your query look like, how do you send the request, how do you access the response/cache data, how are your apollo client and cache configured?

Hey @mindnektar thanks for taking an interest. I’m viewing the response and cache using the Apollo Firefox DevTools extension. The API is returning all fields as expected, however the Cache is only storing the normalised id and ___typename. Here are the rest of the details:

Query:

const CONTRACTS_TABLE_QUERY = gql`
    query ContractsTableQuery {
      listContracts {
        ... on BaseEntity {
          id
          type
        }
        ... on BaseContract {
          series
          issueDate
          maturityDate
          contractId
          amount
          status
          template
          borrowers {
            id
            name
          }
        }
      }
    }
  `;

  const { data, loading, error } = useQuery(CONTRACTS_TABLE_QUERY);

Apollo Client config (integrated with Azure AD for auth):

import { InMemoryCache } from "@apollo/client/cache";
import { ApolloClient, createHttpLink, from } from "@apollo/client/core";
import { setContext } from "@apollo/client/link/context";
import { ApolloProvider } from "@apollo/client/react";
import React, { useContext } from "react";

import { API_ENDPOINT } from "../utils/constants";

import { IdentityContext } from "./Identity";

const ApolloContext: React.FC = (props) => {
  const { getIdToken } = useContext(IdentityContext);

  // Injects the bearer token into header for every API request
  const withToken = setContext(async (_, { headers }) => {
    const token = await getIdToken();
    return {
      headers: {
        ...headers,
        Authorization: token ? `Bearer ${token}` : null,
      },
    };
  });

  const httpLink = createHttpLink({
    uri: API_ENDPOINT,
  });

  const client = new ApolloClient({
    link: from([withToken, httpLink]),
    connectToDevTools: true,
    cache: new InMemoryCache(),
  });

  return <ApolloProvider client={client}>{props.children}</ApolloProvider>;
};

export default ApolloContext;

package.json dependencies:

"dependencies": {
    "@apollo/client": "^3.4.7",
    "@azure/msal-browser": "^2.16.1",
    "@azure/msal-react": "^1.0.1",
    "@material-ui/core": "^4.12.1",
    "@material-ui/data-grid": "^4.0.0-alpha.34",
    "@material-ui/icons": "^4.11.2",
    "@microsoft/applicationinsights-react-js": "^3.1.5",
    "@microsoft/applicationinsights-web": "^2.6.5",
    "apollo-cache-hermes": "^0.8.16",
    "luxon": "^2.0.1",
    "notistack": "^1.0.10",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-number-format": "^4.6.4",
    "react-router-dom": "^5.2.0"
  },
  "devDependencies": {
    "@babel/preset-env": "^7.14.7",
    "@babel/preset-react": "^7.14.5",
    "@babel/preset-typescript": "^7.14.5",
    "@playlyfe/gql": "^2.6.2",
    "@testing-library/dom": "^8.1.0",
    "@testing-library/jest-dom": "^5.14.1",
    "@testing-library/react": "^12.0.0",
    "@testing-library/user-event": "^13.2.1",
    "@types/enzyme": "^3.10.9",
    "@types/jest": "^26.0.24",
    "@types/luxon": "^1.27.1",
    "@types/react": "^17.0.0",
    "@types/react-dom": "^17.0.0",
    "@types/react-router-dom": "^5.1.8",
    "@typescript-eslint/eslint-plugin": "^4.28.3",
    "@typescript-eslint/parser": "^4.28.3",
    "@vitejs/plugin-react-refresh": "^1.3.1",
    "@wojtekmaj/enzyme-adapter-react-17": "^0.6.2",
    "babel-jest": "^27.0.6",
    "babel-plugin-transform-import-meta": "^2.0.0",
    "enzyme": "^3.11.0",
    "eslint": "^7.30.0",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-import": "^2.23.4",
    "eslint-plugin-jest-dom": "^3.9.0",
    "eslint-plugin-prettier": "^3.4.0",
    "eslint-plugin-react": "^7.24.0",
    "eslint-plugin-testing-library": "^4.10.1",
    "graphql": "^15.5.1",
    "husky": "^7.0.0",
    "jest": "^27.0.6",
    "jest-junit": "^12.2.0",
    "prettier": "^2.3.2",
    "react-test-renderer": "^17.0.2",
    "ts-jest": "^27.0.3",
    "typescript": "^4.3.2",
    "vite": "^2.4.2"
  }

It’s worth noting that I’ve swapped out InMemoryCache for apollo-cache-hermes and everything works as expected.

Have you confirmed that data really only contains the id and __typename? It is expected that objects within the cache are referenced only by id and __typename because the cache is normalized, but they will be resolved to the full objects when they are retrieved from the cache. For example, a todos query might result in the following cache contents:

{
    ROOT_QUERY: {
        __typename: 'Query',
        todos: [{
            __ref: 'Todo:36bad921-8fcf-4f33-9f29-0d3cd70205c8'
        }, {
            __ref: 'Todo:a2096556-9a4e-4994-9de8-86c9e85ed6a1'
        }]
    },
    'Todo:36bad921-8fcf-4f33-9f29-0d3cd70205c8': {
        __typename: 'Todo',
        id: '36bad921-8fcf-4f33-9f29-0d3cd70205c8',
        title: 'Buy groceries'
    },
    'Todo:a2096556-9a4e-4994-9de8-86c9e85ed6a1': {
        __typename: 'Todo',
        id: 'a2096556-9a4e-4994-9de8-86c9e85ed6a1',
        title: 'Do the dishes'
    }
}

If these __ref objects are what you’re seeing in the cache, then all is well. They point towards the actual data (including the title field). If the data returned by your useQuery hook does not contain the actual data, though, then something is seriously wrong, but I can’t see anything in your code that could be causing this.

You are correct that the data variable returned by the useQuery hook does not contain the actual data, however when using apollo-cache-hermes I can see that it does contain the complete normalised data. As far as I can tell, this is not a configuration issue on my part, so I’m at a loss for what to do.

What would be your suggested next steps?

For posterity, I was missing the possibleTypes parameter for the InMemoryCache options, which is needed when querying interfaces in fragments.

1 Like

Solved.