Open5

gqlgen 小ネタメモ

こまつやまこまつやま

resolver の生成オプション

resolver.layout に follow-schema を指定すると GQL スキーマファイルと同じ粒度で resovelr のファイルを分割する事ができる。何も指定しないと single-file になる

https://github.com/99designs/gqlgen/blob/f5764a83d54d1f645c942f7a3cf74f1eade34d82/codegen/config/exec.go#L34-L36

現状用意されているのは follow-schemasingle-file だけ
https://github.com/99designs/gqlgen/blob/f5764a83d54d1f645c942f7a3cf74f1eade34d82/codegen/config/exec.go#L26-L31

dir で生成される resolver のディレクトリの指定、package の指定ができる

layout が follow-schema の場合は生成するファイル名のテンプレートを filename_template で指定することができる。{name} とした部分がスキーマファイルの名前に置換される

layout が single-file の場合は resolver のファイル名を filename で指定することができる

https://github.com/99designs/gqlgen/blob/f5764a83d54d1f645c942f7a3cf74f1eade34d82/docs/content/config.md

gqlgen.yaml
# 例
resolver:
  layout: follow-schema
  dir: graph/resolver
  package: resolver
  filename_template: '{name}.custom.go'
こまつやまこまつやま

model の生成オプション

Go の型と GraphQL の型のマッピングを変更したい

models にマッピングを書いてやる。ID 型を int64 で生成する例

gqlgen.yaml
models:
  ID:
    model:
      - github.com/99designs/gqlgen/graphql.Int64

custom scalar を定義する

https://qiita.com/k-kurikuri/items/78451e45810cf84b079a#カスタム型を作りたい

GraphQL のフィールド名から生成される Go のフィールド名をリネームする

Go の略語系の大文字・小文字を揃える命名規則に従いたくなったときに使った

代表的なワードはテンプレートで用意してくれている。これに無いものは手動でフィールド名のマッピングを追加できる

https://github.com/99designs/gqlgen/blob/c6eb1a854225c2618ee6f281401a90a58f535c59/codegen/templates/templates.go#L215-L254
(golangci-lint か何かでも同じような単語の羅列を見たような記憶。)

gqlgen.yaml
models:
  Hoge:
    fields:
      urls:
        fieldName: URLs # GraphQL の type に紐づく struct になる
      hogeHoge:
        fieldName: HugaHuga # 全く別名にすることも一応可能
こまつやまこまつやま

middleware 周り

srv := handler.NewDefaultServer(generated.NewExecutableSchema(
	generated.Config{Resolvers: Resolver{}
))

// その名の通り error の presenter。
// `*gqlerror.Error` が GraphQL のエラーの型になっている。
// エラーに対して共通処理をしたいときはここでやれる
srv.SetErrorPresenter(func(ctx context.Context, err error) *gqlerror.Error {
	var gqlerr *gqlerror.Error
	if errors.As(err, &gqlerr) {
		return gqlerr
	}

	return nil
})

// resolver で発生したランタイムエラーのハンドリング
srv.SetRecoverFunc(func(ctx context.Context, v interface{}) (userMessage error) {
	log.Prinln("resolver で panic が発生しました")

	// ここで返したエラーは ErrorPresenter で受け取ることができる
	return errors.New("internal server error")
})

srv.AroundResponses(func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
	if oc := graphql.GetOperationContext(ctx); oc != nil {
		log.Println(oc.OperationName)
		log.Println(oc.RawQuery)
		log.Println(oc.Variables)
	}

  return next(ctx)
})

srv.AroundRootFields(func(ctx context.Context, next graphql.RootResolver) graphql.Marshaler {
	marshaler := next(ctx)

	return marshaler
})

srv.AroundFields(func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
	res, err = next(ctx)

	return
})

公式の example に AroundFields を使っている箇所があった。

https://github.com/99designs/gqlgen/blob/572fb419fc66c56ac103abf65bb54282d46aec29/example/starwars/server/server.go#L17-L24

こまつやまこまつやま

AroundResponsesAroundRootFieldsArroundFieldsリゾルバの処理AroundFieldsAroundRootFieldsAroundResponses
の順番

こまつやまこまつやま

errors パッケージの import が正しく認識されない問題

errors.Wrap() とかをやってくれるgithub.com/pkg/errors を resolver で import していると、標準パッケージの errors にすげ替わってしまうというバグ。
既知のバグのようで、issue も上がっている。

https://github.com/99designs/gqlgen/issues/1171

こちらのコメントの通り、 import するときにエイリアスを付けてやるやり方で回避。

import e "github.com/pkg/errors"