介绍了用于gRPC微服务的graphql-gateway服务器

这是GraphQL Advent Calendar 2019的第14个帖子。

这次介绍的是我正在以兴趣为基础开发的GraphQL网关。
gRPC生态系统中有一个名为grpc-gateway的反向代理服务器,它可以将JSON转换为REST-API,并能自动生成协议缓冲区。
GraphQL网关也可以类似地根据协议缓冲区自动生成适用于GraphQL的反向代理服务器,供使用。

以下是一种可能的中文翻译:
GitHub存储库

安装步骤

只限于使用Golang进行开发环境的前提条件。

安装 protoc-gen-graphql-gateway

go get -u github.com/grpc-custom/graphql-gateway/cmd/protoc-gen-graphql-gateway
go get -u github.com/golang/protobuf/protoc-gen-go

如果已经安装了gRPC,那就需要使用protoc-gen-go。(如果已经安装了,就不需要了。)

使用方法

我想制作一个作为示例的UserService和BookService。UserService可以根据ID获取用户数据,而BookService可以根据ISBN获取图书数据。

定义proto

用户.proto

syntax = "proto3";
package user;

import "github.com/grpc-custom/graphql-gateway/graphql.proto";

message User {
  int32 id    = 1;
  string name = 2;
}

message GetUserRequest {
  int32 id = 1;
}

message GetUserResponse {
  User user = 1;
}

service UserService {
  rpc GetUser(GetUserRequest) returns (GetUserResponse) {
    // graphql-gatewayのカスタムオプションを指定する
    option (grpc_custom.graphql.schema) = {
      query: "getUser" // GraphQLのクエリー文字指定
    };
  }
}

图书服务

syntax = "proto3";
package book;

import "github.com/grpc-custom/graphql-gateway/graphql.proto";

message Book {
  string isbn  = 1;
  string title = 2;
}

message GetBookRequest {
  string isbn = 1;
}

message GetBookResponse {
  Book book = 1;
}

service BookService {
  rpc GetBook(GetBookRequest) returns (GetBookResponse) {
    option (grpc_custom.graphql.schema) = {
      query: "getBook"
    };
  }
}

生成反向代理

使用protoc命令生成GraphQL服务器。

protoc \
  -I=${GOPATH}/src:. \
  --go_out=plugins=grpc:. \
  --graphql-gateway_out=. \
  /path/to/user.proto
protoc \
  -I=${GOPATH}/src:. \
  --go_out=plugins=grpc:. \
  --graphql-gateway_out=. \
  /path/to/book.proto

生成的文件名为.gql.go。

3. 实施服务器代码

使用由2生成的GraphQL来实现Golang服务器。

package main

import (
    "context"
    "log"
    "net/http"

    "github.com/grpc-custom/graphql-gateway/runtime"
    "google.golang.org/grpc"

    "path/to/book" // protocで生成されたファイルをimport
    "path/to/user"
)

func main() {
    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    defer cancel()

    mux, err := runtime.NewServeMux()
    if err != nil {
        log.Fatal(err)
    }
    opts := []grpc.DialOption{
        grpc.WithInsecure(),
    }
    // gRPCのUserServiceにアクセスするための定義を追加
    err = user.RegisterUserServiceFromEndpoint(ctx, mux, "localhost:9001", opts)
    if err != nil {
        log.Fatal(err)
    }
    // gRPCのBookServiceにアクセスするための定義を追加
    err = book.RegisterBookServiceFromEndpoint(ctx, mux, "localhost:9002", opts)
    if err != nil {
        log.Fatal(err)
    }
    err = http.ListenAndServe(":8080", mux)
    if err != nil {
        log.Fatal(err)
    }
}

确认动作

我们将启动 UserService 和 BookService 的 gRPC 服务器,并启动先前创建的 GraphQL 服务器,然后尝试实际进行访问。

由於端點固定為/graphql,因此我們嘗試將請求發送到該位置。

这次我将使用名为Insomnia的客户端来尝试访问。

sample

可以通过图像看到,可以获取到两个数据。

实际上,我们可以访问UserService和BookService中不同的gRPC服务器,并将它们作为一个响应返回给前端。

整理

本次介绍了我正在用于娱乐目的的graphql-gateway。

由于目前只实现了Query和Mutation,因此还想要添加Subscription的支持,或者增加可以使用CDN的缓存机制,也希望能够兼容Apollo等客户端。因为有很多想做的事情,所以希望能够一步一步地进行。

请支持并给我们的Github项目点赞,这将对我们未来的开发动力产生积极影响,非常感谢!

广告
将在 10 秒后关闭
bannerAds