GraphQLクライアント周り調べて設定した

雑多な感じです

# TypeScript編

サンプルリポジトリ: https://github.com/sisisin-sandbox/try-gql/pull/1
（業務で使ってる構成の再現構成となっています）

## クライアントライブラリ選び

多分選択肢はこんな

- [apollo client](https://www.apollographql.com/docs/react/)
- [relay](https://relay.dev/)
- 生http client

観測範囲でapollo使ってるのを多く見ていた/relayはReact特化っぽい/apolloのclient cacheを使うケースがありそうなどでapollo clientを選択
（といいつつrelayはろくに調べてないです）

## apollo client設定

### apollo clientについて

doc: https://www.apollographql.com/docs/

apolloはreact向けのクライアント以外にもサーバー実装・iOSクライアント・graphqlの運用サポートSaaSという具合に色々提供してくれてるすごいやつ（小並感）
この記事ではreact向けクライアントについて書きます

apollo clientはサーバーへのqueryはもちろんgraphql schemaを用いたローカルの状態管理の仕組み、middleware的なレイヤー（apollo-link）など様々な機能があります
この辺多少調べて設定したのでそれについて書いていきます

### やったこと

- ApolloClientをapollo-boostを使わずに設定（apollo-boostは設定を細かく出来ないので
- apollo client:codegenコマンドによる型定義コード生成
- vscodeの[apollo clientプラグイン](https://marketplace.visualstudio.com/items?itemName=apollographql.vscode-apollo)設定

#### ApolloClientをapollo-boostを使わずに設定

ドキュメントにapollo-boost/apollo-clientの例が入り混じってて大変紛らわしいやつ
apollo-boostはエントリー用パッケージのようなので実戦投入するなら自前でapollo-clientを設定するのが良い
（apollo-client v3ではapollo-boostぐらいのお手軽設定から始められるようになるっぽい）

初期設定自体はapollo-boostからのマイグレーションというドキュメントがあるのでこれを見ればいい
参考リンク: https://www.apollographql.com/docs/react/migrating/boost-migration/

#### apollo client:codegenコマンドによる型定義コード生成

typescript使うなら型定義の生成は人権
選択肢としては他にもいくつかあったが、apollo-clientを利用することにした

他の選択肢

- [graphql code generator](https://graphql-code-generator.com/)
- [ts-graphql-plugin](https://github.com/Quramy/ts-graphql-plugin)
- 後なにか他のも見かけたけど忘れた・・・

選んだ理由としては、

- 一通りの機能をサポートしている
    - 例えばts-graphql-pluginは別名に対応してないなどがある
- 同じエコシステムにしとくほうが無難な気がした（完全に個人の感想）
    - apollo client v3でcustom scalarのdeserializeが書けるようになりそうで、もしそこと生成する型定義が上手くつなぎ込めるなら・・・？という希望もあった
- graphql-code-generator乗り換えは検討しても良いかも？とは思っている
    - 機能はこちらのほうが豊富（後述）


その他細々と以下のような設定をしたりしました

- `globalTypes.ts` は `/__generated__` ではなく `/src` 配下へ配置
    - create-react-appなどを利用する場合に取り回しやすいように
- コード生成時に `--customScalarsPrefix` を付け、 `global.d.ts` のようなファイルを配置してそのファイル内で `declare type GitHubDate=string` のように定義
    - まあサンプル通りですが
- introspectionを使わずschema.graphqlをダウンロードしてきてコード生成に利用
    - 諸般の事情によりサーバーがVPN内にいてCIからエンドポイントを叩けないのでこのような構成に


#### vscodeの[apollo clientプラグイン](https://marketplace.visualstudio.com/items?itemName=apollographql.vscode-apollo)設定

インストールするだけっちゃするだけ
fragmentとかへ定義ジャンプ出来たりフィールド名のサジェストが出てきたりして便利
これがないとschemaを手書きすることになるので大変です

### やってない(やれてない）こと

- apollo-link-scalarsを用いたデータ取得時のcustom scalarのdeserialize
- vscodeの[graphql プラグイン](https://marketplace.visualstudio.com/items?itemName=Prisma.vscode-graphql)によるエディタからのquery実行
- [graphql code generator](https://graphql-code-generator.com/)によるコード生成
- ApolloClientのラッパー実装

#### apollo-link-scalarsを用いたデータ取得時のcustom scalarのdeserialize

custom scalarとして定義された `Date` 型（ISO 8601形式文字列であるとする）をfetchしてきて受け取った時点で `new Date(val)`しておきたい、というのが人情だと思うんですよ（？）
サーバーサイドでは実際そういう仕組はあるけれど、apollo clientではcustom scalarに対してそういった統一的なfetch時のdeserialize処理を挟むことが出来ません

そこでapollo-linkの仕組みを利用して、fetch時にcustom scalarをdeserializeする処理を挟み込んでやってしまおう、というのが [apollo-link-scalars](https://github.com/eturino/apollo-link-scalars) というライブラリのアイデアです
が、問題点があり、

- `apollo-cache-persist` などのhttpを経由しない値の取得で意図通り動かない
    - https://github.com/apollographql/apollo-client/issues/585#issuecomment-400777797
    - apollo-linkの仕組みはあくまでもhttpリクエストを飛ばすとき・レスポンスを受け取るときに解決されるので、メモリキャッシュからの読み込みでは適用されないのが原因
- `apollo-link-scalars` の実装ではサーバーサイド向けの実装に依存している( [Example of loading a schema](https://github.com/eturino/apollo-link-scalars#example-of-loading-a-schema)参照のこと）
    - 結果、bundleサイズがやべえことになる
        - 仮にそこを無視できるとしても、 サーバーサイド実装はユニバーサルなjsとしてメンテされる保証がないのでリスキー
        - 現時点で `graphql-tools` はfsに依存してたりしてcreate-react-appなどではそのままでは動かない
    - ついでにschema.graphql相当の文字列を突っ込むだけでも結構サイズが膨れる

custom scalar対応の[feature requestはある](https://github.com/apollographql/apollo-feature-requests/issues/2)のでapollo client v3に期待・・・？

#### vscodeの[graphql プラグイン](https://marketplace.visualstudio.com/items?itemName=Prisma.vscode-graphql)によるエディタからのquery実行

ちょっと触って詰まったのでちゃんと調べてない・・・（後で試したい）

#### [graphql code generator](https://graphql-code-generator.com/)によるコード生成

先述したようにapollo client:codegenを利用してるのでこちらはやってません
機能的にはこちらのほうが出来ることは多いので再検討しても良いかもとは考えてます

- cameCaseの別名で一括解決してくれる
- custom scalar向けの型を独自定義できる
- 生成した型を利用するreact hookも一緒にコード生成してくれる


ただコード生成って機能が豊富になっても初手の手数が減るだけなのでよっぽど魅力的じゃないとわざわざ乗り換えるほどでもない、とはなりそう・・・

#### ApolloClientのラッパー実装

例えばreduxのmiddlewareレイヤーでクライアントを使いたい場合に欲しいはずなのでそのうちやるつもりです
具体的には、graphql errorのときにrejectedなPromiseが返ってくるためにanyで推論されてしまって、せっかく `GraphQLError` 型があるのに使いにくい、というような点が挙げられます
他には `query`メソッドの型引数が省略可能（デフォルトany）になるなど、微妙な点があるのでその辺をラップした自前のクライアントクラスを作ろうかなとは考えてます
この辺は追々。

# Scala編

sbt-graphqlの話を書こうと思ったけどタイムアップ