feat(goctl/rpc): support external proto imports with cross-package ty… (#5472)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
kesonan
2026-03-22 12:01:20 +08:00
committed by GitHub
parent c12c82b2f6
commit 004995f06a
93 changed files with 4871 additions and 270 deletions

View File

@@ -0,0 +1,100 @@
# 示例 01基础 RPC 服务
这是使用 goctl 生成 RPC 服务的最简单示例。
## Proto 定义
一个 `greeter.proto` 文件,包含一个服务和一个 RPC 方法,无外部导入。
`go_package` 使用完整的模块路径:
```protobuf
option go_package = "example.com/demo/greeter";
```
## 生成命令
### 方式一:使用 `goctl rpc new` 快速创建
```bash
# 一条命令创建完整的 RPC 项目
goctl rpc new greeter
```
该命令会同时生成 proto 文件和服务代码:
```
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
```
### 方式二:基于已有 Proto 文件生成
首先,在输出目录中初始化 `go.mod`
```bash
mkdir -p output && cd output && go mod init example.com/demo && cd ..
```
然后生成代码:
```bash
goctl rpc protoc greeter.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 .
```
生成的目录结构:
```
output/
├── etc
│ └── greeter.yaml
├── go.mod
├── greeter
│ ├── greeter.pb.go
│ └── greeter_grpc.pb.go
├── greeter.go
├── greeterclient
│ └── greeter.go
└── internal
├── config
│ └── config.go
├── logic
│ └── sayhellologic.go
├── server
│ └── greeterserver.go
└── svc
└── servicecontext.go
```
## 要点说明
- 这是最简单的场景:一个 proto 文件、一个服务、一个 RPC 方法。
- `go_package` 使用完整的模块路径(`example.com/demo/greeter`),而非相对路径。
- `--module` 告诉 goctl Go 模块名;`--go_opt=module=...``--go-grpc_opt=module=...` 告诉 protoc 从输出路径中去除模块前缀。
- `--zrpc_out` 指定 goctl 生成的服务代码输出目录。
- `--go_out``--go-grpc_out` 指定 protoc 生成代码的输出目录。
- 编辑逻辑文件(`internal/logic/sayhellologic.go`)来实现业务逻辑。

View File

@@ -0,0 +1,100 @@
# Example 01: Basic RPC Service
This is the simplest example of generating an RPC service with goctl.
## Proto Definition
A single `greeter.proto` file with one service and one RPC method, no external imports.
The `go_package` uses a full module path:
```protobuf
option go_package = "example.com/demo/greeter";
```
## Generation Commands
### Method 1: Quick Start with `goctl rpc new`
```bash
# Create a complete RPC project with one command
goctl rpc new greeter
```
This generates the proto file and service code together:
```
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 an Existing Proto
First, initialize the output directory with a `go.mod`:
```bash
mkdir -p output && cd output && go mod init example.com/demo && cd ..
```
Then generate the code:
```bash
goctl rpc protoc greeter.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 .
```
Generated directory structure:
```
output/
├── etc
│ └── greeter.yaml
├── go.mod
├── greeter
│ ├── greeter.pb.go
│ └── greeter_grpc.pb.go
├── greeter.go
├── greeterclient
│ └── greeter.go
└── internal
├── config
│ └── config.go
├── logic
│ └── sayhellologic.go
├── server
│ └── greeterserver.go
└── svc
└── servicecontext.go
```
## Key Points
- This is the simplest scenario: one proto file, one service, one RPC method.
- The `go_package` uses a full module path (`example.com/demo/greeter`), not a relative path.
- The `--module` flag tells goctl the Go module name; `--go_opt=module=...` and `--go-grpc_opt=module=...` tell protoc to strip the module prefix from output paths.
- The `--zrpc_out` flag specifies where the goctl-generated service code goes.
- The `--go_out` and `--go-grpc_out` flags specify where protoc-generated code goes.
- Edit the logic file (`internal/logic/sayhellologic.go`) to implement your business logic.

View File

@@ -0,0 +1,17 @@
syntax = "proto3";
package greeter;
option go_package = "example.com/demo/greeter";
message HelloReq {
string name = 1;
}
message HelloReply {
string message = 1;
}
service Greeter {
rpc SayHello(HelloReq) returns (HelloReply);
}

View File

@@ -0,0 +1,77 @@
# 示例 02导入同级 Proto 文件
本示例演示如何导入同一目录下的 proto 文件。
## Proto 定义
同一目录下的两个 proto 文件共享相同的 `go_package`
- `types.proto` — 定义共享消息类型(`User`)。
- `user.proto` — 定义 RPC 服务,导入 `types.proto`
两个文件使用相同的 `go_package`,采用完整模块路径:
```protobuf
option go_package = "example.com/demo/pb";
```
`user.proto` 通过以下方式导入 `types.proto`
```protobuf
import "types.proto";
```
## 生成命令
首先,在输出目录中初始化 `go.mod`
```bash
mkdir -p output && cd output && go mod init example.com/demo && cd ..
```
然后生成代码:
```bash
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 .
```
生成的目录结构:
```
output/
├── etc
│ └── usersvc.yaml
├── go.mod
├── internal
│ ├── config
│ │ └── config.go
│ ├── logic
│ │ ├── createuserlogic.go
│ │ └── getuserlogic.go
│ ├── server
│ │ └── userserviceserver.go
│ └── svc
│ └── servicecontext.go
├── pb
│ ├── types.pb.go
│ ├── user.pb.go
│ └── user_grpc.pb.go
├── userservice
│ └── userservice.go
└── usersvc.go
```
## 要点说明
- 两个 proto 文件(`user.proto``types.proto`)共享相同的 `go_package = "example.com/demo/pb"`,编译到同一个 Go 包中。
- `user.proto` 通过 `import "types.proto"` 导入 `types.proto`
- 多个 proto 文件共享相同的 `go_package` 时,它们会编译到同一个 Go 包中。
- 只需将包含 `service` 定义的 proto 文件传递给 `goctl rpc protoc`
- 导入的 proto 文件会被 protoc 自动编译,并由 goctl 自动解析。

View File

@@ -0,0 +1,77 @@
# Example 02: Importing a Sibling Proto File
This example demonstrates importing a proto file from the same directory.
## Proto Definition
Two proto files in the same directory share the same `go_package`:
- `types.proto` — Defines shared message types (`User`).
- `user.proto` — Defines the RPC service, importing `types.proto`.
Both files use the same `go_package` with a full module path:
```protobuf
option go_package = "example.com/demo/pb";
```
`user.proto` imports `types.proto` via:
```protobuf
import "types.proto";
```
## Generation Commands
First, initialize the output directory with a `go.mod`:
```bash
mkdir -p output && cd output && go mod init example.com/demo && cd ..
```
Then generate the code:
```bash
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 .
```
Generated directory structure:
```
output/
├── etc
│ └── usersvc.yaml
├── go.mod
├── internal
│ ├── config
│ │ └── config.go
│ ├── logic
│ │ ├── createuserlogic.go
│ │ └── getuserlogic.go
│ ├── server
│ │ └── userserviceserver.go
│ └── svc
│ └── servicecontext.go
├── pb
│ ├── types.pb.go
│ ├── user.pb.go
│ └── user_grpc.pb.go
├── userservice
│ └── userservice.go
└── usersvc.go
```
## Key Points
- Two proto files (`user.proto` and `types.proto`) share the same `go_package = "example.com/demo/pb"`, compiled into a single Go package.
- `user.proto` imports `types.proto` via `import "types.proto"`.
- When multiple proto files share the same `go_package`, they compile into a single Go package.
- Only the proto file containing `service` definitions needs to be passed to `goctl rpc protoc`.
- The imported proto is automatically compiled by protoc and resolved by goctl.

View File

@@ -0,0 +1,11 @@
syntax = "proto3";
package types;
option go_package = "example.com/demo/pb";
message User {
string id = 1;
string name = 2;
int32 age = 3;
}

View File

@@ -0,0 +1,29 @@
syntax = "proto3";
package usersvc;
option go_package = "example.com/demo/pb";
import "types.proto";
message GetUserReq {
string id = 1;
}
message GetUserReply {
types.User user = 1;
}
message CreateUserReq {
string name = 1;
int32 age = 2;
}
message CreateUserReply {
types.User user = 1;
}
service UserService {
rpc GetUser(GetUserReq) returns (GetUserReply);
rpc CreateUser(CreateUserReq) returns (CreateUserReply);
}

View File

@@ -0,0 +1,82 @@
# 示例 03导入子目录中的 Proto 文件
本示例演示如何导入子目录中的 proto 文件。
## Proto 定义
两个 proto 文件有**不同**的 `go_package` 值:
- `order.proto` — 定义 `OrderService`,导入 `common/types.proto`
```protobuf
option go_package = "example.com/demo/pb";
```
- `common/types.proto` — 定义可复用的分页和排序消息。
```protobuf
option go_package = "example.com/demo/pb/common";
```
`order.proto` 从子目录导入 `common/types.proto`
```protobuf
import "common/types.proto";
```
注意两个文件的 `go_package` **不同**,因此会编译到不同的 Go 包中。
## 生成命令
首先,在输出目录中初始化 `go.mod`
```bash
mkdir -p output && cd output && go mod init example.com/demo && cd ..
```
然后生成代码:
```bash
goctl rpc protoc order.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 .
```
生成的目录结构:
```
output/
├── etc
│ └── ordersvc.yaml
├── go.mod
├── internal
│ ├── config
│ │ └── config.go
│ ├── logic
│ │ ├── getorderlogic.go
│ │ └── listorderslogic.go
│ ├── server
│ │ └── orderserviceserver.go
│ └── svc
│ └── servicecontext.go
├── orderservice
│ └── orderservice.go
├── ordersvc.go
└── pb
├── common
│ └── types.pb.go
├── order.pb.go
└── order_grpc.pb.go
```
## 要点说明
- 两个 proto 文件有**不同**的 `go_package` 值,编译到不同的 Go 包中(`pb/``pb/common/`)。
- `order.proto` 从子目录导入 `common/types.proto`
- 当导入的 proto 文件有不同的 `go_package`goctl 会自动生成跨包导入。
- `-I .` 告诉 protoc 从当前目录开始搜索,使其能够找到 `common/types.proto`

View File

@@ -0,0 +1,82 @@
# Example 03: Importing Proto from a Subdirectory
This example demonstrates importing a proto file from a subdirectory.
## Proto Definition
Two proto files with **different** `go_package` values:
- `order.proto` — Defines the `OrderService`, imports `common/types.proto`.
```protobuf
option go_package = "example.com/demo/pb";
```
- `common/types.proto` — Defines reusable pagination and sorting messages.
```protobuf
option go_package = "example.com/demo/pb/common";
```
`order.proto` imports `common/types.proto` from a subdirectory:
```protobuf
import "common/types.proto";
```
Note that the two files have **different** `go_package` values, so they compile into separate Go packages.
## Generation Commands
First, initialize the output directory with a `go.mod`:
```bash
mkdir -p output && cd output && go mod init example.com/demo && cd ..
```
Then generate the code:
```bash
goctl rpc protoc order.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 .
```
Generated directory structure:
```
output/
├── etc
│ └── ordersvc.yaml
├── go.mod
├── internal
│ ├── config
│ │ └── config.go
│ ├── logic
│ │ ├── getorderlogic.go
│ │ └── listorderslogic.go
│ ├── server
│ │ └── orderserviceserver.go
│ └── svc
│ └── servicecontext.go
├── orderservice
│ └── orderservice.go
├── ordersvc.go
└── pb
├── common
│ └── types.pb.go
├── order.pb.go
└── order_grpc.pb.go
```
## Key Points
- Two proto files have **different** `go_package` values, so they compile into separate Go packages (`pb/` and `pb/common/`).
- `order.proto` imports `common/types.proto` from a subdirectory.
- When imported protos have a different `go_package`, goctl automatically generates cross-package imports.
- The `-I .` flag tells protoc to search from the current directory, enabling it to find `common/types.proto`.

View File

@@ -0,0 +1,15 @@
syntax = "proto3";
package common;
option go_package = "example.com/demo/pb/common";
message PageInfo {
int32 page = 1;
int32 size = 2;
}
message SortInfo {
string field = 1;
string order = 2;
}

View File

@@ -0,0 +1,35 @@
syntax = "proto3";
package ordersvc;
option go_package = "example.com/demo/pb";
import "common/types.proto";
message OrderItem {
string id = 1;
string name = 2;
double price = 3;
}
message ListOrdersReq {
common.PageInfo page = 1;
common.SortInfo sort = 2;
}
message ListOrdersReply {
repeated OrderItem orders = 1;
}
message GetOrderReq {
string id = 1;
}
message GetOrderReply {
OrderItem order = 1;
}
service OrderService {
rpc ListOrders(ListOrdersReq) returns (ListOrdersReply);
rpc GetOrder(GetOrderReq) returns (GetOrderReply);
}

View File

@@ -0,0 +1,72 @@
# 示例 04传递性导入
本示例演示 proto 的传递性导入,即 A 导入 BB 导入 C。
## Proto 定义
三个 proto 文件形成传递导入链,共享相同的 `go_package`
```protobuf
option go_package = "example.com/demo/pb";
```
- `base.proto` — C 层:定义基础类型(`BaseResp`)。
- `middleware.proto` — B 层:导入 `base.proto`,定义 `RequestMeta`
- `main.proto` — A 层:导入 `middleware.proto`,定义 `PingService`(入口文件)。
导入链:`main.proto``middleware.proto``base.proto`
## 生成命令
首先,在输出目录中初始化 `go.mod`
```bash
mkdir -p output && cd output && go mod init example.com/demo && cd ..
```
然后生成代码:
```bash
goctl rpc protoc main.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 .
```
生成的目录结构:
```
output/
├── etc
│ └── pingsvc.yaml
├── go.mod
├── internal
│ ├── config
│ │ └── config.go
│ ├── logic
│ │ └── pinglogic.go
│ ├── server
│ │ └── pingserviceserver.go
│ └── svc
│ └── servicecontext.go
├── pb
│ ├── base.pb.go
│ ├── main.pb.go
│ ├── main_grpc.pb.go
│ └── middleware.pb.go
├── pingservice
│ └── pingservice.go
└── pingsvc.go
```
## 要点说明
- 三个 proto 文件(`base.proto``middleware.proto``main.proto`)形成传递导入链。
- goctl 自动递归解析所有传递导入。
- 三个文件共享相同的 `go_package = "example.com/demo/pb"`
- 只需指定入口 proto 文件goctl 和 protoc 会自动处理其余部分。
- 循环导入会被检测并报错(与 protoc 行为一致)。

View File

@@ -0,0 +1,72 @@
# Example 04: Transitive Imports
This example demonstrates transitive proto imports, where A imports B and B imports C.
## Proto Definition
Three proto files form a transitive import chain, all sharing the same `go_package`:
```protobuf
option go_package = "example.com/demo/pb";
```
- `base.proto` — Layer C: defines base types (`BaseResp`).
- `middleware.proto` — Layer B: imports `base.proto`, defines `RequestMeta`.
- `main.proto` — Layer A: imports `middleware.proto`, defines the `PingService` (entry point).
Import chain: `main.proto``middleware.proto``base.proto`
## Generation Commands
First, initialize the output directory with a `go.mod`:
```bash
mkdir -p output && cd output && go mod init example.com/demo && cd ..
```
Then generate the code:
```bash
goctl rpc protoc main.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 .
```
Generated directory structure:
```
output/
├── etc
│ └── pingsvc.yaml
├── go.mod
├── internal
│ ├── config
│ │ └── config.go
│ ├── logic
│ │ └── pinglogic.go
│ ├── server
│ │ └── pingserviceserver.go
│ └── svc
│ └── servicecontext.go
├── pb
│ ├── base.pb.go
│ ├── main.pb.go
│ ├── main_grpc.pb.go
│ └── middleware.pb.go
├── pingservice
│ └── pingservice.go
└── pingsvc.go
```
## Key Points
- Three proto files (`base.proto``middleware.proto``main.proto`) form a transitive import chain.
- goctl recursively resolves all transitive imports automatically.
- All three files share the same `go_package = "example.com/demo/pb"`.
- You only need to specify the entry proto file — goctl and protoc handle the rest.
- Circular imports are detected and will cause an error (same as protoc behavior).

View File

@@ -0,0 +1,10 @@
syntax = "proto3";
package base;
option go_package = "example.com/demo/pb";
message BaseResp {
int32 code = 1;
string msg = 2;
}

View File

@@ -0,0 +1,19 @@
syntax = "proto3";
package pingsvc;
option go_package = "example.com/demo/pb";
import "middleware.proto";
message PingReq {
middleware.RequestMeta meta = 1;
}
message PingReply {
string pong = 1;
}
service PingService {
rpc Ping(PingReq) returns (PingReply);
}

View File

@@ -0,0 +1,12 @@
syntax = "proto3";
package middleware;
option go_package = "example.com/demo/pb";
import "base.proto";
message RequestMeta {
string trace_id = 1;
base.BaseResp base = 2;
}

View File

@@ -0,0 +1,80 @@
# 示例 05多服务模式`--multiple`
本示例演示从一个 proto 文件生成多个 RPC 服务。
## Proto 定义
两个 proto 文件共享相同的 `go_package`
```protobuf
option go_package = "example.com/demo/pb";
```
- `shared.proto` — 定义共享消息类型(`Meta`)。
- `multi.proto` — 定义了**两个**服务:`SearchService``NotifyService`
当 proto 文件包含多个 `service` 块时,必须使用 `-m`(或 `--multiple`)标志。
## 生成命令
首先,在输出目录中初始化 `go.mod`
```bash
mkdir -p output && cd output && go mod init example.com/demo && cd ..
```
然后使用 `-m` 标志生成代码:
```bash
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
```
生成的目录结构:
```
output/
├── client
│ ├── notifyservice
│ │ └── notifyservice.go
│ └── searchservice
│ └── searchservice.go
├── etc
│ └── multisvc.yaml
├── go.mod
├── internal
│ ├── config
│ │ └── config.go
│ ├── logic
│ │ ├── notifyservice
│ │ │ └── notifylogic.go
│ │ └── searchservice
│ │ └── searchlogic.go
│ ├── server
│ │ ├── notifyservice
│ │ │ └── notifyserviceserver.go
│ │ └── searchservice
│ │ └── searchserviceserver.go
│ └── svc
│ └── servicecontext.go
├── multisvc.go
└── pb
├── multi.pb.go
├── multi_grpc.pb.go
└── shared.pb.go
```
## 要点说明
- `-m`(或 `--multiple`)标志启用多服务模式。
- 多服务模式下,`client/` 包含按服务名分组的子目录;`logic/``server/` 也按服务名分组。
- 两个服务共享一个入口文件(`multisvc.go`)和配置。
- 不使用 `--multiple`goctl 只允许每个 proto 文件有一个 `service` 块。
- 所有服务共享同一个 `config.go``servicecontext.go`

View File

@@ -0,0 +1,80 @@
# Example 05: Multiple Services (`--multiple`)
This example demonstrates generating multiple RPC services from a single proto file.
## Proto Definition
Two proto files share the same `go_package`:
```protobuf
option go_package = "example.com/demo/pb";
```
- `shared.proto` — Defines shared message types (`Meta`).
- `multi.proto` — Defines **two** services: `SearchService` and `NotifyService`.
The `-m` (or `--multiple`) flag is required when a proto file contains more than one `service` block.
## Generation Commands
First, initialize the output directory with a `go.mod`:
```bash
mkdir -p output && cd output && go mod init example.com/demo && cd ..
```
Then generate the code with the `-m` flag:
```bash
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
```
Generated directory structure:
```
output/
├── client
│ ├── notifyservice
│ │ └── notifyservice.go
│ └── searchservice
│ └── searchservice.go
├── etc
│ └── multisvc.yaml
├── go.mod
├── internal
│ ├── config
│ │ └── config.go
│ ├── logic
│ │ ├── notifyservice
│ │ │ └── notifylogic.go
│ │ └── searchservice
│ │ └── searchlogic.go
│ ├── server
│ │ ├── notifyservice
│ │ │ └── notifyserviceserver.go
│ │ └── searchservice
│ │ └── searchserviceserver.go
│ └── svc
│ └── servicecontext.go
├── multisvc.go
└── pb
├── multi.pb.go
├── multi_grpc.pb.go
└── shared.pb.go
```
## Key Points
- The `-m` (or `--multiple`) flag enables multiple-service mode.
- In multiple mode, `client/` contains per-service subdirectories; `logic/` and `server/` are also grouped by service name.
- Both services share a single entry point (`multisvc.go`) and config.
- Without `--multiple`, goctl only allows one `service` block per proto file.
- All services share the same `config.go` and `servicecontext.go`.

View File

@@ -0,0 +1,33 @@
syntax = "proto3";
package multisvc;
option go_package = "example.com/demo/pb";
import "shared.proto";
message SearchReq {
shared.Meta meta = 1;
string keyword = 2;
}
message SearchReply {
repeated string items = 1;
}
message NotifyReq {
shared.Meta meta = 1;
string message = 2;
}
message NotifyReply {
bool ok = 1;
}
service SearchService {
rpc Search(SearchReq) returns (SearchReply);
}
service NotifyService {
rpc Notify(NotifyReq) returns (NotifyReply);
}

View File

@@ -0,0 +1,10 @@
syntax = "proto3";
package shared;
option go_package = "example.com/demo/pb";
message Meta {
string trace_id = 1;
string version = 2;
}

View File

@@ -0,0 +1,65 @@
# 示例 06知名类型
本示例演示如何使用 Google protobuf 知名类型(`Timestamp``Duration``Any`)作为消息字段。
## Proto 定义
`events.proto` 使用 `google.protobuf.Timestamp` 作为消息字段类型。
`go_package` 使用完整的模块路径:
```protobuf
option go_package = "example.com/demo/pb";
```
## 生成命令
首先,在输出目录中初始化 `go.mod`
```bash
mkdir -p output && cd output && go mod init example.com/demo && cd ..
```
然后生成代码:
```bash
goctl rpc protoc events.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 .
```
生成的目录结构:
```
output/
├── etc
│ └── eventsvc.yaml
├── eventservice
│ └── eventservice.go
├── eventsvc.go
├── go.mod
├── internal
│ ├── config
│ │ └── config.go
│ ├── logic
│ │ ├── createeventlogic.go
│ │ └── listeventslogic.go
│ ├── server
│ │ └── eventserviceserver.go
│ └── svc
│ └── servicecontext.go
└── pb
├── events.pb.go
└── events_grpc.pb.go
```
## 要点说明
- 使用 Google 知名类型(`google.protobuf.Timestamp``google.protobuf.Duration``google.protobuf.Any`)作为消息字段。
- goctl 自动将知名类型映射到 Go 导入包(`timestamppb``durationpb``anypb` 等)。
- 如果 protoc 已正确安装,知名类型无需额外的 `--proto_path`

View File

@@ -0,0 +1,65 @@
# Example 06: Well-Known Types
This example demonstrates using Google protobuf well-known types (`Timestamp`, `Duration`, `Any`) as message fields.
## Proto Definition
`events.proto` uses `google.protobuf.Timestamp` as a message field type.
The `go_package` uses a full module path:
```protobuf
option go_package = "example.com/demo/pb";
```
## Generation Commands
First, initialize the output directory with a `go.mod`:
```bash
mkdir -p output && cd output && go mod init example.com/demo && cd ..
```
Then generate the code:
```bash
goctl rpc protoc events.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 .
```
Generated directory structure:
```
output/
├── etc
│ └── eventsvc.yaml
├── eventservice
│ └── eventservice.go
├── eventsvc.go
├── go.mod
├── internal
│ ├── config
│ │ └── config.go
│ ├── logic
│ │ ├── createeventlogic.go
│ │ └── listeventslogic.go
│ ├── server
│ │ └── eventserviceserver.go
│ └── svc
│ └── servicecontext.go
└── pb
├── events.pb.go
└── events_grpc.pb.go
```
## Key Points
- Uses Google well-known types (`google.protobuf.Timestamp`, `google.protobuf.Duration`, `google.protobuf.Any`) as message fields.
- goctl automatically maps well-known types to Go imports (`timestamppb`, `durationpb`, `anypb`, etc.).
- No extra `--proto_path` needed for well-known types if protoc is properly installed.

View File

@@ -0,0 +1,35 @@
syntax = "proto3";
package eventsvc;
option go_package = "example.com/demo/pb";
import "google/protobuf/timestamp.proto";
message Event {
string id = 1;
string name = 2;
google.protobuf.Timestamp created_at = 3;
}
message CreateEventReq {
string name = 1;
}
message CreateEventReply {
Event event = 1;
}
message ListEventsReq {
int32 page = 1;
int32 size = 2;
}
message ListEventsReply {
repeated Event events = 1;
}
service EventService {
rpc CreateEvent(CreateEventReq) returns (CreateEventReply);
rpc ListEvents(ListEventsReq) returns (ListEventsReply);
}

View File

@@ -0,0 +1,77 @@
# 示例 07外部 Proto — 相同 `go_package`
本示例演示从外部目录导入 proto 文件,且两个文件共享**相同**的 `go_package`
## Proto 定义
`service.proto``ext.proto` 使用相同的 `go_package`
```protobuf
option go_package = "example.com/demo/pb";
```
源码布局:
```
07-external-proto-same-pkg/
├── ext_protos
│ └── ext.proto # 外部 protogo_package = "example.com/demo/pb"
├── service.proto # 服务定义go_package = "example.com/demo/pb"
├── README.md
└── README-cn.md
```
- `ext.proto` 位于独立目录(`ext_protos/`),但与 `service.proto` 有相同的 `go_package`
- `service.proto` 导入 `ext.proto`,使用 `ext.ExtReq` / `ext.ExtReply` 作为 RPC 类型。
## 生成命令
首先,在输出目录中初始化 `go.mod`
```bash
mkdir -p output && cd output && go mod init example.com/demo && cd ..
```
然后生成代码(注意 `-I ./ext_protos`
```bash
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 ./ext_protos
```
生成的目录结构:
```
output/
├── etc
│ └── svc.yaml
├── go.mod
├── internal
│ ├── config
│ │ └── config.go
│ ├── logic
│ │ └── querylogic.go
│ ├── server
│ │ └── queryserviceserver.go
│ └── svc
│ └── servicecontext.go
├── pb
│ ├── ext.pb.go
│ ├── service.pb.go
│ └── service_grpc.pb.go
├── queryservice
│ └── queryservice.go
└── svc.go
```
## 要点说明
- `ext.proto` 位于独立目录(`ext_protos/`),但与 `service.proto` 有相同的 `go_package`
- 使用 `-I ./ext_protos` 将外部目录添加到 proto 搜索路径。
- 当外部 proto 有**相同**的 `go_package` 时,所有类型合并到一个 Go 包中——无需跨包导入。

View File

@@ -0,0 +1,77 @@
# Example 07: External Proto — Same `go_package`
This example demonstrates importing proto files from an external directory where both files share the **same** `go_package`.
## Proto Definition
Both `service.proto` and `ext.proto` use the same `go_package`:
```protobuf
option go_package = "example.com/demo/pb";
```
Source layout:
```
07-external-proto-same-pkg/
├── ext_protos
│ └── ext.proto # External proto (go_package = "example.com/demo/pb")
├── service.proto # Service definition (go_package = "example.com/demo/pb")
├── README.md
└── README-cn.md
```
- `ext.proto` lives in a separate directory (`ext_protos/`), but has the same `go_package` as `service.proto`.
- `service.proto` imports `ext.proto` and uses `ext.ExtReq` / `ext.ExtReply` as RPC types.
## Generation Commands
First, initialize the output directory with a `go.mod`:
```bash
mkdir -p output && cd output && go mod init example.com/demo && cd ..
```
Then generate the code (note `-I ./ext_protos`):
```bash
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 ./ext_protos
```
Generated directory structure:
```
output/
├── etc
│ └── svc.yaml
├── go.mod
├── internal
│ ├── config
│ │ └── config.go
│ ├── logic
│ │ └── querylogic.go
│ ├── server
│ │ └── queryserviceserver.go
│ └── svc
│ └── servicecontext.go
├── pb
│ ├── ext.pb.go
│ ├── service.pb.go
│ └── service_grpc.pb.go
├── queryservice
│ └── queryservice.go
└── svc.go
```
## Key Points
- `ext.proto` lives in a separate directory (`ext_protos/`), but has the same `go_package` as `service.proto`.
- Use `-I ./ext_protos` to add the external directory to the proto search path.
- When the external proto has the **same** `go_package`, all types merge into one Go package — no cross-package imports are needed.

View File

@@ -0,0 +1,14 @@
syntax = "proto3";
package ext;
option go_package = "example.com/demo/pb";
message ExtReq {
string key = 1;
}
message ExtReply {
string value = 1;
int32 code = 2;
}

View File

@@ -0,0 +1,11 @@
syntax = "proto3";
package svc;
option go_package = "example.com/demo/pb";
import "ext.proto";
service QueryService {
rpc Query(ext.ExtReq) returns (ext.ExtReply);
}

View File

@@ -0,0 +1,78 @@
# 示例 08外部 Proto — 不同 `go_package`
本示例演示从外部目录导入 proto 文件,且文件具有**不同**的 `go_package` 值,需要在生成的 Go 代码中进行跨包导入。
## Proto 定义
proto 文件使用不同的 `go_package` 值:
- `service.proto``go_package = "example.com/demo/pb"`
- `ext_protos/common/types.proto``go_package = "example.com/demo/pb/common"`
源码布局:
```
08-external-proto-diff-pkg/
├── ext_protos
│ └── common
│ └── types.proto # 外部 protogo_package = "example.com/demo/pb/common"
├── service.proto # 服务定义go_package = "example.com/demo/pb"
├── README.md
└── README-cn.md
```
- `types.proto``go_package = "example.com/demo/pb/common"` — **不同**的 Go 包。
- `service.proto` 直接使用 `common.ExtReq` / `common.ExtReply` 作为 RPC 参数类型。
## 生成命令
首先,在输出目录中初始化 `go.mod`
```bash
mkdir -p output && cd output && go mod init example.com/demo && cd ..
```
然后生成代码(注意 `-I ./ext_protos`
```bash
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 ./ext_protos
```
生成的目录结构:
```
output/
├── dataservice
│ └── dataservice.go
├── etc
│ └── svc.yaml
├── go.mod
├── internal
│ ├── config
│ │ └── config.go
│ ├── logic
│ │ └── fetchlogic.go
│ ├── server
│ │ └── dataserviceserver.go
│ └── svc
│ └── servicecontext.go
├── pb
│ ├── common
│ │ └── types.pb.go
│ ├── service.pb.go
│ └── service_grpc.pb.go
└── svc.go
```
## 要点说明
- 当外部 proto 有**不同**的 `go_package`goctl 会自动生成跨包 Go 导入。
- goctl 通过解析导入 proto 的 `go_package` 选项,将 proto 包名(如 `common`)映射到正确的 Go 导入路径。
- `service.proto` 直接使用 `common.ExtReq` / `common.ExtReply` 作为 RPC 参数类型。

View File

@@ -0,0 +1,78 @@
# Example 08: External Proto — Different `go_package`
This example demonstrates importing proto files from an external directory where the files have **different** `go_package` values, requiring cross-package imports in the generated Go code.
## Proto Definition
The proto files use different `go_package` values:
- `service.proto`: `go_package = "example.com/demo/pb"`
- `ext_protos/common/types.proto`: `go_package = "example.com/demo/pb/common"`
Source layout:
```
08-external-proto-diff-pkg/
├── ext_protos
│ └── common
│ └── types.proto # External proto (go_package = "example.com/demo/pb/common")
├── service.proto # Service definition (go_package = "example.com/demo/pb")
├── README.md
└── README-cn.md
```
- `types.proto` has `go_package = "example.com/demo/pb/common"` — a **different** Go package.
- `service.proto` uses `common.ExtReq` / `common.ExtReply` directly as RPC parameter types.
## Generation Commands
First, initialize the output directory with a `go.mod`:
```bash
mkdir -p output && cd output && go mod init example.com/demo && cd ..
```
Then generate the code (note `-I ./ext_protos`):
```bash
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 ./ext_protos
```
Generated directory structure:
```
output/
├── dataservice
│ └── dataservice.go
├── etc
│ └── svc.yaml
├── go.mod
├── internal
│ ├── config
│ │ └── config.go
│ ├── logic
│ │ └── fetchlogic.go
│ ├── server
│ │ └── dataserviceserver.go
│ └── svc
│ └── servicecontext.go
├── pb
│ ├── common
│ │ └── types.pb.go
│ ├── service.pb.go
│ └── service_grpc.pb.go
└── svc.go
```
## Key Points
- When the external proto has a **different** `go_package`, goctl generates cross-package Go imports automatically.
- goctl resolves the proto package name (e.g., `common`) to the correct Go import path by parsing the imported proto's `go_package` option.
- `service.proto` uses `common.ExtReq` / `common.ExtReply` directly as RPC parameter types.

View File

@@ -0,0 +1,15 @@
syntax = "proto3";
package common;
option go_package = "example.com/demo/pb/common";
message ExtReq {
string key = 1;
string source = 2;
}
message ExtReply {
string value = 1;
int32 code = 2;
}

View File

@@ -0,0 +1,11 @@
syntax = "proto3";
package svc;
option go_package = "example.com/demo/pb";
import "common/types.proto";
service DataService {
rpc Fetch(common.ExtReq) returns (common.ExtReply);
}

View File

@@ -0,0 +1,65 @@
# 示例 09Google 类型作为 RPC 参数
本示例演示将 Google protobuf 知名类型**直接**用作 RPC 请求或响应类型(而不仅仅是消息字段)。
## Proto 定义
`service.proto` 使用 `google.protobuf.Empty``google.protobuf.Timestamp` 直接作为 RPC 请求/响应类型。
`go_package` 使用完整的模块路径:
```protobuf
option go_package = "example.com/demo/pb";
```
## 生成命令
首先,在输出目录中初始化 `go.mod`
```bash
mkdir -p output && cd output && go mod init example.com/demo && cd ..
```
然后生成代码:
```bash
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 .
```
生成的目录结构:
```
output/
├── etc
│ └── healthsvc.yaml
├── go.mod
├── healthservice
│ └── healthservice.go
├── healthsvc.go
├── internal
│ ├── config
│ │ └── config.go
│ ├── logic
│ │ ├── gettimelogic.go
│ │ └── pinglogic.go
│ ├── server
│ │ └── healthserviceserver.go
│ └── svc
│ └── servicecontext.go
└── pb
├── service.pb.go
└── service_grpc.pb.go
```
## 要点说明
- 使用 Google 知名类型(`google.protobuf.Empty``google.protobuf.Timestamp`)直接作为 RPC 请求/响应类型(不仅仅是消息字段)。
- goctl 正确将其映射到 Go 类型(`emptypb.Empty``timestamppb.Timestamp`)并生成正确的导入。
- 这与示例 06 不同,示例 06 中知名类型用作消息字段。

View File

@@ -0,0 +1,65 @@
# Example 09: Google Types as RPC Parameters
This example demonstrates using Google protobuf well-known types **directly** as RPC request or response types (not just as message fields).
## Proto Definition
`service.proto` uses `google.protobuf.Empty` and `google.protobuf.Timestamp` directly as RPC request/response types.
The `go_package` uses a full module path:
```protobuf
option go_package = "example.com/demo/pb";
```
## Generation Commands
First, initialize the output directory with a `go.mod`:
```bash
mkdir -p output && cd output && go mod init example.com/demo && cd ..
```
Then generate the code:
```bash
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 .
```
Generated directory structure:
```
output/
├── etc
│ └── healthsvc.yaml
├── go.mod
├── healthservice
│ └── healthservice.go
├── healthsvc.go
├── internal
│ ├── config
│ │ └── config.go
│ ├── logic
│ │ ├── gettimelogic.go
│ │ └── pinglogic.go
│ ├── server
│ │ └── healthserviceserver.go
│ └── svc
│ └── servicecontext.go
└── pb
├── service.pb.go
└── service_grpc.pb.go
```
## Key Points
- Uses Google well-known types (`google.protobuf.Empty`, `google.protobuf.Timestamp`) directly as RPC request/response types (not just message fields).
- goctl correctly maps these to Go types (`emptypb.Empty`, `timestamppb.Timestamp`) and generates proper imports.
- This differs from Example 06 where well-known types are used as message fields.

View File

@@ -0,0 +1,19 @@
syntax = "proto3";
package healthsvc;
option go_package = "example.com/demo/pb";
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
message HealthCheckReq {
string service = 1;
}
service HealthService {
// Ping returns empty — useful for health checks with no response body.
rpc Ping(HealthCheckReq) returns (google.protobuf.Empty);
// GetTime returns a Timestamp directly as the response type.
rpc GetTime(HealthCheckReq) returns (google.protobuf.Timestamp);
}

View File

@@ -0,0 +1,66 @@
# 示例 10流式 RPC
本示例演示 gRPC 的三种流式通信模式:服务端流、客户端流和双向流。
## Proto 定义
`stream.proto` 定义了三个 RPC 方法,演示每种流式模式。
`go_package` 使用完整的模块路径:
```protobuf
option go_package = "example.com/demo/pb";
```
## 生成命令
首先,在输出目录中初始化 `go.mod`
```bash
mkdir -p output && cd output && go mod init example.com/demo && cd ..
```
然后生成代码:
```bash
goctl rpc protoc stream.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 .
```
生成的目录结构:
```
output/
├── etc
│ └── streamsvc.yaml
├── go.mod
├── internal
│ ├── config
│ │ └── config.go
│ ├── logic
│ │ ├── bidistreamlogic.go
│ │ ├── clientstreamlogic.go
│ │ └── serverstreamlogic.go
│ ├── server
│ │ └── streamserviceserver.go
│ └── svc
│ └── servicecontext.go
├── pb
│ ├── stream.pb.go
│ └── stream_grpc.pb.go
├── streamservice
│ └── streamservice.go
└── streamsvc.go
```
## 要点说明
- 支持三种流式模式:服务端流(响应带 `stream`)、客户端流(请求带 `stream`)和双向流(两端都带 `stream`)。
- goctl 为每个流式 RPC 方法生成独立的逻辑文件。
- 流式客户端代码不会自动生成,需直接使用 gRPC 客户端。

View File

@@ -0,0 +1,66 @@
# Example 10: Streaming RPC
This example demonstrates all three gRPC streaming patterns: server streaming, client streaming, and bidirectional streaming.
## Proto Definition
`stream.proto` defines three RPC methods demonstrating each streaming pattern.
The `go_package` uses a full module path:
```protobuf
option go_package = "example.com/demo/pb";
```
## Generation Commands
First, initialize the output directory with a `go.mod`:
```bash
mkdir -p output && cd output && go mod init example.com/demo && cd ..
```
Then generate the code:
```bash
goctl rpc protoc stream.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 .
```
Generated directory structure:
```
output/
├── etc
│ └── streamsvc.yaml
├── go.mod
├── internal
│ ├── config
│ │ └── config.go
│ ├── logic
│ │ ├── bidistreamlogic.go
│ │ ├── clientstreamlogic.go
│ │ └── serverstreamlogic.go
│ ├── server
│ │ └── streamserviceserver.go
│ └── svc
│ └── servicecontext.go
├── pb
│ ├── stream.pb.go
│ └── stream_grpc.pb.go
├── streamservice
│ └── streamservice.go
└── streamsvc.go
```
## Key Points
- Supports three streaming patterns: server streaming (`stream` on response), client streaming (`stream` on request), and bidirectional streaming (`stream` on both).
- goctl generates separate logic files for each streaming RPC method.
- Streaming client code is not auto-generated; use the gRPC client directly.

View File

@@ -0,0 +1,24 @@
syntax = "proto3";
package streamsvc;
option go_package = "example.com/demo/pb";
message StreamReq {
string input = 1;
}
message StreamReply {
string output = 1;
}
service StreamService {
// ServerStream: client sends one request, server returns a stream of responses.
rpc ServerStream(StreamReq) returns (stream StreamReply);
// ClientStream: client sends a stream of requests, server returns one response.
rpc ClientStream(stream StreamReq) returns (StreamReply);
// BidiStream: both client and server send streams of messages.
rpc BidiStream(stream StreamReq) returns (stream StreamReply);
}

View File

@@ -0,0 +1,93 @@
# RPC Examples
This directory contains complete examples for all `goctl rpc` code generation scenarios.
Each example includes:
- `.proto` source files
- `README.md` (English) and `README-cn.md` (中文) documentation
## Examples
| # | Directory | Scenario | Key Flags |
|---|-----------|----------|-----------|
| 01 | [01-basic](01-basic/) | Basic single service, no imports | — |
| 02 | [02-import-sibling](02-import-sibling/) | Import sibling proto file | `--proto_path=.` |
| 03 | [03-import-subdir](03-import-subdir/) | Import proto from subdirectory | `--proto_path=.` |
| 04 | [04-transitive-import](04-transitive-import/) | Transitive imports (A → B → C) | `--proto_path=.` |
| 05 | [05-multiple-services](05-multiple-services/) | Multiple services in one proto | `--multiple` |
| 06 | [06-wellknown-types](06-wellknown-types/) | Google well-known types in messages | `--proto_path=$PROTOC_INCLUDE` |
| 07 | [07-external-proto-same-pkg](07-external-proto-same-pkg/) | External proto, same `go_package` | `-I ./ext_protos` |
| 08 | [08-external-proto-diff-pkg](08-external-proto-diff-pkg/) | External proto, different `go_package` | `-I ./ext_protos` |
| 09 | [09-google-types-as-rpc](09-google-types-as-rpc/) | Google types as RPC parameters | `--proto_path=$PROTOC_INCLUDE` |
| 10 | [10-streaming](10-streaming/) | Server/client/bidirectional streaming | — |
## Prerequisites
- [Go](https://go.dev/) 1.22+
- [protoc](https://github.com/protocolbuffers/protobuf/releases) (Protocol Buffers compiler)
- [protoc-gen-go](https://pkg.go.dev/google.golang.org/protobuf/cmd/protoc-gen-go) and [protoc-gen-go-grpc](https://pkg.go.dev/google.golang.org/grpc/cmd/protoc-gen-go-grpc)
- [goctl](https://github.com/zeromicro/go-zero/tree/master/tools/goctl)
## Quick Start
```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
# Try the basic example
cd 01-basic
mkdir -p output && cd output && go mod init example.com/demo && cd ..
goctl rpc protoc greeter.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 .
```
---
# RPC 示例
本目录包含所有 `goctl rpc` 代码生成场景的完整示例。
每个示例包含:
- `.proto` 源文件
- `README.md`(英文)和 `README-cn.md`(中文)文档
## 示例列表
| # | 目录 | 场景 | 关键标志 |
|---|------|------|---------|
| 01 | [01-basic](01-basic/) | 基础单服务,无导入 | — |
| 02 | [02-import-sibling](02-import-sibling/) | 导入同级 proto 文件 | `--proto_path=.` |
| 03 | [03-import-subdir](03-import-subdir/) | 导入子目录中的 proto | `--proto_path=.` |
| 04 | [04-transitive-import](04-transitive-import/) | 传递性导入A → B → C | `--proto_path=.` |
| 05 | [05-multiple-services](05-multiple-services/) | 单 proto 多服务 | `--multiple` |
| 06 | [06-wellknown-types](06-wellknown-types/) | 消息中使用 Google 标准类型 | `--proto_path=$PROTOC_INCLUDE` |
| 07 | [07-external-proto-same-pkg](07-external-proto-same-pkg/) | 外部 proto相同 `go_package` | `-I ./ext_protos` |
| 08 | [08-external-proto-diff-pkg](08-external-proto-diff-pkg/) | 外部 proto不同 `go_package` | `-I ./ext_protos` |
| 09 | [09-google-types-as-rpc](09-google-types-as-rpc/) | Google 类型作为 RPC 参数 | `--proto_path=$PROTOC_INCLUDE` |
| 10 | [10-streaming](10-streaming/) | 服务端/客户端/双向流 | — |
## 前置条件
- [Go](https://go.dev/) 1.22+
- [protoc](https://github.com/protocolbuffers/protobuf/releases)Protocol Buffers 编译器)
- [protoc-gen-go](https://pkg.go.dev/google.golang.org/protobuf/cmd/protoc-gen-go) 和 [protoc-gen-go-grpc](https://pkg.go.dev/google.golang.org/grpc/cmd/protoc-gen-go-grpc)
- [goctl](https://github.com/zeromicro/go-zero/tree/master/tools/goctl)
## 快速开始
```bash
# 安装 protoc 插件
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
# 试试基础示例
cd 01-basic
mkdir -p output && cd output && go mod init example.com/demo && cd ..
goctl rpc protoc greeter.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 .
```