RSS

gRPC 与 REST 和开放 API

我们今天的客座文章来自 CoreOS 的 Brandon Phillips。CoreOS 为 Linux 容器构建开源项目和产品。他们用于共识和发现的旗舰产品 etcd 和他们的容器引擎 rkt 是 gRPC 的早期采用者。

CoreOS 选择 gRPC 的主要原因之一是它使用 HTTP/2,使应用程序能够在单个 TCP 端口上呈现 HTTP 1.1 REST/JSON API 和高效的 gRPC 接口(可用于 Go)。这为开发人员提供了与 REST Web 生态系统的兼容性,同时推进了一种新的、高效的 RPC 协议。随着 Go 1.6 的发布,Go 默认附带了一个稳定的 net/http2 包。

由于许多 CoreOS 客户端使用带有 JSON 的 HTTP 1.1,gRPC 与 JSON 和 Open API 规范(以前称为 Swagger)的易于互操作性非常有价值。对于那些更习惯于基于 HTTP/1.1+JSON 和 Open API Spec API 的用户,他们使用开源库的组合,以 gRPC 和 HTTP REST 两种风格提供他们的 gRPC 服务,使用 API 多路复用器为用户提供两全其美的体验。让我们深入了解细节,找出他们是如何做到的!

一个名为 EchoService 的 gRPC 应用程序

在本文中,我们将从 gRPC API 定义构建一个小型的概念验证 gRPC 应用程序,添加一个 REST 服务网关,最后在单个 TLS 端口上提供所有内容。该应用程序名为 EchoService,是 shell 命令 echo 的 Web 等效项:该服务返回或“回显”发送给它的任何文本。

首先,让我们在名为 EchoMessage 的 protobuf 消息中定义 EchoService 的参数,其中包括一个名为 value 的字段。我们将在名为 service.proto 的 protobuf“.proto”文件中定义此消息。这是我们的 EchoMessage

message EchoMessage {
 string value = 1;
}

在同一个 .proto 文件中,我们定义一个 gRPC 服务,该服务接受此数据结构并返回它

service EchoService {
  rpc Echo(EchoMessage) returns (EchoMessage) {
  }
}

通过 Protocol Buffer 编译器 protoc “按原样”运行此 service.proto 文件,将生成 Go 中的 stub gRPC 服务,以及各种语言的客户端。但是,仅 gRPC 不如同时公开 REST 接口的服务有用,因此我们不会止步于 gRPC 服务 stub。

接下来,我们添加 gRPC REST 网关。此库将在 gRPC EchoService 之上构建一个 RESTful 代理。要构建此网关,我们在 EchoService .proto 中添加元数据,以指示 Echo RPC 映射到 RESTful POST 方法,并且所有 RPC 参数都映射到 JSON 正文。网关可以将 RPC 参数映射到 URL 路径和查询参数,但为了简洁起见,我们在这里省略了这些复杂性。

service EchoService {
  rpc Echo(EchoMessage) returns (EchoMessage) {
    option (google.api.http) = {
      post: "/v1/echo"
      body: "*"
    };
  }
}

这意味着由 protoc 生成的网关现在可以接受来自 curl 的 HTTP 请求,如下所示

curl -X POST -k https://127.0.0.1:10000/v1/echo -d '{"value": "CoreOS is hiring!"}'

到目前为止,整个系统看起来像这样,单个 service.proto 文件生成 gRPC 服务器和 REST 代理

gRPC API with REST gateway

为了将所有这些结合在一起,echo 服务创建一个 Go http.Handler 来检测协议是否为 HTTP/2 并且 Content-Type 是否为“application/grpc”,并将此类请求发送到 gRPC 服务器。其他所有内容都路由到 REST 网关。代码如下所示

if r.ProtoMajor == 2 && strings.Contains(r.Header.Get("Content-Type"), "application/grpc") {
	grpcServer.ServeHTTP(w, r)
} else {
	otherHandler.ServeHTTP(w, r)
}

要尝试一下,您只需要一个可用的 Go 1.6 开发环境和以下简单命令

go get -u github.com/philips/grpc-gateway-example
grpc-gateway-example serve

在服务器运行时,您可以在 HTTP 1.1 和 gRPC 接口上尝试请求

grpc-gateway-example echo Take a REST from REST with gRPC
curl -X POST -k https://127.0.0.1:10000/v1/echo -d '{"value": "CoreOS is hiring!"}'

最后一个奖励:因为我们有一个 Open API 规范,如果您在笔记本电脑上运行上面的服务器,则可以在 https://127.0.0.1:10000/swagger-ui/#!/EchoService/Echo 上浏览 Open API UI。

gRPC/REST Open API document

我们已经了解了如何使用 gRPC 连接到 REST 世界。如果您想查看完整项目,请查看 GitHub 上的代码库。我们认为这种使用单个 protobuf 描述 API 的模式可以形成一个易于使用、灵活的 API 框架,我们很高兴在更多的项目中使用它。