# goctl rpc — RPC Code Generation English | [中文](README-cn.md) goctl rpc is the RPC service code generation module of the `goctl` scaffold. It generates a complete zRPC service from `.proto` files. You only need to write the proto definition and business logic — all boilerplate code is generated automatically. ## Features - **protoc compatible**: Fully compatible with protoc, all protoc arguments are passed through - **External proto imports**: Cross-directory and cross-package proto imports with automatic transitive dependency resolution - **Multiple services**: Define multiple services in a single proto file, auto-grouped by service name - **Streaming support**: Server streaming, client streaming, and bidirectional streaming - **Google well-known types**: Automatic recognition of `google.protobuf.*` types with correct Go imports - **Client generation**: Auto-generated RPC client wrapper code ## Prerequisites ```bash # Install protoc plugins go install google.golang.org/protobuf/cmd/protoc-gen-go@latest go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest ``` ## Quick Start ### Method 1: Create a Service Instantly ```bash goctl rpc new greeter ``` Generates a complete project structure: ``` greeter/ ├── etc/ │ └── greeter.yaml ├── greeter/ │ ├── greeter.pb.go │ └── greeter_grpc.pb.go ├── greeter.go ├── greeter.proto ├── greeterclient/ │ └── greeter.go └── internal/ ├── config/ │ └── config.go ├── logic/ │ └── pinglogic.go ├── server/ │ └── greeterserver.go └── svc/ └── servicecontext.go ``` ### Method 2: Generate from a Proto File 1. Generate a proto template: ```bash goctl rpc template -o=user.proto ``` 2. Initialize the output directory and generate service code: ```bash mkdir -p output && cd output && go mod init example.com/demo && cd .. goctl rpc protoc user.proto \ --go_out=output --go-grpc_out=output --zrpc_out=output \ --go_opt=module=example.com/demo --go-grpc_opt=module=example.com/demo \ --module=example.com/demo -I . ``` --- ## Command Reference ### `goctl rpc protoc` Generate zRPC service code from a `.proto` file. ```bash goctl rpc protoc [flags] ``` **Examples:** ```bash # Basic usage goctl rpc protoc user.proto \ --go_out=output --go-grpc_out=output --zrpc_out=output \ --go_opt=module=example.com/demo --go-grpc_opt=module=example.com/demo \ --module=example.com/demo -I . # Multiple services mode goctl rpc protoc multi.proto \ --go_out=output --go-grpc_out=output --zrpc_out=output \ --go_opt=module=example.com/demo --go-grpc_opt=module=example.com/demo \ --module=example.com/demo -I . -m # Import external protos goctl rpc protoc service.proto \ --go_out=output --go-grpc_out=output --zrpc_out=output \ --go_opt=module=example.com/demo --go-grpc_opt=module=example.com/demo \ --module=example.com/demo -I . -I ./shared_protos # Use Google well-known types goctl rpc protoc service.proto \ --go_out=output --go-grpc_out=output --zrpc_out=output \ --go_opt=module=example.com/demo --go-grpc_opt=module=example.com/demo \ --module=example.com/demo -I . ``` **Flags:** | Flag | Short | Type | Default | Description | |------|-------|------|---------|-------------| | `--zrpc_out` | | string | **required** | Output directory for zRPC service code | | `--go_out` | | string | **required** | Output directory for protoc Go code | | `--go-grpc_out` | | string | **required** | Output directory for protoc gRPC code | | `--go_opt` | | string | | Options for protoc-gen-go (e.g., `module=example.com/demo`) | | `--go-grpc_opt` | | string | | Options for protoc-gen-go-grpc (e.g., `module=example.com/demo`) | | `--proto_path` | `-I` | string[] | | Proto import search directories (repeatable) | | `--multiple` | `-m` | bool | `false` | Multiple services mode | | `--client` | `-c` | bool | `true` | Generate RPC client code | | `--style` | | string | `gozero` | File naming style | | `--module` | | string | | Custom Go module name | | `--name-from-filename` | | bool | `false` | Use filename instead of package name for service naming | | `--verbose` | `-v` | bool | `false` | Enable verbose logging | | `--home` | | string | | goctl template directory | | `--remote` | | string | | Remote template Git repository URL | | `--branch` | | string | | Remote template branch | ### `goctl rpc new` Quickly create a complete RPC service project. ```bash goctl rpc new [flags] ``` **Flags:** | Flag | Short | Type | Default | Description | |------|-------|------|---------|-------------| | `--style` | | string | `gozero` | File naming style | | `--client` | `-c` | bool | `true` | Generate RPC client code | | `--module` | | string | | Custom Go module name | | `--verbose` | `-v` | bool | `false` | Enable verbose logging | | `--idea` | | bool | `false` | Generate IDE project marker | | `--name-from-filename` | | bool | `false` | Use filename instead of package name for service naming | | `--home` | | string | | goctl template directory | | `--remote` | | string | | Remote template Git repository URL | | `--branch` | | string | | Remote template branch | ### `goctl rpc template` Generate a proto file template. ```bash goctl rpc template -o= [flags] ``` **Flags:** | Flag | Type | Description | |------|------|-------------| | `-o` | string | Output file path (required) | | `--home` | string | goctl template directory | | `--remote` | string | Remote template Git repository URL | | `--branch` | string | Remote template branch | --- ## Feature Details ### Multiple Services Mode (`--multiple`) When a proto file contains multiple `service` definitions, the `--multiple` flag is required. ```protobuf service SearchService { rpc Search(SearchReq) returns (SearchReply); } service NotifyService { rpc Notify(NotifyReq) returns (NotifyReply); } ``` **Directory differences with `--multiple`:** | Feature | Default mode | `--multiple` mode | |---------|-------------|-------------------| | Services per proto | Exactly 1 | 1 or more | | Client directory | Named after service | Fixed `client/` directory | | Code organization | Flat structure | Grouped by service name | **`--multiple=false` (default) directory structure:** ``` output/ ├── greeterclient/ │ └── greeter.go ├── internal/ │ ├── logic/ │ │ └── sayhellologic.go │ └── server/ │ └── greeterserver.go └── ... ``` **`--multiple=true` directory structure:** ``` output/ ├── client/ │ ├── searchservice/ │ │ └── searchservice.go │ └── notifyservice/ │ └── notifyservice.go ├── internal/ │ ├── logic/ │ │ ├── searchservice/ │ │ │ └── searchlogic.go │ │ └── notifyservice/ │ │ └── notifylogic.go │ └── server/ │ ├── searchservice/ │ │ └── searchserviceserver.go │ └── notifyservice/ │ └── notifyserviceserver.go └── ... ``` ### External Proto Imports (`--proto_path`) Use `-I` / `--proto_path` to specify additional proto search directories. Supported scenarios: - **Same-directory import**: `import "types.proto";` - **Subdirectory import**: `import "common/types.proto";` - **External directory import**: Proto files outside the project - **Transitive imports**: A imports B, B imports C — goctl resolves recursively - **Cross-package imports**: Different `go_package` values generate correct Go imports automatically ```bash # Search multiple directories for proto files goctl rpc protoc service.proto \ --go_out=output --go-grpc_out=output --zrpc_out=output \ --go_opt=module=example.com/demo --go-grpc_opt=module=example.com/demo \ --module=example.com/demo \ -I . -I ./shared_protos -I /path/to/external_protos ``` ### Service Naming By default, the service name is derived from the proto **package name** (e.g., `package user;` → service name `user`). This allows multiple proto files to share the same package: ``` protos/ ├── user_base.proto # package user; ├── user_auth.proto # package user; └── user_profile.proto # package user; ``` All three files generate into a single `user` service. To use the proto filename for naming (legacy behavior), add the `--name-from-filename` flag. ### Streaming RPC All three gRPC streaming patterns are supported: ```protobuf service StreamService { rpc ServerStream(Req) returns (stream Reply); // Server streaming rpc ClientStream(stream Req) returns (Reply); // Client streaming rpc BidiStream(stream Req) returns (stream Reply); // Bidirectional streaming } ``` ### Google Well-Known Types goctl automatically recognizes and handles Google protobuf well-known types: | Proto Type | Go Type | |-----------|---------| | `google.protobuf.Empty` | `emptypb.Empty` | | `google.protobuf.Timestamp` | `timestamppb.Timestamp` | | `google.protobuf.Duration` | `durationpb.Duration` | | `google.protobuf.Any` | `anypb.Any` | | `google.protobuf.Struct` | `structpb.Struct` | | `google.protobuf.FieldMask` | `fieldmaskpb.FieldMask` | | `google.protobuf.*Value` | `wrapperspb.*Value` | These types can be used directly as RPC parameter types — goctl generates the correct imports automatically. --- ## Examples See the [example/](example/) directory for 10 complete examples covering all generation scenarios. | # | Example | Scenario | |---|---------|----------| | 01 | [Basic service](example/01-basic/) | Single service, no imports | | 02 | [Sibling import](example/02-import-sibling/) | Import from same directory | | 03 | [Subdirectory import](example/03-import-subdir/) | Import from subdirectory | | 04 | [Transitive import](example/04-transitive-import/) | A → B → C dependency chain | | 05 | [Multiple services](example/05-multiple-services/) | `--multiple` mode | | 06 | [Well-known types](example/06-wellknown-types/) | Timestamp etc. in messages | | 07 | [External proto (same pkg)](example/07-external-proto-same-pkg/) | External proto, same go_package | | 08 | [External proto (diff pkg)](example/08-external-proto-diff-pkg/) | External proto, different go_package | | 09 | [Google types as params](example/09-google-types-as-rpc/) | Empty/Timestamp as RPC parameters | | 10 | [Streaming](example/10-streaming/) | Server/client/bidirectional streaming |