#概要
gRPC
を使用して、Go、Node.jsのプログラム間でRPC通信をします。
クライアント側をGo、サーバ側をNode.jsが担当します。
環境
MacOS Catalina: 10.15.1
Go: 1.13.4
Node.js: 10.15.3
#クライアント(Go)の作成
クライアント側のディレクトリを作成します。
$ mkdir grpc-test-go
クライアント側のディレクトリ構成は最終的に以下のようになります。
$ cd grpc-test-go
$ tree
.
├── bridge
│ ├── bridge.pb.go
│ ├── bridge.proto
│ └── go.mod
├── client.go
└── go.mod
###.protoファイルの作成
protoファイルを作成して、仕様を定義します。
型にrepeated
をつけると配列になります。
公式ページを参照してください。
syntax = "proto3";
package bridge;
service BridgeService {
rpc PostData (Data) returns (Reply) {}
}
message Data {
string key = 1;
repeated string data = 2;
}
message Reply {
string response = 1;
}
###.protoファイルからコードを生成
定義した.protoファイルからクライアント、サーバー共通で使用するコードを生成します。
まず、コードを生成するために必要なprotobuf
パッケージをインストールします。
$ brew install protobuf
$ protoc bridge/bridge.proto --go_out=plugins=grpc:.
これで、bridge.pb.go
が作成されました
###module周りを整理
ローカルでbridge.pb.go
を参照したいので、色々します。
$ go mod init grpc-test-go
$ cd bridge
$ go mod init bridge
grpc-test-go
の方のgo.mod
ファイルを編集
module grpc-test-go
go 1.13
require (
github.com/[username]/grpc-test2/bridge v0.0.0
google.golang.org/grpc v1.25.1
)
replace github.com/[username]/grpc-test-go/bridge => ./bridge
###クライアント側コードの作成
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
pb "github.com/melonattacker/grpc-test-go/bridge"
)
func RpcPost(key string, Data []string) (string, error) {
conn, err := grpc.Dial("127.0.0.1:50051", grpc.WithInsecure())
if err != nil {
return "", err
}
defer conn.Close()
client := pb.NewBridgeServiceClient(conn)
message := &pb.Data{Key: key, Data: Data}
res, err := client.PostData(context.TODO(), message)
response := res.Response
if err != nil {
return "", err
}
return response, nil
}
func main() {
data := []string{"apple", "orange", "lemon"}
result, err := RpcPost("fruit", data);
if err != nil {
fmt.Println(err)
}
fmt.Println(result)
}
$ go build
コンパイルが通るはずです。
#サーバ(Node.js)の作成
サーバ側のディレクトリを作成します。
クライアント側と依存しない形で作成しましょう。
$ mkdir grps-test-node
$ cd grps-test-node
###.protoファイルの作成
上で作成したbridge.proto
をコピーしてきます。
syntax = "proto3";
package bridge;
service BridgeService {
rpc PostData (Data) returns (Reply) {}
}
message Data {
string key = 1;
repeated string data = 2;
}
message Reply {
string response = 1;
}
###必要なnpmパッケージのインストール
$ npm init -y
$ npm install grpc @grpc/proto-loader --save
###サーバ側コードの作成
const grpc = require('grpc')
const protoLoader = require('@grpc/proto-loader')
const PROTO_PATH = __dirname + '/bridge.proto'
const packageDefinition = protoLoader.loadSync(
PROTO_PATH,
{
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true
}
)
const BridgeProto = grpc.loadPackageDefinition(packageDefinition)
const server = new grpc.Server()
const PostData = (call, callback) => {
console.log(call.request);
callback(null, { response: "Data was sent to server with key: " + call.request.key })
}
server.addService(BridgeProto.bridge.BridgeService.service, {
PostData: PostData,
})
server.bind('127.0.0.1:50051', grpc.ServerCredentials.createInsecure())
console.log('Listening on 127.0.0.1:50051...')
server.start()
#実行
###サーバ(Node.js)
$ cd grpc-test-node
$ node main.js
Listening on 127.0.0.1:50051...
###クライアント(Go)
$ cd grpc-test-go
$ go run client.go
###サーバ(Node.js)
{ data: [ 'apple', 'orange', 'lemon' ], key: 'fruit' }
###クライアント(Go)
Data was sent to server with key: fruit
無事データが送られました!
以上です!