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.
Solved.