Apollo-client: Resolve missing fields in queries when optional ?

Created on 29 Jul 2020  路  3Comments  路  Source: apollographql/apollo-client

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.

鈦夛笍 question

Most helpful comment

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...
      },
    },
  },
})

All 3 comments

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

Was this page helpful?
0 / 5 - 0 ratings