はじめに
Go で gRPC を使い始める際に、.proto
ファイルから自動生成されたコードが思わぬディレクトリ構造に配置されてしまい、インポートがうまくいかない……という経験はありませんか?
本記事では、Go Modules を使ったプロジェクトで、gRPC + Protocol Buffers の開発環境を正しく構築し、スムーズにコード生成・インポートを行うまでの流れを整理します。
前提
- OS: Mac など(Homebrew を利用できる環境)
- Go バージョン: go1.23.6 以上
- Go Modules: 有効化済み
1. プロジェクトの作成と Go Modules の初期化
まずは、新しいディレクトリを作り、そこをプロジェクトのルートとします。ここでは、仮に my-grpc-project
という名前とします。
mkdir my-grpc-project
cd my-grpc-project
go mod init github.com/yourusername/my-grpc-project
-
go.mod
が作成され、モジュールパスがgithub.com/yourusername/my-grpc-project
に設定されます。
2. Protocol Buffers Compiler (protoc) とプラグインのインストール
2-1. protoc のインストール
brew install protobuf
protoc --version
# libprotoc 23.x など、バージョンが表示されればOK
2-2. Go 用 gRPC プラグインのインストール
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
- これらは通常
$(go env GOPATH)/bin
にインストールされます。 -
$PATH
に$(go env GOPATH)/bin
を含めるよう設定しておきます。
3. ディレクトリ構成を決める
最初に、proto
ディレクトリを作成し、その下にサービスごとにフォルダを作るやり方がわかりやすいです。
my-grpc-project/
├── go.mod
└── proto/
└── greeter/
└── greeter.proto
ここでは、greeter
サービスを想定し、proto/greeter
フォルダに .proto
ファイルを配置します。
4. .proto
ファイルの作成
greeter.proto
を以下のように作成します。
syntax = "proto3";
package greeter;
// go_package のインポートパスは、go.mod のモジュールパス + ディレクトリ
option go_package = "github.com/yourusername/my-grpc-project/proto/greeter;greeter";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloResponse);
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string message = 1;
}
-
package greeter;
Protocol Buffers 上のパッケージ名 -
option go_package
生成される Go コードのインポートパスとパッケージ名を指定
例:"github.com/yourusername/my-grpc-project/proto/greeter;greeter"
5. コード生成
プロジェクトルート (my-grpc-project
) で以下のコマンドを実行します。
protoc --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:. proto/greeter/greeter.proto
-
paths=source_relative
オプションを使うと、.proto
ファイルと同じディレクトリ (proto/greeter
) に生成ファイルが配置されます。 - 成功すると、以下のように
.pb.go
や_grpc.pb.go
が生成されます。
my-grpc-project/
├── go.mod
└── proto/
└── greeter/
├── greeter.proto
├── greeter.pb.go
└── greeter_grpc.pb.go
6. 依存関係を追加 (gRPC パッケージ)
生成されたコードを使ってサーバーやクライアントを実装するには、google.golang.org/grpc
を依存関係に追加する必要があります。
go get google.golang.org/grpc@latest
go mod tidy
これで go.mod
と go.sum
に必要な情報が書き込まれ、VSCode のインポートエラーなども解消されます。
7. 簡単な gRPC サーバー実装例
cmd/server/main.go
など、エントリーポイントを用意して以下のように書きます。
package main
import (
"context"
"log"
"net"
"google.golang.org/grpc"
pb "github.com/yourusername/my-grpc-project/proto/greeter"
)
type server struct {
pb.UnimplementedGreeterServer
}
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) {
log.Printf("Received: %v", in.Name)
return &pb.HelloResponse{Message: "Hello " + in.Name}, nil
}
func main() {
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
log.Printf("server listening at %v", lis.Addr())
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
7-1. 実行
cd cmd/server
go run main.go
-
:50051
ポートで gRPC サーバーが起動します。 - 別のターミナルで
grpcurl
などを使えばテストも可能です。
8. まとめ
-
go.mod の初期化
go mod init github.com/yourusername/my-grpc-project
-
Protobuf とプラグインのインストール
brew install protobuf
-
go install protoc-gen-go
/protoc-gen-go-grpc
-
.proto ファイルで go_package を設定
option go_package = "github.com/yourusername/my-grpc-project/proto/greeter;greeter";
-
paths=source_relative
オプションを付けて protoc 実行- 生成ファイルを .proto と同じフォルダへ配置
-
依存関係を go get で追加
go get google.golang.org/grpc@latest
- サーバー実装 & 起動
この流れで、モジュールパスとディレクトリ構造が一致し、VSCode のエラーも起こりにくくなります。
ぜひ試してみてください。何か詰まったらコメントなどで教えていただければ幸いです。
参考リンク
以上が、Go + gRPC + Protocol Buffers を使った開発フローの簡単なまとめです。皆さんの開発がスムーズに進むことを願っています!