Files
teamai-test/.teamai/skills/common/golang-grpc/references/protoc-reference.md
T

4.1 KiB

Protobuf & Code Generation Reference

Directory Layout

Organize proto files by domain with versioned directories. Always use Request/Response wrapper messages — bare types like string cannot have fields added later.

proto/
├── user/v1/
│   ├── user.proto          # Messages
│   └── user_service.proto  # Service RPCs
├── order/v1/
│   ├── order.proto
│   └── order_service.proto
└── shared/v1/
    └── common.proto        # Pagination, timestamps, shared enums

Proto File Conventions

syntax = "proto3";
package mycompany.user.v1;
option go_package = "github.com/mycompany/myservice/gen/user/v1;userv1";

service UserService {
  rpc GetUser(GetUserRequest) returns (GetUserResponse);
  rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
  rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);
  rpc UpdateUser(UpdateUserRequest) returns (UpdateUserResponse);
  rpc DeleteUser(DeleteUserRequest) returns (DeleteUserResponse);
}

message GetUserRequest {
  string user_id = 1;
}

message GetUserResponse {
  User user = 1;
}

message ListUsersRequest {
  int32 page_size = 1;
  string page_token = 2;
}

message ListUsersResponse {
  repeated User users = 1;
  string next_page_token = 2;
}

go_package conventions

  • Format: "import/path;alias" — the alias becomes the Go package name
  • Convention: lowercase version suffix (e.g. userv1, orderv1)
  • Generate into a gen/ directory to keep generated code separate from hand-written code

Code Generation with protoc

# Basic generation
protoc --go_out=gen --go_opt=paths=source_relative \
       --go-grpc_out=gen --go-grpc_opt=paths=source_relative \
       proto/user/v1/*.proto

# With validation (using buf-validate)
protoc --go_out=gen --go_opt=paths=source_relative \
       --go-grpc_out=gen --go-grpc_opt=paths=source_relative \
       --validate_out="lang=go:gen" \
       proto/user/v1/*.proto

# Include external imports
protoc -I proto -I third_party \
       --go_out=gen --go_opt=paths=source_relative \
       --go-grpc_out=gen --go-grpc_opt=paths=source_relative \
       proto/user/v1/*.proto

Common protoc flags

Flag Purpose
--go_out=DIR Output directory for message types
--go-grpc_out=DIR Output directory for service stubs
--go_opt=paths=source_relative Place output relative to proto source
-I DIR Add import path for proto dependencies
--descriptor_set_out=FILE Emit binary descriptor (for reflection)

Code Generation with buf

buf is the recommended modern alternative to raw protoc. It manages dependencies, lints protos, and generates code from a single config.

buf.gen.yaml

version: v2
plugins:
  - remote: buf.build/protocolbuffers/go
    out: gen
    opt: paths=source_relative
  - remote: buf.build/grpc/go
    out: gen
    opt: paths=source_relative

buf.yaml

version: v2
modules:
  - path: proto
lint:
  use:
    - STANDARD
breaking:
  use:
    - FILE

Common buf commands

buf generate              # Generate code from buf.gen.yaml
buf lint                  # Lint proto files
buf breaking --against '.git#branch=main'  # Check backward compatibility
buf dep update            # Update dependencies
buf build                 # Validate proto files compile

Generated Code Patterns

After generation, import and use the generated code:

import (
    userv1 "github.com/mycompany/myservice/gen/user/v1"
)

// Server: implement the interface
type userServer struct {
    userv1.UnimplementedUserServiceServer
}

// Client: use the generated client
client := userv1.NewUserServiceClient(conn)
resp, err := client.GetUser(ctx, &userv1.GetUserRequest{UserId: "123"})

Always embed Unimplemented*Server (not Unsafe*Server) — it provides forward compatibility when new RPCs are added to the proto definition.