TypeScriptなGraphQLサーバをGoにリプレースした
TypeScriptなGraphQLサーバをGoにリプレースした
3-shake Advent Calendar 2022の11日目です。
現在携わっているプロダクトではGraphQLを利用してフロント/バックエンドの通信を行っています。
7月に入社した当初はTypeScriptで開発が進んでおり、ある程度の機能が出揃っていましたが、チーム編成が変わったことによりGoが得意なメンバーがバックエンドを担当することになりました。
そこで既存のGraphQLサーバをGoにリプレースしたのでまとめます。
これまで
既存のGraphQLサーバはTypeScriptをベースに構成されており、以下のようなパッケージを採用していました。
NestJSの拡張機能でGraphQLを取り扱い、Prismaで定義したスキーマを利用して永続化を行っていました。
これから
技術選定
Goへのリプレースでは以下のようなパッケージを採用しました。
gqlgenはGraphQLスキーマ定義ファイルから必要なリゾルバコードを生成してくれるパッケージです。枠組みとなるGoコードを起こしてくれるので穴埋めだけで動作するうえ、map[string]interface{}
などのゆるい型宣言は生成されないので型による補完を利用することができます。
SQLBoilerはDBスキーマからGoコードを生成してくれるパッケージです。テーブル定義やenum定義をGoコードに起こしてくれるので型による補完を利用しながら実装することができます。
sqldefはSQLファイルからDBマイグレーションをしてくれるパッケージです。多くのマイグレーションツールは適用するマイグレーションをファイルごとに分けて管理しますが、このツールは1ファイルで管理します。このことでファイル分割 + gitによるバージョンの二重管理を避けることができました。
HTTPサーバとDB接続は標準パッケージのnet/httpとdatabase/sqlを利用し、外部パッケージは利用しないことにしました。
アーキテクチャ
オニオンアーキテクチャを採用しました。
大きくdomain、usecase、adapter、infraディレクトリに分け、domain層にinterface定義、それ以外にその実装を置くようにしました。たとえばgqlgenが生成するリゾルバはadapter/resolver配下に置き、SQLBoilerが生成するモデルはinfra/persistence配下に置きました。
.
├── adapter
│ ├── dataloader
│ ├── handler
│ ├── presenter
│ ├── resolver
│ ├── server
│ └── service
├── cmd
│ └── server
├── domain
│ ├── client
│ ├── configuration
│ ├── constant
│ ├── handler
│ ├── logger
│ ├── model
│ ├── persistence
│ ├── presenter
│ ├── repository
│ ├── service
│ ├── tracer
│ └── usecase
├── graph
│ ├── generated
│ ├── model
│ └── schema
├── infra
│ ├── client
│ ├── configuration
│ ├── logger
│ ├── persistence
│ ├── repository
│ └── tracer
└── usecase
監視設計
OpenTelemetryを採用しました。
選択肢としてGoogle Cloud Trace/Monitoring、Datadog、Sentryなどがありましたが、いずれにも対応できるパッケージを選定しました。
現在はCloud Traceでトレースを可視化しており、GraphQLリゾルバからDBへ発行されるクエリまでの全ての工程を追えるようにしています。
おまけ
ER図を生成してくれるtblsとGitHub Actionsを使ってER図を自動で生成してくれるようにしました。
GitHub Actionsのcron設定を使って1日1回ジョブが走って、差分がある場合にはPRを作成してくれます。
図に起こすことでリレーションの過不足を知ることができたり、オンボーディング時にサービスの全容を把握するためにかかる時間を削減したりすることを目的としています。
まとめ
メンバーの変化によりTypeScriptからGoにGraphQLサーバを置き換えました。
実は紹介したパッケージたちは「使ってみてダメなら乗り換えよう」のスタンスで実装しながら評価を行った”現在の状態”であり、これからもパッケージは必要があれば乗り換えていきます。
これからも変化に対して柔軟なチームでありたいと考えています。
Discussion