雑多な感じです
TypeScript編
サンプルリポジトリ: https://github.com/sisisin-sandbox/try-gql/pull/1
(業務で使ってる構成の再現構成となっています)
クライアントライブラリ選び
多分選択肢はこんな
- apollo client
- relay
- 生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プラグイン設定
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
- 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プラグイン設定
インストールするだけっちゃするだけ
fragmentとかへ定義ジャンプ出来たりフィールド名のサジェストが出てきたりして便利
これがないとschemaを手書きすることになるので大変です
やってない(やれてない)こと
- apollo-link-scalarsを用いたデータ取得時のcustom scalarのdeserialize
- vscodeのgraphql プラグインによるエディタからのquery実行
- graphql code generatorによるコード生成
- 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 というライブラリのアイデアです
が、問題点があり、
-
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参照のこと)- 結果、bundleサイズがやべえことになる
- 仮にそこを無視できるとしても、 サーバーサイド実装はユニバーサルなjsとしてメンテされる保証がないのでリスキー
- 現時点で
graphql-tools
はfsに依存してたりしてcreate-react-appなどではそのままでは動かない
- ついでにschema.graphql相当の文字列を突っ込むだけでも結構サイズが膨れる
- 結果、bundleサイズがやべえことになる
custom scalar対応のfeature requestはあるのでapollo client v3に期待・・・?
vscodeのgraphql プラグインによるエディタからのquery実行
ちょっと触って詰まったのでちゃんと調べてない・・・(後で試したい)
graphql code generatorによるコード生成
先述したようにapollo client:codegenを利用してるのでこちらはやってません
機能的にはこちらのほうが出来ることは多いので再検討しても良いかもとは考えてます
- cameCaseの別名で一括解決してくれる
- custom scalar向けの型を独自定義できる
- 生成した型を利用するreact hookも一緒にコード生成してくれる
ただコード生成って機能が豊富になっても初手の手数が減るだけなのでよっぽど魅力的じゃないとわざわざ乗り換えるほどでもない、とはなりそう・・・
ApolloClientのラッパー実装
例えばreduxのmiddlewareレイヤーでクライアントを使いたい場合に欲しいはずなのでそのうちやるつもりです
具体的には、graphql errorのときにrejectedなPromiseが返ってくるためにanyで推論されてしまって、せっかく GraphQLError
型があるのに使いにくい、というような点が挙げられます
他には query
メソッドの型引数が省略可能(デフォルトany)になるなど、微妙な点があるのでその辺をラップした自前のクライアントクラスを作ろうかなとは考えてます
この辺は追々。
Scala編
sbt-graphqlの話を書こうと思ったけどタイムアップ