Apollo graphql throwing errors on frontend when there are some fields missing in the graph ql response

Query : 
    query sample {
      accountBalance(issuanceRequired: true) {
        uCardAccountBalance {
          purses {
            uCardPurseType
            promotionId
            availableAmount
            startDate
            endDate
            nextDeposit {
              id
              status
              amount
            }
            groceryDiscountsInfo {
              numDiscounts
            }
          }
        }
      }
    }
  `;

With this query sometimes nextDeposit, startDate, endDate from purses
are not available in the graphql response like this

"purses": [
                    {
                        "uCardPurseType": "grocery",
                        "availableAmount": 13.88,
                        "startDate": "2017-02-17T00:00:00",
                        "endDate": "2099-12-31T00:00:00",
                        "groceryDiscountsInfo": {
                            "numDiscounts": 6,
                            "__typename": "UCardPurseGroceryDiscountInfo"
                        },
                        "__typename": "UCardPurse"
                    },
                    {
                        "uCardPurseType": "otc_food_utilities",
                        "availableAmount": 0.0,
                        "__typename": "UCardPurse"
                    },
                    {
                        "uCardPurseType": "renew_rewards",
                        "availableAmount": 0.0,
                        "__typename": "UCardPurse"
                    }
                ],

as you see some fields are missing in two objects of purses, I get errors corresponding to each missing field on the console.

I tried adding them to typePolicies like this but I was wondering how many fields I will end up adding to fix this issues.

Is there a better way to handle it on frontend or backend efficiently?

typePolicies: {
    UCardPurse: {
      fields: {
        startDate: {
          read(existing) {
            return existing || 'N/A'; // Provide a default value if startDate is missing
          },
        },
        endDate: {
          read(existing) {
            return existing || 'N/A'; // Provide a default value if endDate is missing
          },
        },
        nextDeposit: {
          read(existing) {
            console.log('Reading nextDeposit from cache:', existing);
            return existing || {}; // Provide a default value if nextDeposit is missing
          },
        },
      },
    },
  },

Hey @optimistic :waving_hand:

It looks like your server might not be spec compliant. The server response should contain a JSON object with each key listed from the query. Unless you’re using @include or @skip directive, the response is not expected to only return partial data. Apollo Client assumes that a GraphQL server will return a value for every key in the selection set. I would advise checking with your server to ensure it is returning a value for every field.

In the short term, that read function is probably your best bet to ensure you have a value for each of those missing fields, but this would ultimately be best addressed by your server.

FYI null is a valid value and will you will not see a warning if null is provided as a value to any key in your response. I see your read functions are returning a default that matches the field type, but null is also acceptable and would be considered “complete”. When the client reads or writes to the cache, it checks if a field returns undefined to determine if its missing or not. Trying to write a field with undefined will result in the warning you’re seeing. Reading from a field that returns undefined will cause a fetch.

In other words, if your server response looks like this, the warnings will go away (and is spec compliant):

{
  "purses": [
    {
      "uCardPurseType": "grocery",
      "promotionId": null,
      "availableAmount": 13.88,
      "startDate": "2017-02-17T00:00:00",
      "endDate": "2099-12-31T00:00:00",
      "nextDeposit": null,
      "groceryDiscountsInfo": {
        "numDiscounts": 6,
        "__typename": "UCardPurseGroceryDiscountInfo"
      },
      "__typename": "UCardPurse"
    },
    {
      "uCardPurseType": "otc_food_utilities",
      "promotionId": null,
      "availableAmount": 0.0,
      "startDate": null,
      "endDate": null,
      "nextDeposit": null,
      "groceryDiscountsInfo": null,
      "__typename": "UCardPurse"
    },
    {
      "uCardPurseType": "renew_rewards",
      "promotionId": null,
      "availableAmount": 0.0,
      "startDate": null,
      "endDate": null,
      "nextDeposit": null,
      "groceryDiscountsInfo": null,
      "__typename": "UCardPurse"
    }
  ],
}

Let me also suggest one bit of advice on the GraphQL design side. I don’t know if you have any control over the server, but if you do, I’d recommend looking into using a GraphQL interface type (at least this is what it looks like you’re trying to do, given the presence of that uCardPurseType field in the schema). Adding an an interface type here and updating that purses field to return a list of that interface type would make what you’re trying to do possible on the response side, which is not include fields if its a particular type.

Your GraphQL schema would need to be updated to look something like this (this won’t entirely be accurate, but you get the idea):

type Query {
  # or whatever you want to name the interface type
  purses: [UCardPurse]
}

# Ensure this is an `interface` instead of a `type`
interface UCardPurse {
  availableAmount: Float
}

type RenewRewardsUCardPurse implements UCardPurse {
  availableAmount: Float
}

type OTCFoodUtilities implements UCardPurse {
  availableAmount: Float
}

type Grocery implements UCardPurse {
  availableAmount: Float
  startDate: String
  endDate: String
  groceryDiscountsInfo: UCardPurseGroceryDiscountInfo
}

This would allow you to query for those different types without needing that separate uCardPurseType and would let you refine the field selections for each type:

query {
  purses {
    # Shared fields from all types
    availableAmount
  
    # specific fields for your "Grocery" type (or whatever you'd call this)
    ...on Grocery {
      promotionId
      startDate
      endDate
      nextDeposit {
        id
        status
        amount
      }
      groceryDiscountsInfo {
        numDiscounts
      }
    }
  }
}

With this schema/query you’d get a response that looks more like your original, but due to the inline fragments, it would handle this better. If you go this route, just be sure to define possibleTypes so that the cache knows which selection set to traverse properly :slightly_smiling_face: