# Key Fields

> Key fields should be defined on all types which have a unique identifier. 

This may seem counter-intuitive to you if 
you've read the Apollo Client documentation -- it says right there that types will default their `keyFields` value to 
`id`, so why should I bother setting this directly? The answer is quite nuanced.

Suppose we have the following types defined in our back-end GraphQL schema:

```graphql
type Song {
  id: ID!
  name: String!
  following: Boolean!
}

type Query {
  song(id: String!): Song
}

type Mutation {
  followSong(id: String!): Song
}
```

And on our client we execute this GraphQL query to retrieve a `Song`

```graphql
query($id: ID!) {
  song(id: $id) {
    id
    name
    following
  }
}
```

which has these corresponding `typePolicies` defined for the Apollo Cache:

```graphql
const typePolicies = {
  Song: {}
}
```

When we issue the query, the results are placed into our Apollo cache as:

```javascript
> __APOLLO_CLIENT__.cache.data.data
{
  "ROOT_QUERY": {
    __typename: "Query",
    "song({\"id\":\"123\"})": {
      __ref: "Song:{\"id\":\"123\"}"
    }
  },
  "Song:{\"id\":\"123\"}": {
    id: 123,
    __typename: "Song",
    name: "Dynamite",
    following: false
  }
}
```

Looks good so far! Now let's assume we perform a simple mutation that will "follow" the song:

```graphql
mutation($id: ID!) {
  followSong(id: $id) {
    following
  }
}
```

Once we execute this, our Apollo cache now looks like this:

```javascript
> __APOLLO_CLIENT__.cache.data.data
{
  "ROOT_QUERY": {
    __typename: "Query",
    "song({\"id\":\"123\"})": {
      __ref: "Song:{\"id\":\"123\"}"
    }
  },
  "Song:{\"id\":\"123\"}": {
    id: 123,
    __typename: "Song",
    name: "Dynamite",
    following: false
  },
  "ROOT_MUTATION": {
    __typename: "Mutation",
    "followSong(\"id\":\"123\")": {
      __typename: "Song",
      following: true
    }
  }
}
```

This doesn't quite look like what we want. What we probably expect to see here is that the default merge type policy 
will apply to the `Song` type, and update the cached reference to set `following` to `true`. Why didn't this happen?

Let's see what happens when we add a `keyFields` for `Song`'s `id` to our type policies:

```javascript
const typePolicies = {
  Song: {
    keyFields: ["id"]
  }
}
```

Now when we run the mutation, we'll see this error message

```
Error: Missing field 'id' while computing key fields
    at new ApolloError
    at Object.next
    at notifySubscription
    at onNotify
    at SubscriptionObserver.next
    ...
```

Interesting. So when we run our mutation, the Apollo cache says that the query is missing the `keyField` for `id`. This
is a very important clarification, because it tells us that the response couldn't be normalized into the Apollo cache
properly. Looking back at our mutation

```graphql
mutation($id: ID!) {
  followSong(id: $id) {
    following
  }
}
```

we see that we didn't return the key field we specified in our type policies in our response, so of course Apollo 
doesn't know where to put it. We _did_ specify it as an input parameter to the mutation, but that value isn't necssarily
associated with the `Song` type definition. So we should change our mutation to return the key field identifier:

```graphql
mutation($id: ID!) {
  followSong(id: $id) {
    id
    following
  }
}
```

and once we run this again we see:

```javascript
> __APOLLO_CLIENT__.cache.data.data
{
  "ROOT_QUERY": {
    __typename: "Query",
    "song({\"id\":\"123\"})": {
      __ref: "Song:{\"id\":\"123\"}"
    }
  },
  "Song:{\"id\":\"123\"}": {
    id: 123,
    __typename: "Song",
    name: "Dynamite",
    following: true
  },
  "ROOT_MUTATION": {
    __typename: "Mutation",
    "followSong(\"id\":\"123\")": {
      __typename: "Song",
      following: true
    }
  }
}
```

Why doesn't Apollo client warn us about this sort of thing when we don't explicitly include the `keyField`? Well, not 
all types are necessarily identifiable. We might have types like:

```graphql
type TimeseriesValue {
  date: Date!
  value: Float!
}

type Song {
  id: ID!
  name: String!
  following: Boolean!
  streams: [TimeseriesValue!]!
}
```

In this case, it doesn't really make sense to define a `keyField` on the `TimeseriesValue` type, since it's really just
a container for data, and not really a proper type in and of itself.