10
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

gRPCマイクロサービス用のgraphql-gatewayサーバーの紹介

Last updated at Posted at 2019-12-13

これは GraphQL Advent Calendar 2019 14日目の記事です。

今回は私が趣味で作っているGraphQL Gatewayについての紹介になります。
gRPCのecosystemには、grpc-gatewayというJSONのREST-APIに変換するリバースプロキシサーバーが存在し、protocol bufferから自動生成することができます。
GraphQL Gatewayも同様にprotocol bufferから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

protoc-gen-goはgRPCを使用するため必要になります。(既にインストール済の場合は必要ありません。)

使い方

今回はサンプルとして、UserServiceBookServiceを作り、UserServiceではIDを指定してユーザデータが取得できるユーザ機能とBookServiceではISBNを指定して本データを取得できるマスター機能を作りたいと思います。

1. protoを定義する

user.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のクエリー文字指定
    };
  }
}

BookService

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"
    };
  }
}

2. reverse-proxyを生成する

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)
	}
}

動作確認

UserServiceBookServiceのgRPCサーバを起動し、先程作成したGraphQLサーバも起動させて実際にアクセスしてみます。

エンドポイントは/graphqlというのが固定で出来ていますので、そこに向けてアクセスしてみます。

(今回はInsomniaというクライアントを使用してアクセスしてみます。)

sample

画像でも分かる通り2つのデータが取得出来ているのが確認できます。

実際はUserServiceBookServiceの異なるgRPCサーバにアクセスして1つのレスポンスとしてフロントに返すことが出来ています。

まとめ

今回、趣味で作っているgraphql-gatewayについて紹介しました。

現在はQueryとMutationまでしか実装出来ていないため、Subscriptionも対応したり、CDNでも利用できるようなキャッシュ機構を付けたり、Apolloなどのクライアントにも対応したりと、やりたいことが沢山あるので粛々とやっていきたいと思います。

(Githubの方にスター等を頂けますと今後の開発のやる気にも繋がるので宜しくおねがいします。)

10
5
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?