[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的网络用户界面

gqlgen_playground.png

还有其他人

有许多功能可以支持,但有许多从未使用过的功能,所以会根据需要进行添加。(希望能尝试使用Dataloaders、Directives、Caching等等)

广告
将在 10 秒后关闭
bannerAds