# goctl rpc — RPC 코드 생성 [English](README.md) | [中文](README-cn.md) | 한국어 goctl rpc는 `goctl` 스캐폴딩 도구의 RPC 서비스 코드 생성 모듈입니다. `.proto` 파일에서 완전한 zRPC 서비스를 생성합니다. proto 정의와 비즈니스 로직만 작성하면 나머지 보일러플레이트 코드는 모두 자동으로 생성됩니다. ## 기능 - **protoc 호환**: protoc와 완전히 호환되며 모든 protoc 인수를 그대로 전달합니다. - **외부 proto import**: 디렉터리와 패키지를 넘나드는 proto import를 지원하고 전이 의존성을 자동으로 해결합니다. - **다중 서비스**: 하나의 proto 파일에 여러 서비스를 정의하고, 서비스 이름별로 자동 그룹화합니다. - **스트리밍 지원**: 서버 스트리밍, 클라이언트 스트리밍, 양방향 스트리밍을 지원합니다. - **Google well-known types**: 지원되는 `google.protobuf.*` 타입을 자동으로 인식하고 올바른 Go import를 생성합니다. - **클라이언트 생성**: 자동 생성된 RPC 클라이언트 래퍼 코드를 제공합니다. ## 사전 요구 사항 ```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 ``` ## 빠른 시작 ### 방법 1: 즉시 서비스 만들기 ```bash goctl rpc new greeter ``` 완전한 프로젝트 구조가 생성됩니다. ``` 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 ``` ### 방법 2: proto 파일에서 생성하기 1. proto 템플릿을 생성합니다. ```bash goctl rpc template -o=user.proto ``` 2. 출력 디렉터리를 초기화하고 서비스 코드를 생성합니다. ```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 . ``` --- ## 명령 참조 ### `goctl rpc protoc` `.proto` 파일에서 zRPC 서비스 코드를 생성합니다. ```bash goctl rpc protoc [flags] ``` **예시:** ```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 . # 다중 서비스 모드 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 # 외부 proto import 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 # 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 . ``` **플래그:** | 플래그 | 축약 | 타입 | 기본값 | 설명 | |------|-------|------|---------|-------------| | `--zrpc_out` | | string | **필수** | zRPC 서비스 코드 출력 디렉터리 | | `--go_out` | | string | **필수** | protoc Go 코드 출력 디렉터리 | | `--go-grpc_out` | | string | **필수** | protoc gRPC 코드 출력 디렉터리 | | `--go_opt` | | string | | protoc-gen-go 옵션(예: `module=example.com/demo`) | | `--go-grpc_opt` | | string | | protoc-gen-go-grpc 옵션(예: `module=example.com/demo`) | | `--proto_path` | `-I` | string[] | | proto import 검색 디렉터리(반복 지정 가능) | | `--multiple` | `-m` | bool | `false` | 다중 서비스 모드 | | `--client` | `-c` | bool | `true` | RPC 클라이언트 코드 생성 | | `--style` | | string | `gozero` | 파일 이름 스타일 | | `--module` | | string | | 사용자 지정 Go module 이름 | | `--name-from-filename` | | bool | `false` | 서비스 이름에 `package` 이름 대신 파일 이름 사용 | | `--verbose` | `-v` | bool | `false` | 상세 로그 활성화 | | `--home` | | string | | goctl 템플릿 디렉터리 | | `--remote` | | string | | 원격 템플릿 Git 저장소 URL | | `--branch` | | string | | 원격 템플릿 브랜치 | ### `goctl rpc new` 완전한 RPC 서비스 프로젝트를 빠르게 생성합니다. ```bash goctl rpc new [flags] ``` **플래그:** | 플래그 | 축약 | 타입 | 기본값 | 설명 | |------|-------|------|---------|-------------| | `--style` | | string | `gozero` | 파일 이름 스타일 | | `--client` | `-c` | bool | `true` | RPC 클라이언트 코드 생성 | | `--module` | | string | | 사용자 지정 Go module 이름 | | `--verbose` | `-v` | bool | `false` | 상세 로그 활성화 | | `--idea` | | bool | `false` | IDE 프로젝트 마커 생성 | | `--name-from-filename` | | bool | `false` | 서비스 이름에 `package` 이름 대신 파일 이름 사용 | | `--home` | | string | | goctl 템플릿 디렉터리 | | `--remote` | | string | | 원격 템플릿 Git 저장소 URL | | `--branch` | | string | | 원격 템플릿 브랜치 | ### `goctl rpc template` proto 파일 템플릿을 생성합니다. ```bash goctl rpc template -o= [flags] ``` **플래그:** | 플래그 | 타입 | 설명 | |------|------|-------------| | `-o` | string | 출력 파일 경로(필수) | | `--home` | string | goctl 템플릿 디렉터리 | | `--remote` | string | 원격 템플릿 Git 저장소 URL | | `--branch` | string | 원격 템플릿 브랜치 | --- ## 기능 상세 ### 다중 서비스 모드(`--multiple`) proto 파일에 여러 `service` 정의가 포함된 경우 `--multiple` 플래그가 필요합니다. ```protobuf service SearchService { rpc Search(SearchReq) returns (SearchReply); } service NotifyService { rpc Notify(NotifyReq) returns (NotifyReply); } ``` **`--multiple` 사용 시 디렉터리 차이:** | 기능 | 기본 모드 | `--multiple` 모드 | |---------|-------------|-------------------| | proto당 서비스 수 | 정확히 1개 | 1개 이상 | | 클라이언트 디렉터리 | 서비스 이름 기반 | 고정 `client/` 디렉터리 | | 코드 구성 | 평면 구조 | 서비스 이름별 그룹화 | **`--multiple=false`(기본값) 디렉터리 구조:** ``` output/ ├── greeterclient/ │ └── greeter.go ├── internal/ │ ├── logic/ │ │ └── sayhellologic.go │ └── server/ │ └── greeterserver.go └── ... ``` **`--multiple=true` 디렉터리 구조:** ``` output/ ├── client/ │ ├── searchservice/ │ │ └── searchservice.go │ └── notifyservice/ │ └── notifyservice.go ├── internal/ │ ├── logic/ │ │ ├── searchservice/ │ │ │ └── searchlogic.go │ │ └── notifyservice/ │ │ └── notifylogic.go │ └── server/ │ ├── searchservice/ │ │ └── searchserviceserver.go │ └── notifyservice/ │ └── notifyserviceserver.go └── ... ``` ### 외부 proto import(`--proto_path`) `-I` / `--proto_path`로 추가 proto 검색 디렉터리를 지정합니다. 지원되는 시나리오는 다음과 같습니다. - **같은 디렉터리 import**: `import "types.proto";` - **하위 디렉터리 import**: `import "common/types.proto";` - **외부 디렉터리 import**: 프로젝트 외부에 있는 proto 파일 - **전이 import**: A가 B를 import하고 B가 C를 import하는 경우 — goctl이 재귀적으로 해결합니다. - **패키지 간 import**: 서로 다른 `go_package` 값을 가진 파일에 대해 올바른 Go import를 자동으로 생성합니다. ```bash # 여러 디렉터리에서 proto 파일 검색 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 ``` ### 서비스 이름 지정 기본적으로 서비스 이름은 proto의 **`package` 이름**에서 파생됩니다(예: `package user;` → 서비스 이름 `user`). 이를 통해 여러 proto 파일이 같은 `package`를 공유할 수 있습니다. ``` protos/ ├── user_base.proto # package user; ├── user_auth.proto # package user; └── user_profile.proto # package user; ``` 세 파일은 모두 하나의 `user` 서비스로 생성됩니다. 서비스 이름에 proto 파일 이름을 사용하려면(레거시 동작) `--name-from-filename` 플래그를 추가하세요. ### 스트리밍 RPC 세 가지 gRPC 스트리밍 패턴을 모두 지원합니다. ```protobuf service StreamService { rpc ServerStream(Req) returns (stream Reply); // 서버 스트리밍 rpc ClientStream(stream Req) returns (Reply); // 클라이언트 스트리밍 rpc BidiStream(stream Req) returns (stream Reply); // 양방향 스트리밍 } ``` ### Google well-known types goctl은 지원되는 Google protobuf well-known types를 자동으로 인식하고 처리합니다. | Proto 타입 | Go 타입 | |-----------|---------| | `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` | 이 타입들은 RPC 파라미터 타입으로 직접 사용할 수 있으며, goctl이 올바른 import를 자동으로 생성합니다. --- ## 예제 모든 생성 시나리오를 다루는 10개의 완전한 예제는 [example/](example/) 디렉터리를 참고하세요. | # | 예제 | 시나리오 | |---|---------|----------| | 01 | [기본 서비스](example/01-basic/) | 단일 서비스, import 없음 | | 02 | [동일 디렉터리 import](example/02-import-sibling/) | 같은 디렉터리에서 import | | 03 | [하위 디렉터리 import](example/03-import-subdir/) | 하위 디렉터리에서 import | | 04 | [전이 import](example/04-transitive-import/) | A → B → C 의존성 체인 | | 05 | [다중 서비스](example/05-multiple-services/) | `--multiple` 모드 | | 06 | [Google well-known types](example/06-wellknown-types/) | 메시지에서 Timestamp 등 사용 | | 07 | [외부 proto(동일 패키지)](example/07-external-proto-same-pkg/) | 외부 proto, 같은 go_package | | 08 | [외부 proto(다른 패키지)](example/08-external-proto-diff-pkg/) | 외부 proto, 다른 go_package | | 09 | [Google well-known types를 파라미터로 사용](example/09-google-types-as-rpc/) | Empty/Timestamp를 RPC 파라미터로 사용 | | 10 | [스트리밍](example/10-streaming/) | 서버/클라이언트/양방향 스트리밍 |