GraphQLのモデルからファイルを自動生成してくれるgqlgenというものがあります。 GitHub - 99designs/gqlgen: go generate based graphql server librarygo generate based graphql server library. Contribute to 99designs/gqlgen development by creating an account on GitHub.https://github.com/99designs/gqlgen
挙動を理解するために チュートリアル に沿って使ってみました。
Golang ってコードの自動生成多いですね。ようやく慣れてきました。
Initialize
このセクションのコードはこのあとのセクションと区別するために
world/
ディレクトリ配下で行います。
まずは以下のファイルを置いて
以下のコマンドでファイル群を初期化します。
作られたファイルが以下の5つです。
- gqlgen.yml
自動生成の設定ファイル
- schema
- GraphQL の設定ファイルです。
- 配列で複数指定することもできますが、 Glob で指定できるため
schema/*.graphql
のようにディレクトリ配下の設定を一括取り込みしたりもできます。
- exec
後述する models_gen.go をどのようなファイル名、どのようなパッケージ名で出力するか設定できます。
filename
にはパスから指定できるのでディレクトリも変更できます。package
を指定すれば出力するファイルのパッケージ名を変更できます。- 出力するディレクトリ名と合わせる必要があります
- model
- 後述する generated.go をどのようなファイル名、どのようなパッケージ名で出力するか設定できます。 (設定方法は execと同じため省略)
- models
- 手動で生成したモデルを gqlgen に教えてあげるための設定です。
{親ディレクトリまでのパス}/{パッケージ名}.{モデル名}
という具合に指定します。 詳しくは次のセクションまで読み進めてください。
- 手動で生成したモデルを gqlgen に教えてあげるための設定です。
- resolver
- 後述する resolver.go をどのようなファイル名、どのようなパッケージ名で出力するか設定できます。 (設定方法は execと同じため省略)
- type はリゾルバに設定する名前です。変えたからと言って挙動が変わったりはしません。
通常は
Resolver
のままにしておくのがよいでしょう。
- autobind
- 手動で作成したモデルを自動的に読み込むための設定です。 配列でパスを指定すれば該当するモデルを読み込んでくれます。
v0.9.1
から使えます。- How to configure gqlgen using gqlgen.yml - gqlgen
- generated.go
- GraphQL を処理するためのランタイム。 gqlgen 自身はコードを自動生成するだけでランタイムを提供しません。
- このファイルが置かれたディレクトリをモジュールとしてインポートして扱うことになります。手動で変更してはいけません。
ResolverRoot
というインタフェースに意図しないメソッドが出力される場合、抽出すべきフィールドの型が誤っている可能性があります。 (前にハマったのでメモ)- 今回
world/generated.go
というファイルが出力されましたが、ファイルが大きすぎてページの読み込みに支障が出ているのでのせません。
- models_gen.go
- graphql の モデル定義を Golang で扱えるように構造体に変換したコード。手動で変更してはいけません。
- resolver.go
- 実際にリクエストを処理するコードです。初期状態では関数のガワだけが定義されており呼び出すとパニックが発生するので徐々に実装していきます。
- server/server.go
- GraphQLサーバを動かすための最小限のエンドポイント実装です。
早速サーバを起動してみましょう。
$ go run server/server.go 2020/02/09 21:00:00 connect to http://localhost:8080/ for GraphQL playground
続いて localhost:8080 にアクセスしてみると、Play groundが表示されました。
まだ実装されていないので何をやってもエラーになりますが、とりあえず一歩は進展しました。
Implement
- info
- 前のセクションと区別するために
kitty/
ディレクトリ配下で行います。 - ちなみにキティはよく知りません。
- 前のセクションと区別するために
チュートリアルに沿って話を進めていきます。
先程自動生成されたファイルは正しくなかったとしましょう。
Todo
構造体には User
構造体が埋め込まれていましたが、実は UserID だけで十分だったのです。
models_gen.go
に定義された Todo を切り出して
todo.go
に以下のように記述します。
(「切り出して」とは言いましたが、 models_gen.go を編集する必要はありません。どうせこのあと作り直すのでどちらでもよいですが)
設定ファイルも次のようにいじっていきます。
Todo モデルは手動で作ったからそれを見てくれという指定を
models
に追加しただけです。
- info
- 今回はひとつなのであまり気になりませんが、モデルが増えてくると管理が煩雑になってきます。
- 手動で追加したのに gqlgen.yml に登録し忘れることもあるでしょう。
- 先程の説明で軽く触れましたが
autobind
を使うとモデルを自動検出して読み込んでくれます。 つまり、 models の代わりに以下のように autobind を書いても同じことです。 autobind: - hello/kitty
ではもう一度コードの生成を行います。
kitty ディレクトリに移動して
kitty $ go run github.com/99designs/gqlgen -v kitty/todo.go:3 adding resolver method for Todo.user, nothing matched kitty/resolver.go already exists
- info
- 設定ファイルは
--config=
で指定できるため、ファイル名を変える場合はこのオプションとともに利用ください。 -v
は詳細情報表示のオプションです
- 設定ファイルは
generated.go と models_gen.go が修正されました。 (v0.9.0以前では、フィールドのGetterを書かないとパニックになることがあったのですが、現時点の最新v0.10.2では発生しないようです)
先程のコードを比較してみると models_gen.go から Todo モデルが消えているのがわかります。
todo.go
に手動で定義したのでこれは期待通りの動作です。むしろ作られたら困ります。
先程の生成で「 resolver.go
がすでにあるので生成されなかった」と警告が出ていたのに気づきましたか?
resolver.go は編集可能なファイルなので勝手に上書きしたりしません。 作り直す場合は一度削除して再実行します。
kitty $ rm resolver.go kitty $ go run github.com/99designs/gqlgen
少しわかりにくいですが、 TodoResolver
タイプと
User
メソッドが追加されました。
- warning
- お気づきのように Query や Mutation はインタフェースのフィールドに追加されます。
- resolver.go を新規で作る場合はこれらのメソッドも空で作られてくれますが、 すでにある場合は開発者が resolver.go に手動でメソッドを追加してあげないとエラーになるので注意しましょう。
type MutationResolver interface { CreateTodo(ctx context.Context, input NewTodo) (*Todo, error) } type QueryResolver interface { Todos(ctx context.Context) ([]*Todo, error) }
ここに処理を実装していきましょう。
以下のように変更して再度サーバを起動します。
- Resolver は Todo を保存するための Array
todos
を持つ- Resolver を埋め込んだ全ての構造体も同様に todos を参照できる
- CreateTodo は 受け取ったパラメータをもとに Todo を作成し todos に追加する
- Todos は todos をそのまま返却する
動作確認に Mutation(x2) と Query を実行します。
- Mutation1
- Mutation2
- Query
うまく動いているようでよかったです。
ちなみに gqlgen とは直接関係ありませんが、GraphQL Playground はサーバ側の負荷が高いとうんともすんとも言わなくなることがあるので
apollo-client-developer
という Chrome アドオンを使っています。
実際のGraphQLリクエストを捕捉して再送できたりするので便利です。
Apollo Client DevtoolsGraphQL debugging tools for Apollo Client.https://chrome.google.com/webstore/detail/apollo-client-devtools/jdkknkkbebbapilgoeccciglkfbmbnfm
履歴を永続化してくれるともっとうれしいんだけど。