使用 GraphQL 如果需要使用到一些自訂的型別,如同特殊的 DateTime Serialize 的狀況,可以使用 Custom Scalars,本篇文章說明如何使用 Go-gqlgen 的自訂純量 (scalars)。
預先防雷警告,以下文章只是說明純量的操作,本文章輸入出的結果只是作為範例,它必定會失敗,如果是在找 gqlgen 有沒有時間的型別,是有的。
在 GraphQL Schema 檔案開頭就使用:
scalar Time
就可以直接在各處定義中使用 Time 這個型別,例如:
createdAt: Time!
使用 gqlgen ,最好要使用 gqlgen.yml 設定檔去帶入 scalars 模組位置,差別就在於使用指令:
go run github.com/99designs/gqlgen generate
此指令時,會自動去讀取該指令所在目錄下的 gqlgen.yml 檔案。
在設定之前,先說明一下該 yaml 設定檔的內容:
# graphql schema 所有檔案的位置
schema:
- graphql/schema/*.graphql
# generated.go 這個 interface 最後要產生在哪邊
exec:
filename: graphql/schema/generated.go
package: schema
# 給 Apollo federation 使用的,沒有用 apollo 就不需要打開這項設定
federation:
filename: graphql/schema/federation.go
package: schema
# models_gen.go 這個所有結構 struct 的檔案最後要產生在哪邊
model:
filename: graphql/schema/models_gen.go
package: schema
# 需不需要自動幫忙產生預設實作的 resolvers.go 檔案 (不要可以自己關閉)
# auto implements
resolver:
layout: follow-schema
dir: graphql/mar
package: graph
filename_template: "{name}.resolvers.go"
# Optional: turn on use ` + "`" + `gqlgen:"fieldName"` + "`" + ` tags in your models
# struct_tag: json
# Optional: turn on to use []Thing instead of []*Thing
# omit_slice_element_pointers: false
# Optional: set to speed up generation time by not performing a final validation pass.
# skip_validation: true
# gqlgen will search for any type names in the schema in these go packages
# if they match it will use them, otherwise it will generate them.
#autobind:
# - "github.com/your/app/graph/model"
# This section declares type mapping between the GraphQL and go type systems
#
# The first line in each type will be used as defaults for resolver arguments and
# modelgen, the others will be allowed when binding to fields. Configure them to
# your liking
# 額外 (第三方以上) 的純量模組使用
models:
ID:
model:
- github.com/99designs/gqlgen/graphql.ID
- github.com/99designs/gqlgen/graphql.Int
- github.com/99designs/gqlgen/graphql.Int64
- github.com/99designs/gqlgen/graphql.Int32
Int:
model:
- github.com/99designs/gqlgen/graphql.Int
- github.com/99designs/gqlgen/graphql.Int64
- github.com/99designs/gqlgen/graphql.Int32
對於自訂純量,如果要在 graphql 檔案中,使用自訂型別 DateTime,則要先開一個 go 的檔案,使用以下設定做為參考:
package scalars
import (
"fmt"
"io"
"time"
)
// 定義一個型別,叫做 DateTime (有大小寫敏感)
type DateTime struct {
t time.Time
}
func New(t time.Time) *DateTime {
return &DateTime{
t: t,
}
}
func (d *DateTime) GetTime() time.Time {
return d.t
}
// gqlgen 會在每一次 query 中自動做反序列化
func (d *DateTime) UnmarshalGQL(vi interface{}) (err error) {
v, ok := vi.(string)
if !ok {
return fmt.Errorf("unknown type of DateTime: `%+v`", vi)
}
if d.t, err = time.Parse("2006-01-02T15:04:05.000Z", v); err != nil {
return err
}
return nil
}
// gqlgen 會在 query 要回傳 response query 時做序列化,把日期換成時間再丟出去
func (d DateTime) MarshalGQL(w io.Writer) {
w.Write([]byte(d.t.Format(TimeLayout)))
}
假設這個檔案叫做 DateTime.go,那麼就把這個模組放在 gqlgen.yml 描述中:
# 額外 (第三方以上) 的純量模組使用
models:
ID:
model:
- github.com/99designs/gqlgen/graphql.ID
- github.com/99designs/gqlgen/graphql.Int
- github.com/99designs/gqlgen/graphql.Int64
- github.com/99designs/gqlgen/graphql.Int32
Int:
model:
- github.com/99designs/gqlgen/graphql.Int
- github.com/99designs/gqlgen/graphql.Int64
- github.com/99designs/gqlgen/graphql.Int32
DateTime:
model:
- bitbucket.org/xxx/xxx.DateTime # 指向你的 package 位置,斜線到該檔案目錄,用 . 連接裡面的 Type 名稱。 (注意名稱也是有大小寫敏感)
完成後,做 gqlgen generate 就可以看到自動產生的 models_gen.go, resolvers 裡面的 struct 應該都會換成你自訂的型別。
References:
https://gqlgen.com/reference/scalars/
https://blog.laisky.com/p/gqlgen/
https://medium.com/@rtw0913/%E6%B7%BA%E8%AB%87-graphql-%E8%87%AA%E8%A8%82%E7%B4%94%E9%87%8F%E8%AE%8A%E6%95%B8-70c36f9f35b8
沒有留言:
張貼留言