Golang 初心者向けgRPCを使ってみよう

#はじめに
**「gRPCって何？」**
**「gRPCを聞いたことあるけど使ったことがない。」**
**「gRPCをGolang/Go言語で使うにはどうしたらいいの？」**

という人向け（私です）に記載しました。
gRPCをGolangで使ってみましょう。

「Go Quick Start」　を参考にしています。
https://grpc.io/docs/quickstart/go.html

#gRPCとは
[gRPC](https://grpc.io/) は、Googleが開発したプロトコルです。デフォルトでは、Protocol Bufferを使って、データをシリアライズ化し、高速な通信が可能です。

gRPCでは、クライアントアプリケーションは別のマシン上のサーバーアプリケーションのメソッドをローカルオブジェクトのように直接呼び出すことができるため、分散型のアプリケーションやサービスを簡単に作成できます。

gRPCは多くの言語をサポートしています。たとえば、Go、Python、またはRubyのクライアントを使用して、JavaでgRPCサーバーを簡単に作成できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317035/2904a9ab-bd25-7cf2-1c13-1d03485cbeea.png)

#Golangで開発してみる

## Goのバージョン
gRPCは、Goのバージョンが1.6以上で使えます。下記のコマンドでバージョンを確認してください。

```
$ go version
```

## gRPCのインストール
下記のコマンドでgRPCをインストールします。

```
$ go get -u -v google.golang.org/grpc
```

## Protocol Buffers v3のインストール

自分の環境に合わせて、こちらからダウンロードします。
https://github.com/protocolbuffers/protobuf/releases

PATHの通ったディレクトリに解凍したディレクトリの/bin の中のバイナリを移してください。

また、macの場合は、下記のコマンドでもインストールできます。

```
$ brew install protobuf
```

次に、Golang用の protoc pluginを下記のようにインストールします。

```
$ go get -u github.com/golang/protobuf/protoc-gen-go
```

もしGolangのPathを通してない場合は、下記のようにPathを通しましょう。

```
$ export PATH=$PATH:$GOPATH/bin
```

#サンプルのビルド

サンプルディレクトリへ移動します。

```
$ cd $GOPATH/src/google.golang.org/grpc/examples/helloworld
```

gRPCでは、`.proto`ファイルを作成します。
`protoc`コンパイラを使って、`.proto`ファイルをビルドして、`.pb.go`ファイルを作成します。
（※サンプルではすでにhelloworld.pb.goが作成されています。）

```
$ protoc -I helloworld/ helloworld/helloworld.proto --go_out=plugins=grpc:helloworld
```

#HelloWorldの実行
サーバとクライアントを実行して、HelloWorldを実行してみましょう。

```
$ go run greeter_server/main.go
```

別のターミナルを開いて、下記を実行します。

```
$ go run greeter_client/main.go
```

すると、`Greeting: Hello world`と表示されます。
gRPCを使って、client-serverアプリケーションを実行できました。

##gRPCの更新

gRPCを更新してみます。`helloworld.proc`を下記のように更新します。
`SayHelloAgain`を追加しています。

```helloworld.proc
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";

package helloworld;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
  // Sends another greeting
  rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}
```

`protoc`コンパイラを使って、`.proto`ファイルをビルドして、`.pb.go`ファイルを作成します。

```
$ protoc -I helloworld/ helloworld/helloworld.proto --go_out=plugins=grpc:helloworld
```

次に、greeter_server/main.goのファイルを更新します。

```.go
func (s *server) SayHelloAgain(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    return &pb.HelloReply{Message: "Hello again " + in.Name}, nil
}
```
を追加して、下記のようになります。

```greeter_server/main.go
/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

//go:generate protoc -I ../helloworld --go_out=plugins=grpc:../helloworld ../helloworld/helloworld.proto

// Package main implements a server for Greeter service.
package main

import (
	"context"
	"log"
	"net"

	"google.golang.org/grpc"
	pb "google.golang.org/grpc/examples/helloworld/helloworld"
)

const (
	port = ":50051"
)

// server is used to implement helloworld.GreeterServer.
type server struct{}

// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	log.Printf("Received: %v", in.Name)
	return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}

func (s *server) SayHelloAgain(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	return &pb.HelloReply{Message: "Hello again " + in.Name}, nil
}

func main() {
	lis, err := net.Listen("tcp", port)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	pb.RegisterGreeterServer(s, &server{})
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}
```

次に、greeter_client/main.goのファイルを更新します。

```.go
	r, err = c.SayHelloAgain(ctx, &pb.HelloRequest{Name: name})
	if err != nil {
			log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.Message)
```

を追加して、下記のようになります。

```greeter_client/main.go
/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

// Package main implements a client for Greeter service.
package main

import (
	"context"
	"log"
	"os"
	"time"

	"google.golang.org/grpc"
	pb "google.golang.org/grpc/examples/helloworld/helloworld"
)

const (
	address     = "localhost:50051"
	defaultName = "world"
)

func main() {
	// Set up a connection to the server.
	conn, err := grpc.Dial(address, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewGreeterClient(conn)

	// Contact the server and print out its response.
	name := defaultName
	if len(os.Args) > 1 {
		name = os.Args[1]
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.Message)
	r, err = c.SayHelloAgain(ctx, &pb.HelloRequest{Name: name})
	if err != nil {
			log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.Message)
}
```

上記と同様に、サーバとクライアントを実行して、HelloWorldを実行してみましょう。

```
$ go run greeter_server/main.go
```

別のターミナルを開いて、下記を実行します。

```
$ go run greeter_client/main.go
```

すると、
`Greeting: Hello world`
`Greeting: Hello again world`
と表示されます。

gRPCを使って、client-serverアプリケーションを更新できました。

#終わりに
gRPCをGolangで動作してみました。

gRPCを使うと、Rest APIは使えなくなるのですが、gRPC-gatewayを使うと使用することができます。
~~それはまた別途記載します。~~

記載しました。
https://qiita.com/ryu3/items/b2882d4f45c7f8485030