[GraphQL]我想使用gqlgen来实现某事
概括一下
我正在使用gqlgen来实现GraphQL服务器。
我已经对开发有了一些熟悉,但在引入gqlgen时,需要进行一些调查来完成这个任务,需要做什么?要做什么?我稍微写一下。
然而,这些大致都可以在官方文件中找到,所以最好查看那些详细内容。
公式文档
-
- GraphQL
- gqlgen
我想要捕获错误并进行特定于应用程序的处理。
假设在从Resolver返回错误时,我们总是希望执行以下操作。
-
- Internalエラーはログ出力したい
- エラーに応じて決められたjsonフォーマットでエラーメッセージを返したい
为了满足这样的需求,gqlgen的handler.Server提供了一个名为SetErrorPresenter的函数来捕获resolver返回的错误。
在GraphQL中,错误消息被设置在名为extensions的JSON键中。
无法将其添加到其他JSON层次结构中(因为将来可能与GraphQL的名称发生冲突)。
https://github.com/graphql/graphql-spec/releases/tag/June2018
func main() {
// 一部抜粋
srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{}))
srv.SetErrorPresenter(func(ctx context.Context, err error) *gqlerror.Error {
return &gqlerror.Error{
Message: err.Error(),
Extensions: map[string]interface{}{
// 実際には引数のerrorをerrors.As()なりで、動的にtype, codeなどをセットする
"type": "Internal",
"code": "1002567",
},
}
})
}
想要控制恐慌情绪。
我希望在发生恐慌时能够控制应用程序的进程不会终止。与错误的Hook类似,gqlgen的handler.Server中提供了SetRecoverFunc函数,可以使用它来控制当出现恐慌时不会终止应用程序的进程。
func main() {
// 一部抜粋
srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{}))
srv.SetRecoverFunc(func(ctx context.Context, err interface{}) error {
log.From(ctx).Error("recovered", zap.Error(fmt.Errorf("%v", err)))
return &gqlerror.Error{
Message: "server error",
Extensions: map[string]interface{}{
"type": "Internal",
"code": "Unknown",
},
}
})
}
我想要制作定制型的产品。
如果想要在gqlgen中使用自定义的类型,尽管该工具已经提供了一些预定义类型,我们可以指定自己定义的类型,并使用接口来描述它的行为。
这是UnmarshalGQL和MarshalGQL。
UnmarshalGQL是调用函数时,用于与请求的值进行结构绑定的函数,而MarshalGQL是调用函数以返回JSON响应之前的处理函数。
如果要定义并使用一种叫做UUID的自定义类型,那么示例如下:
scalar UUID
# 一部抜粋
models:
UUID:
model: github.com/graphql-app/graph/model.UUID
package model
type UUID struct {
string
}
// UnmarshalGQL implements the graphql.Unmarshaler interface
func (u *UUID) UnmarshalGQL(v interface{}) error {
str, ok := v.(string)
if !ok {
return fmt.Errorf("uuid must be string")
}
if _, err := uuid.Parse(str); err != nil {
return fmt.Errorf("not in uuid format: %w", err)
}
u.string = str
return nil
}
// MarshalGQL implements the graphql.Marshaler interface
func (u UUID) MarshalGQL(w io.Writer) {
_, _ = io.WriteString(w, strconv.Quote(u.string))
}
我想要把`.graphql`模式文件进行分割。
在gqlgen的示例中,经常会在schema.graphql文件中声明Query,Mutation,scalar等。当然,将所有内容追加到一个文件中也是可以的,但如果想要根据不同的角色进行文件分割,则可以按照以下方式进行分割。
只需将文件名与在gqlgen.yml中设置的扩展名保持一致,文件名可以任意指定而不会产生问题。
schema {
query: Query
mutation: Mutation
}
type Query
type Mutation
type User {
id: ID!
name: String!
}
# QueryやMutationはextendキーワードを使用して宣言する
extend type Query {
getUser: User!
}
extend type Mutation {
addUser: User!
}
scalar UUID
我想随意查询Query,或者查看GraphQL模式。
通过启用Introspection功能,类似于grpc的反射功能,可以查看定义的模式列表。
由于gqlgen内置了显示WebUI功能的playground.Handler,与此相结合,可以通过模式定义来输入并补全查询或操作,并快速确认,非常方便。
然而,最好只在开发时将此功能打开。
如果与PlayGround结合使用的话,可以使用以下方式
func main() {
// 一部抜粋
srv := handler.New(generated.NewExecutableSchema(generated.Config{}))
srv.AddTransport(transport.Options{})
srv.AddTransport(transport.GET{})
srv.AddTransport(transport.POST{})
// 環境変数なりでON/OFFするとよい
usePlayGround := true
if usePlayGround {
srv.Use(extension.Introspection{})
}
// ここではルーティングに"github.com/go-chi/chi"を使う前提。ルーティングは好きなものを使ってOK
router := chi.NewRouter()
router.Group(func(r chi.Router) {
r.Handle("/graphql", srv)
if usePlayGround {
r.Handle("/", playground.Handler("graphql playground", "/graphql"))
}
})
}
PlayGround的网络用户界面
还有其他人
有许多功能可以支持,但有许多从未使用过的功能,所以会根据需要进行添加。(希望能尝试使用Dataloaders、Directives、Caching等等)