Go、Node.jsのプログラム間でRPC通信をする

#概要
`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`をつけると配列になります。
[公式ページ](https://developers.google.com/protocol-buffers/docs/proto3)を参照してください。

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

###.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`ファイルを編集

```: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
```

###クライアント側コードの作成

```go:client.go
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`をコピーしてきます。

```: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
```

###サーバ側コードの作成

```js:server.js
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
```

無事データが送られました！
以上です！