gRPC はGoogleが開発したRPC(Remote Procedure Call)フレームワークです。Protocol Buffers(protobuf)でインターフェイスを定義し、複数言語のコードを自動生成できます。REST APIと比べてバイナリ通信により高速で、型安全なAPI設計が可能です。
REST API との比較
| 項目 | REST API | gRPC |
|---|---|---|
| 通信形式 | JSON(テキスト) | Protocol Buffers(バイナリ) |
| インターフェイス定義 | OpenAPI(任意) | .proto ファイル(必須) |
| コード生成 | ツール依存 | protoc で自動生成 |
| ストリーミング | 非対応(SSE等で補完) | 双方向ストリーミング対応 |
| ブラウザからの直接利用 | 可 | 基本的に不可(gRPC-Webが必要) |
| 向いているケース | 外部公開API | マイクロサービス間通信 |
Protocol Buffers(protobuf)とは
gRPCのインターフェイス定義言語です。.proto ファイルにメッセージ型とサービスを定義し、protoc コンパイラで各言語のコードを生成します。
syntax = "proto3"; message User { int32 id = 1; string name = 2; string email = 3; }
フィールドに付く数字(= 1・= 2)はタグ番号です。バイナリエンコード時の識別子になるため、一度決めたら変更しません。
.proto ファイルの書き方
メッセージ型
syntax = "proto3"; package user; message User { int32 id = 1; string name = 2; string email = 3; bool is_active = 4; } message GetUserRequest { int32 id = 1; } message ListUsersResponse { repeated User users = 1; }
主なスカラー型
| proto型 | Go | Python |
|---|---|---|
string |
string |
str |
int32 |
int32 |
int |
int64 |
int64 |
int |
bool |
bool |
bool |
float |
float32 |
float |
bytes |
[]byte |
bytes |
サービス定義
syntax = "proto3"; package user; option go_package = "./pb"; service UserService { rpc GetUser (GetUserRequest) returns (User); rpc ListUsers (ListUsersRequest) returns (ListUsersResponse); rpc CreateUser (CreateUserRequest) returns (User); rpc DeleteUser (DeleteUserRequest) returns (DeleteUserResponse); } message GetUserRequest { int32 id = 1; } message ListUsersRequest {} message CreateUserRequest { string name = 1; string email = 2; } message DeleteUserRequest { int32 id = 1; } message DeleteUserResponse { bool success = 1; } message ListUsersResponse { repeated User users = 1; } message User { int32 id = 1; string name = 2; string email = 3; }
ツールのインストール
protoc(macOS)
brew install protobuf protoc --version
Go用プラグイン
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
Python
pip install grpcio grpcio-tools
コードの生成
Go
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative proto/user.proto
user.pb.go(メッセージ型)と user_grpc.pb.go(サービスインターフェイス)が生成されます。
Python
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. proto/user.proto
サーバー実装(Go)
package main import ( "context" "log" "net" "google.golang.org/grpc" pb "example.com/myapp/pb" ) type userServer struct { pb.UnimplementedUserServiceServer } func (s *userServer) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.User, error) { return &pb.User{ Id: req.Id, Name: "田中 太郎", Email: "tanaka@example.com", }, nil } func (s *userServer) CreateUser(ctx context.Context, req *pb.CreateUserRequest) (*pb.User, error) { return &pb.User{ Id: 1, Name: req.Name, Email: req.Email, }, nil } func main() { lis, _ := net.Listen("tcp", ":50051") s := grpc.NewServer() pb.RegisterUserServiceServer(s, &userServer{}) log.Println("gRPC server listening on :50051") s.Serve(lis) }
クライアント実装(Go)
package main import ( "context" "log" "time" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" pb "example.com/myapp/pb" ) func main() { conn, _ := grpc.Dial("localhost:50051", grpc.WithTransportCredentials(insecure.NewCredentials()), ) defer conn.Close() client := pb.NewUserServiceClient(conn) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() user, err := client.GetUser(ctx, &pb.GetUserRequest{Id: 1}) if err != nil { log.Fatalf("GetUser failed: %v", err) } log.Printf("User: id=%d name=%s", user.Id, user.Name) }
ストリーミング
gRPCには4種類の通信パターンがあります。
| パターン | .proto の書き方 | 用途 |
|---|---|---|
| Unary | rpc Get(Req) returns (Res) |
通常のリクエスト/レスポンス |
| Server streaming | rpc List(Req) returns (stream Res) |
サーバーが複数レスポンスを返す |
| Client streaming | rpc Upload(stream Req) returns (Res) |
クライアントが複数送信 |
| Bidirectional | rpc Chat(stream Req) returns (stream Res) |
双方向リアルタイム |
Server streaming の例
service UserService { rpc ListUsers (ListUsersRequest) returns (stream User); }
// サーバー側 func (s *userServer) ListUsers(req *pb.ListUsersRequest, stream pb.UserService_ListUsersServer) error { users := []pb.User{{Id: 1, Name: "田中"}, {Id: 2, Name: "鈴木"}} for _, u := range users { stream.Send(&u) } return nil } // クライアント側 stream, _ := client.ListUsers(ctx, &pb.ListUsersRequest{}) for { user, err := stream.Recv() if err == io.EOF { break } log.Printf("受信: %s", user.Name) }
動作確認ツール:grpcurl
curl のgRPC版です。
# インストール
brew install grpcurl
# サービス一覧(リフレクション有効時)
grpcurl -plaintext localhost:50051 list
# メソッド呼び出し
grpcurl -plaintext -d '{"id": 1}' localhost:50051 user.UserService/GetUser
サーバー側でリフレクションを有効にするには:
import "google.golang.org/grpc/reflection" s := grpc.NewServer() reflection.Register(s)
まとめ
1. .proto ファイルにメッセージ型とサービスを定義する 2. protoc でサーバー・クライアントのコードを生成する 3. 生成されたインターフェイスを実装してサーバーを起動する 4. 生成されたクライアントコードでメソッドを呼び出す
| 要素 | 役割 |
|---|---|
.proto |
APIのインターフェイス定義 |
protoc |
コード生成ツール |
50051 |
gRPCのデフォルトポート |
grpcurl |
コマンドラインから動作確認 |
REST APIとの比較・設計については「OpenAPI入門:スキーマ定義からモックサーバーまで」も参考にしてください。
curlでREST APIを叩く方法は「curl入門:GET・POST・PUT・認証・クッキーの使い方まとめ」を参照してください。