使用 Go 构建我们的第一个 GraphQL 服务器:实施指南

trivago 为旅行者提供了广泛的酒店选择,使他们能够比较价格并发现最佳的度假优惠。由于有这么多可用的特殊选项,我们引入了一项名为“收藏夹”的新功能来简化导航过程。此功能使用户能够轻松保存他们喜欢的住宿并稍后访问,确保易用性。

幕后花絮

我们已经开始实施强大的后端解决方案来支持该功能,并付出必要的努力来确保其成功。我们最初的计划是使用 GraphQL 服务器(GraphQL 整体)作为 API 和传入请求之间的中间层。这种方法意味着请求在到达 API 之前必须经过另一个服务。下图说明了我们最初的想法以及它的运作方式。

使用 Go 构建我们的第一个 GraphQL 服务器:实施指南-每日运维

值得注意的是,我们的 GraphQL 设置是联合的,这意味着请求通过 GraphQL 网关分布在子图之间。我们的 GraphQL 整体架构就是这样的一个子图。然而,通过整体与网关通信会增加延迟和依赖性,因此我们试图避免这种情况。由于我们已经有一个 GraphQL 网关来减少资源消耗并提高响应时间,因此我们选择通过在网关后面实现专用 GraphQL 服务器来利用它,从而绕过整体。这一变化为我们带来了以下好处:

  • 客户端始终使用网关的架构,幕后更改不会影响任何客户端。
  • 由于我们通过绕过整体跳过了一个步骤,因此客户端可能应该直接从最喜欢的 GraphQL 服务器本身接收更快的响应。
  • 维护和支持更改更容易,因为我们只需更改最喜欢的 GraphQL 服务器上的代码和架构,而不必调整整体架构。
  • Go 支持在同一服务器中使用不同的路由运行 GraphQL 服务器和 REST API,这意味着在需要时迁移现有的 REST API 总是很容易。
  • 在 Go 中实现 GraphQL 服务器非常容易,唯一需要替换的是接口,其余实现保持不变,这意味着不需要额外的复杂实现。
  • 最喜欢的 GraphQL Server 可以完全依赖 GraphQL Gateway 来进行所有凭证身份验证。

下图显示了最终设计。

使用 Go 构建我们的第一个 GraphQL 服务器:实施指南-每日运维

生成 GraphQL 服务器

通过使用名为的库,在 Go 中实现 GraphQL 服务器非常容易 吉吉根 。可以通过以下命令启动 GraphQL 服务器:

<span class="line">go run github.com/99designs/gqlgen init</span>

然后将按照官方说明创建以下文件夹结构 文档

<span class="line">├── go.mod</span>
<span class="line">├── go.sum</span>
<span class="line">├── gqlgen.yml               - The gqlgen config file, knobs for controlling the generated code.</span>
<span class="line">├── graph</span>
<span class="line">│   ├── generated            - A package that only contains the generated runtime</span>
<span class="line">│   │   └── generated.go</span>
<span class="line">│   ├── model                - A package for all your graph models, generated or otherwise</span>
<span class="line">│   │   └── models_gen.go</span>
<span class="line">│   ├── resolver.go          - The root graph resolver type. This file wont get regenerated</span>
<span class="line">│   ├── schema.graphqls      - Some schema. You can split the schema into as many graphql files as you like</span>
<span class="line">│   └── schema.resolvers.go  - the resolver implementation for schema.graphql</span>
<span class="line">└── server.go                - The entry point to your app. Customize it however you see fit</span>

生成文件后,必须定义 GraphQL 服务器的模式,该模式将在 GraphQL 网关的超级图中使用。定义架构后,可以通过运行以下命令来生成模型和解析器:

<span class="line">//go:generate go run github.com/99designs/gqlgen generate</span>

但也可以执行一些 make 命令来生成所需的文件:

<span class="line">GRAPHQL = bin/gqlgen</span>
<span class="line">$(GRAPHQL): export GOBIN := $(PWD)/bin</span>
<span class="line">$(GRAPHQL): go.mod</span>
<span class="line">    $(GO) install github.com/99designs/gqlgen</span>
<span class="line">    $(GO) mod tidy</span>

<span class="line">$(addprefix generate-graphql-,$(COMMANDS)):</span>
<span class="line">generate-graphql-%: export PATH = $(GOROOT)/bin:$(PWD)/bin</span>
<span class="line">generate-graphql-%: $(GRAPHQL)</span>
<span class="line">    $(GO) generate ./cmd/$*/...</span>

其余的代码非常类似于在 Go 中实现传统的 REST API。GraphQL 服务器的处理程序必须启动,并且可以将依赖项注入到 resolver.go

<span class="line">qlSrv := handler.NewDefaultServer(</span>
<span class="line">        generated.NewExecutableSchema(generated.Config{Resolvers: &graph.Resolver{</span>
<span class="line">            Logger:      logger,</span>
<span class="line">            Service:     service</span>
<span class="line">        }}))</span>

之后,依赖项将可在 schema.resolvers.go 中使用,因为它 resolver.go 默认嵌入为属性。

一旦定义了模式并生成了服务器,查询和突变解析器将在 schema.resolvers.go . 这将是 GraphQL 服务器的处理程序文件。以下示例显示了架构定义和用于获取收藏夹的查询:

<span class="line">type Query {</span>
<span class="line">  """</span>
<span class="line">  Returns user's saved favorite accommodations.</span>
<span class="line">  """</span>
<span class="line">  getMyFavoriteAccommodations: MyFavoriteAccommodationsResponse!</span>
<span class="line">}</span>

代码如下所示:

<span class="line">type queryResolver struct{ *Resolver }</span>

<span class="line">func (r *queryResolver) GetMyFavoriteAccommodations(ctx context.Context) (*model.MyFavoriteAccommodationsResponse, error) {...}</span>

该函数是返回用户收藏夹的处理程序。从这一点来看,它与实现传统 REST API 的流程相同,您可以在这里简单地实现您的业务流程。

结论

转换现有 API 可能有些挑战性,但由于 Go 服务器可以支持 REST API 和 GraphQL,因此从一种 API 切换到另一种 API 非常容易。在我们的例子中,客户端仍处于实现阶段,因此我们不需要同时支持 REST API 和 GraphQL 服务器,我们只需切换到 GraphQL 服务器即可。

另一个重要的一点是为您的模式定义编写注释。当超级图收集您构建的模式时,它将呈现给客户,您写的注释越多,客户就越容易导航。