preloader

gqlgenでGraphQLを実装したときに迷ったこと

私自身、Goでサーバーを立てるときrouterだけ chi を使って、あとは標準パッケージで実装することがよくあります。
そんなときにSubscriptionを使ってみたくてGraphQLに手を出してみたのですが、いかんせん初めて触るものだったので、どうしようかと思ったことを以下に列挙していきます(※随時更新)

どう拡張していけばいいのかわからない


gqlgenを使うとまずこの問題にぶち当たることがあると思います。

gqlgenはコマンドを叩くとGraphQLに必要なファイルやパッケージが生成される便利なツールなのですが、スキーマを追加するたびにResolver関連のファイルを消して再度生成しなければいけません。
なので、何度も生成する可能性のあるscheme.resolvers.go(controller, handlerのようなもの?)はなるべく薄くしたいなーとか思ったりしました。
まず思ったのが、このschema.resolvers.goにsqlの処理を何度も書いて消してするのは、辛いなということです。そこでprojectのルートにdatabaseとrepositoryというディレクトリを作って以下のようにしました。

package conf

import (
	"database/sql"
	_ "github.com/lib/pq"
	"os"
)

var (
    // postgresの形式に合わせた文字列
	source = os.Getenv("DATABASE_URL")
)

func NewDatabaseConnection() (*sql.DB, error) {
	conn, err := sql.Open("postgres", source)
	if err != nil {
		return nil, err
	}
	return conn, nil
}
package repository

import (
	"database/sql"
	"[アプリ名]/graph/model"
)

func NewRepository(conn *sql.DB) Repository {
	return &repository{DB: conn}
}

type Repository interface {
	FetchMessages() ([]*model.Message, error)
}

type repository struct {
	DB *sql.DB
}

func (r *repository)FetchMessages() ([]*model.Message, error) {
	var messages []*model.Message
	rows, err := r.DB.Query("SELECT id, name, text FROM messages;")
	if rows == nil {
		return nil, err
	}
	for rows.Next() {
		message := &model.Message{}
		err = rows.Scan(&message.ID, &message.Name, &message.Text)
		if err == nil {
			messages = append(messages, message)
		}
	}
	return messages, nil
}

...

conn, err := conf.NewDatabaseConnection()
if err != nil {
    panic(err)
}
if conn == nil {
    panic(err)
}
defer func() {
    if conn != nil {
        if err := conn.Close(); err != nil {
            panic(err)
        }
    }
}()

repository := repository.NewRepository(conn)

srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &graph.Resolver{Repository: repository}}))

...

type Resolver struct{
	Repository repository.Repository
}

database.goとrepository.go内でそれぞれモジュールを作ってそれをmain.goでDIするというコードです。

自動生成されるgraph/resolver.goの構造体のなかに埋め込んであげれば、 schema.resolvers.goのリゾルバーの中でも r.Repository.FetchMessages() とかしてあげれば、リポジトリー関数をとって来れるようになります。

それでも、ある程度はリゾルバーが厚くなってしまう

リポジトリーを用いて、実装することでコードを減らすことはできたのですが、結局処理によってはリゾルバーが厚くなってしまうんですよね。
これはコントローラーやハンドラーを作って参照させるしかないかなーと思ったのですが、、、 repository.goを見ると

// This file will not be regenerated automatically.
//
// It serves as dependency injection for your app, add any dependencies you require here.

自動的に再生成はされない ここに必要な依存性を追加していく

と書いてあります。
自動生成はされないというのでこちらにschema.resolvers.goをコピーして貼り付けておけば良いのではないか?という感じがします。 その後schema.resolvers.goをコメントアウトしておけばDuplicateエラーも回避できるかと思います。
どうしてもここに追加したくなければ同じパッケージで新しくファイルを作ってそちらにコピーしておけば大丈夫かと思います。

最後に

現在私はGraphQLを使ってアプリケーションを作っている最中なので、また困ったことがあればこちらに追記していこうと思っております。 それではありがとうございました!

comments powered by Disqus

Recent Articles

Get Andromeda-Premium Now

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi egestas
Werat viverra id et aliquet. vulputate egestas sollicitudin.

Download The Theme
*