protocol-buffersgrpcgrpc-goprotobuf-go

Service compiling successfully, but message structs not generating - gRPC/Go


I am using gRPC/protobufs as the protocol to communicate between my client and server, both written in go. I'm able to run the command show below to generate the cards.pb.go (server) and cards_grpc.pb.go (client) files without any problem. The server file is working perfectly, without any issues. The client file, however, does not seem to have access to the message items that I have defined within my cards.proto file. My services, as well as my client code, require the defined message struct in order to call the service methods, but I'm not sure what I'm missing.

Here is the command I'm running:

protoc -I="./protos" \
--go_out=plugins=grpc:./server \
--go-grpc_out=./client \
protos/*.proto 

Here is my project file structure:

|-- client
    |-- protos (generated protobufs for client)
        |-- cards_grpc.pb.go (this compiled successfully, but structs representing my messages cannot be found)
|-- protos (This is where the proto files are defined)
    |-- cards.proto
|-- server
    |-- protos (generated protobufs for server)
        |-- cards.pb.go (this is working perfectly, has compiled services and messages)

Note: I have defined option go_package = "./protos"; in my cards.proto file, which is why the generated files have outputted into */protos/*.pb.go locations


Solution

  • So you are not generating any protobuf related code for the client code here, only gRPC one. In order to generate the structure that you are looking for, use the following command:

    protoc -I./protos        \
      --go_out=./server      \
      --go-grpc_out=./server \
      --go_out=./client      \
      --go-grpc_out=./client \
      protos/*.proto 
    

    The --go_out generates the go code for protobuf and the --go-grpc_out generates the go code for gRPC.

    Another thing, --go_out=plugins=grpc are not supported in go anymore. You should use the --go-grpc_out.

    More recommendations

    I highly recommend to share the proto directory with both the client and the server (if possible), this limits the potential error due to unsynchronised Proto files.

    So you would have something like:

    |-- client
    |-- protos
        |-- cards.proto
        |-- cards_grpc.pb.go
        |-- cards.pb.go
    |-- server
    

    and then both access the files needed.

    Second, if you are working with Go modules, I recommend that you use the go_package as following:

    option go_package = "${YOUR_MODULE}/protos"
    

    and then generate the code like this:

    protoc -Iprotos \
      --go_opt=module=${YOUR_MODULE} --go_out=. \
      --go-grpc_opt=module=${YOUR_MODULE} --go-grpc_out=. \
      protos/*.proto
    

    Notice the . for the --go_out and --go-grpc_out. This maps the root of your project to the module name and this will generate the code inside your protos directory by removing the Module name to the go_package option. Then you will be able to access this generated code in your code like so:

    import (
        pb "${YOUR_MODULE}/protos"
    )
    

    Clarification

    Just to be clear about the go_package, you need to understand one thing: the protobuf package and the go_package are not the same thing, the former defines package only usable in .proto files, the latter defines the package ... inside your go files. An example:

    For Protobuf package

    file1.proto

    //...
    package protos;
    
    message Test {}
    //...
    

    file2.proto

    //...
    //no package definition
    
    message Test2 {
        protos.Test a_test = 1;
    }
    //...
    

    For go_package

    go.mod

    module my_module
    

    file1.proto (at location: ${ROOT}/protos)

    //...
    option go_package = "my_module/protos"
    
    message Test {}
    //...
    

    generation

    protoc -I./protos        \
      --go_out=./server      \
      --go-grpc_out=./server \
      --go_out=./client      \
      --go-grpc_out=./client \
      protos/file1.proto 
    

    main.go

    package main
    
    import (
        pb "my_module/proto"
    )
    
    func main() {
        var test pb.Test;
    }