I want to get the data referring to a dog from a GraphQL API. Some of the fields returned should not be nullable while others can be. In the below request, the name and the surname of the owner are always present, while the address is a string and is optional.
const GET_DOG = gql`
query GetDog($dogId: String!) {
getDog(dogId: $dogId) {
owner {
name
surname
address
}
}
}
As I want to load my data after clicking a button I use useLazyQuery to get them:
const [getDog, {data}] = useLazyQuery(GET_DOG, {
variables: {
dogId
}
},
onCompleted(data) {
console.log('data retrieved', data)
}
)
The GraphQL API for some dogs doesn't have the address at all, the field address is not returned back in the response. In the network tab, the response is 200 OK and I can see the rest data returned as expected.
On the other side though, as the field address is missing, Apollo throws a warning in the console that address is missing and the data after the request completion are undefined. If I dont request for the address field, then the data are retrieved as expected.
So, the question is how we can query optional fields with Apollo Graphql?
Also if in the above useLazyQuery I add the parameter fetch-policy:'no-cache', the response is resolved... Which is not the best case scenario for me as I want to use the cache.
This is something you can do with the InMemoryCache API in AC3!
new InMemoryCache({
typePolicies: {
// Assuming the __typename of the Dog.owner field is "Person":
Person: {
fields: {
address(existing = null) {
return existing;
},
},
},
},
})
If any data from the server has been written for this field (within this Person object), you'll get that data in the existing parameter. The = null part is a default expression that will be used if existing is undefined. The key here is that returning undefined indicates the field is missing, whereas returning null will suppress the missing field warning. So this field policy ensures you always get at least null for Person.address, which should prevent the warnings.
By the way, if this becomes repetitive, you can shorten the code with a helper function:
function nullable() {
// Create a generic field policy that allows any field to be null by default:
return {
read(existing = null) {
return existing;
},
};
}
new InMemoryCache({
typePolicies: {
Person: {
fields: {
address: nullable(),
middleName: nullable(),
// and so on...
},
},
},
})
Thanks a lot @benjamn! I will apply the solution above :) I do have a ton of fields so the helper function seems really handy
Most helpful comment
By the way, if this becomes repetitive, you can shorten the code with a helper function: