Series: gqlgen
Tags: Go Golang GraphQL

【Go】GraphQL で DB から値を取ってきて返す

Go の GraphQL ライブラリである gqlgen を用いて DB から値を取ってきて返す Query を作る。

開発環境

  • go 1.17
  • github.com/99designs/gqlgen v0.17.1
  • github.com/graph-gophers/dataloader v5.0.0+incompatible

本文

注意:gqlgen は開発が活発であり、バージョンが違うとチュートリアルの内容すらも変わるため、この記事を鵜呑みにしないでください。

DB にあらかじめ架空のブログサービスを想定した初期データを投入しておき、幾つかの Query のみ作成した。

今回の完成品は下記なので、詳しくは下記参照。この記事ではかいつまんで記載する。

https://gitlab.com/k1350/daybreak_sample/-/tree/graphql_query_sample

ひな形作成時の詰まりポイント

まず gqlgen の Getting Started に従ってひな形を作ると思うのだが

https://gqlgen.com/getting-started/

ここ一週間の間にいつのまにか gqlgen のバージョンが v0.17.1 に上がっていて、2022/03/05 現在まだ公式の Getting Started に v0.17.1 の内容が書いていない。

v0.17.1 で注意すべきなのは gqlgen.yml の autobind が最初からコメントアウトされていることである。
それによって Getting Started(v0.16.0 版) の “Don’t eagerly fetch the user” という部分で graph/model/todo.go を作成後、そのまま

go run github.com/99designs/gqlgen generate

というコマンドを打つと Todo の定義が重複しているというエラーとなる。

回避方法はリポジトリの README に書いてある通り gqlgen.yml にカスタムモデルを明示的に指定する。

# gqlgen.yml
models:
  Todo:
    model: github.com/[username]/gqlgen-todos/graph/model.Todo

このように指定してから

go run github.com/99designs/gqlgen generate

を打てば models_gen.go から自動生成のモデルが消える。

MySQL のコネクションを resolver に渡す

自動生成された graph/resolver.go にて、Resolver に DB を持たせておく。

type Resolver struct {
	DB *sql.DB
}

DB への接続は server.go 内で行い、server.go の下記の部分で Resolver に DB を渡す。

srv := handler.NewDefaultServer(
	generated.NewExecutableSchema(
		generated.Config{Resolvers: &graph.Resolver{DB: db}},
	),
)

こうすることで graph/schema.resolvers.go 内ではレシーバから DB を取ることができる。

func (r *queryResolver) Blogs(ctx context.Context) ([]*model.Blog, error) {
	// ログインユーザーのユーザーIDが取れるものとする
	userId := -1
	s := `
		SELECT
			id,
			blog_key,
			user_id,
			name,
			description,
			publish_option,
			created_at,
			updated_at
		FROM blog
		WHERE user_id = ?
		ORDER BY id DESC
		`

	rows, err := r.DB.Query(s, userId)

    // 以下略

Dataloader

下記のように dataloader を使ったデータ取得処理を実装する。

dataloader.go

※dataloader の使用方法を把握したくて実装したが、今回の実装だと dataloader を使う必要はなかった

どのタイミングで、どういう経路で DB を渡せばいいのかよくわからなかったのだが、server.go で Middleware を呼ぶときに渡すことにした。

server.go

http.Handle("/query", graph.DataloaderMIddleware(db, srv))

ID について

github.com/99designs/gqlgen では ID を int 型にできるのだが、github.com/graph-gophers/dataloader のほうが int 型にできるのか調べてもわからなかったので文字列型のままにしている。

こういうのはデフォルトのままにしておくほうが良さそう。

次回以降

引き続き Query でページネーションを実装する。