簡単にgRPCを実施してみた

別サイトで過去に投稿した記事シリーズです。
## gRPCとは
gRPC（Google Remote Procedure Call）は、Googleによって開発されたオープンソースのリモートプロシージャコール（RPC）フレームワークです。RPCは、ネットワーク上で異なるシステムやプログラム間での相互作用を可能にするプログラミングモデルです。

そして、gRPCはクライアントとサーバー間で効率的な通信を実現するために、Protocol Buffers（protobuf）を使用します。Protocol Buffersは、データのシリアライズとデータ構造の定義を行うための仕組みであり、効率的なデータの交換を可能にしています。

## gRPCとHTTPの比較

| 特徴 | gRPC | HTTP API |
| ---- | ---- | ---- |
| プロトコル | HTTP/2 | HTTP |
| フォーマット | protobuf | JSON |

詳細な比較はこちら
https://learn.microsoft.com/en-us/aspnet/core/grpc/comparison?view=aspnetcore-7.0#limited-browser-support

## 開発環境
windows 10
go 1.20
protoc 23.3

## 環境構築
windowsの環境構築に苦労したので、つまずきそうなポイントを上げていきます

### Protocol Buffers 導入
Protocol Buffersをインストール際のときMacの方はbrewで簡単に済むと思うのですが、windowsの場合は下記のGithubからダウンロードしてbinファイルにpathを通してください
https://github.com/protocolbuffers/protobuf/releases
http://realize.jounin.jp/path.html

おそらくパスを通したあとパワーシェルではコマンドを実行できますが、vscodeではうまくいかないと思います。自分の解決策としては再起動することで正常に稼働しました。

```
$ protc --version
libprotoc 23.3
```

### gRPCの導入
```
$ go get -u google.golang.org/grpc
```

### Protocol Buffers の Go プラグインを導入
参照したサイトで多くの場合下記のコマンドが書かれてます
```
$ go get -u github.com/golang/protobuf/protoc-gen-go
```


しかし推奨されていないと返ってきます
```
go: module github.com/golang/protobuf is deprecated: Use the "google.golang.org/protobuf" module instead.
```
現在では次のやり方が推奨されてます

```
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
```
# gRPCの実施
今回はチュートリアルにもある簡単なチャットアプリを作りたいと思います！
`/gRPC_chat`ディレクトリを作りました。

## go modの作成
```
go mod init grpc-go-chat
```

## protoファイルの作成
このprotoファイルに定義を書くことによって、protoファイルを実行することでサーバーとクライアントの雛形を作ることができます。

`/gRPC_chat/chat`にchat.protoを作成します

```proto:chat.proto
syntax = "proto3";
package chat;

option go_package="./chat";

message Message {
  string body = 1;
}

service ChatService {
  rpc SayHello(Message) returns (Message) {}
}
```

## protoファイルの実行
protoファイルを実行することによって、`/gRPC_chat/`に`chat_grpc.pb.go`が作成されます

```
$ protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./chat/chat.proto
```

## サーバーの作成
`/gRPC_chat`にメッセージを返すメソッドの作成

```go:chat.go
package chat

import (
	"context"
	"log"
)

type Server struct {
	UnimplementedChatServiceServer
}

func (s Server) SayHello(ctx context.Context, in *Message) (*Message, error) {
	log.Printf("Receive message body from client: %s", in.Body)
	return &Message{Body: "Hello From the server"}, nil
}
```

`/gRPC_chat`にサーバーの処理を作成
```go:server.go
package main

import (
	"grpc-go-chat/chat"
	"google.golang.org/grpc"
	"log"
	"net"
)

func main() {
	lis, err := net.Listen("tcp", ":9000")
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}

	s := chat.Server{}
	grpcServer := grpc.NewServer()
	chat.RegisterChatServiceServer(grpcServer, &s)
	if err := grpcServer.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %s", err)
	}
}
```

## パッケージのインストール
```
go mod tidy
```

## クライアントの作成
`/gRPC_chat/chat`にサーバーと通信するためのクライアントを作成します。

```go:client.go
package main

import (
	"grpc-go-chat/chat"
	"context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"log"
)

func main() {
	var conn *grpc.ClientConn
	conn, err := grpc.Dial(":9000", grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("did not connect: %s", err)
	}
	defer conn.Close()

	c := chat.NewChatServiceClient(conn)

	resp, err := c.SayHello(context.Background(), &chat.Message{
		Body: "Hello From Client!",
	})
	if err != nil {
		log.Fatalf("Error when calling SyaHello: %s", err)
	}
	log.Printf("Responce from server: %s", resp.Body)
}
```

## サーバの起動
```
$ go run server.go
```

## クライアントの実行
もう一つのターミナルで
```
$ go run client.go
```

```
2023/07/05 14:08:31 Responce from server: Hello From the server
```

```
2023/07/05 14:08:31 Receive message body from client: Hello From Client!
```

双方のターミナルでメッセージが受け取られていることが確認できているとわかります。

# まとめ

gRPCの実装いかがでしたでしょうか？
手順通りに踏んでいけば実装できる内容にしてみました！

実際にgRPCの学習を自身で体験してみた気づいたことがあります。
やはり学習コストが高いです．．．
いろいろなサイトに残ってる情報が古かったり、そもそもprotoファイルの記述が難しかったりなどがありました。
しかし、その分双方向ストリーミングの利点などに気づかされました。
これからもすこしづつ触っていきたいと思います。

ご清聴ありがとうございました！！！

以下参照したサイト等です
https://qiita.com/oohira/items/63b5ccb2bf1a913659d6
https://zenn.dev/redgosho/articles/4933994c32bbde
https://tutorialedge.net/golang/go-grpc-beginners-tutorial/
https://www.youtube.com/watch?v=BdzYdN_Zd9Q