Apollo client で__typename を自動で付与せず、GraphQL Code Generator で non optional な__typename を実現する

著者は GraphQL のクライアントライブラリは Apollo Client 以外使ったことはないのだが、query や mutation の response に__typenameが勝手についてくる。
取得できる分にはいいのだが、こちらが要求していないのに勝手に返してくるのはやめてほしい。
また、GraphQL Code Generator でgqlタグを使用した Document を返す変数や型定義を自動生成する際に、__typenameのハンドリングもしたい。
そのため、**明示的に要求しない場合、__typename を response に含めないし、型にも含めない。明示的に要求した場合、__typename を response に含め、型にも含める。**ことを目指す。

前提

  • GraphQL のクライアントライブラリは Apollo Client
  • GraphQL Code Generator で型や Document を生成

__typename を勝手に含めないようにする

InMemoryCache の constructor にaddTypename: falseを指定すれば勝手につかなくなる。
Configuring the cache - Client (React) - Apollo GraphQL Docs
勝手につかなくなるが、明示的に要求した場合に限り__typename が取得できるようになる。

型に__typename を含めないようにする

GraphQL Code Generator の config ファイル内で、
skipTypename: trueを指定すれば、自動で optional な値として足されていた__typename がつかなくなる。
TypeScript Operations | GraphQL Code Generator
勝手につかなくなるが、明示的に要求した場合に限り__typename が型に含まれるようになる。

nonOptionalTypename: true にすると__typename が optional にならなくなるので、addTypename: true のときに指定しておくと良さそう。

以上の 2 点で終わり。

なぜ__typename を使うのか

そもそも__typename を使う機会ってなんだったのかおさらいすることで、__typename の取り扱いの判断を明確にする。

cache のキーに使う

Apollo Client のキャッシュ機構では、
__typename:<id>みたいに、id と__typename を組み合わせたユニークなキーを生成するために__typename を使う。
Configuring the cache - Client (React) - Apollo GraphQL Docs
キャッシュ機構を使いたい場合は addTypename を true にしておいたほうがいい。

narrowing の条件に使う

interface を implement した type を実装した場合、__typename を使うことで狭めることができる。
TypeScript: TS Playground - An online editor for exploring TypeScript and JavaScript

interface Node {
  id: ID!
  createdAt: DateTime!
  updatedAt: DateTime
}

type Query {
  node(id: ID!): Node
}

type Book implements Node {
  id: ID!
  createdAt: DateTime!
  updatedAt: DateTime
  "名前"
  name: String!
  "著者"
  author: String!

  "金額"
  price: Price!

  "発売日"
  releaseAt: Date!
}

type Movie implements Node {
  id: ID!
  createdAt: DateTime!
  updatedAt: DateTime
  "名前"
  name: String!
  "映画監督"
  director: String!

  "公開日"
  releaseAt: Date!
  "公開地域"
  releaseCountry: [String!]
}

type Music implements Node {
  id: ID!
  createdAt: DateTime!
  updatedAt: DateTime
  "楽曲名"
  name: String!
  "アーティスト名"
  artist: String!

  "公開日"
  releaseAt: Date!
}

query Sample($id: ID!) {
  node(id: $id) {
    ... on Book {
      __typename
      id
      name
      author #Bookにしかないfield
    }

    ... on Movie {
      __typename
      id
      name
      director #Movieにしかないfield
    }

    ... on Music {
      __typename
      id
      name
      artist #Musicにしかないfield
    }
  }
}

narrowing したい構造の場合は、addTypename を false にした上で、明示的に__typename を要求するといい。

終わりに

response を store に含めたい場合に、わざわざ__typename を store に入れない処理を書かないといけないってなった場合に便利だなと思ってる。
Apollo 的にキャッシュ機構を使ってほしいから addTypename が true になっているんだろうけど、みんなキャッシュ機構使っているんだろうか。