Skip to content

[protoc-gen-tonic] Support tonic-build generate_default_stubs option #144

Description

@fivetran-auslacroix

Summary

Feature request.

tonic-build 0.14 exposes CodeGenBuilder::generate_default_stubs, but protoc-gen-tonic does not accept or forward the equivalent plugin option.

This is useful when a service implementation should be able to override only selected RPCs while the generated trait supplies UNIMPLEMENTED defaults for the rest.

Tested with protoc-gen-tonic 0.5.0 built from current main at 3e44d8a, using protoc 36.0.

Reproduction

service.proto:

syntax = "proto3";
package example;

message PingRequest {}
message PingResponse {}

service PingService {
  rpc Ping(PingRequest) returns (PingResponse);
}

With protoc-gen-tonic on PATH:

mkdir out
protoc -I . service.proto \
  --tonic_out=out \
  --tonic_opt=no_include,generate_default_stubs=true

no_include keeps this standalone Tonic invocation from requiring a Prost insertion target.

Actual behavior

Generation fails with exit code 1:

--tonic_out: invalid parameter: generate_default_stubs=true

Expected behavior

generate_default_stubs (bare or =true) should be accepted and forwarded to tonic_build::CodeGenBuilder::generate_default_stubs. Omitting it, or setting it to false, should preserve the current required-method behavior.

Proposed patch

I compiled this patch and reran the reproduction. Generation succeeded, and the server trait's ping method had a default body returning tonic::Status::unimplemented("Not yet implemented").

Patch against current main
diff --git a/protoc-gen-tonic/README.md b/protoc-gen-tonic/README.md
index 5dd1b56..8416ec8 100644
--- a/protoc-gen-tonic/README.md
+++ b/protoc-gen-tonic/README.md
@@ -44,6 +44,8 @@ see the related documentation from `tonic-build`:
 
 In addition, the following options can also be specified:
 
+* `generate_default_stubs(=<boolean>)`: Generates default server method stubs
+  that return an unimplemented gRPC status
 * `no_server(=<boolean>)`: Disables generation of the server modules
 * `no_client(=<boolean>)`: Disables generation of the client modules
 * `no_transport(=<boolean>)`: Disables generation of connect method using `tonic::transport::Channel`
diff --git a/protoc-gen-tonic/src/generator.rs b/protoc-gen-tonic/src/generator.rs
index 6eefc8b..7938171 100644
--- a/protoc-gen-tonic/src/generator.rs
+++ b/protoc-gen-tonic/src/generator.rs
@@ -13,6 +13,7 @@ use crate::{resolver::Resolver, util};
 pub(crate) struct TonicGenerator {
     pub(crate) resolver: Resolver,
     pub(crate) generate_server: bool,
+    pub(crate) generate_default_stubs: bool,
     pub(crate) generate_client: bool,
     pub(crate) generate_transport: bool,
     pub(crate) server_attributes: Attributes,
@@ -161,6 +162,7 @@ impl TonicGenerator {
                                 .build_transport(self.generate_transport)
                                 .compile_well_known_types(self.resolver.compile_well_known_types())
                                 .attributes(self.server_attributes.clone())
+                                .generate_default_stubs(self.generate_default_stubs)
                                 .generate_server(&service, PROTO_PATH)
                         });
 
diff --git a/protoc-gen-tonic/src/lib.rs b/protoc-gen-tonic/src/lib.rs
index 9b3574c..a754890 100644
--- a/protoc-gen-tonic/src/lib.rs
+++ b/protoc-gen-tonic/src/lib.rs
@@ -30,6 +30,7 @@ pub fn execute(raw_request: &[u8]) -> protoc_gen_prost::Result {
     let mut generator = TonicGenerator {
         resolver,
         generate_server: !params.no_server,
+        generate_default_stubs: params.generate_default_stubs,
         generate_client: !params.no_client,
         generate_transport: !params.no_transport,
         server_attributes: params.server_attributes,
@@ -54,6 +55,7 @@ struct Parameters {
     client_attributes: Attributes,
     compile_well_known_types: bool,
     disable_package_emission: bool,
+    generate_default_stubs: bool,
     no_server: bool,
     no_client: bool,
     no_transport: bool,
@@ -101,6 +103,17 @@ impl str::FromStr for Parameters {
                     param: "disable_package_emission",
                     value: "false",
                 } => (),
+                Param::Parameter {
+                    param: "generate_default_stubs",
+                }
+                | Param::Value {
+                    param: "generate_default_stubs",
+                    value: "true",
+                } => ret_val.generate_default_stubs = true,
+                Param::Value {
+                    param: "generate_default_stubs",
+                    value: "false",
+                } => (),
                 Param::Parameter { param: "no_server" }
                 | Param::Value {
                     param: "no_server",

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions