0

golang and grpc newcomer here. I'm having issues with getting started with protobufs and grpc in golang. I'm assuming I made some stupid mistake somewhere. Here is some background information.

  • $GOPATH\bin is in my $PATH
  • I've installed the protoc-gen-go and protoc-gen-go-grpc plugins
  • My go_package value and is to a public git repo.

I'm simply trying to replicate what is in the youtube titled video 13 Introduction to gRPC and Protocol Buffers by a gentleman named Nic Jackson and generate some go code from a .proto file.

Here is the code for currency.proto

syntax = "proto3";

option go_package = "github.com/<my_github>/go-modules;go-modules";

service Currency {
    rpc GetRate(RateRequest) returns (RateResponse);
}

message RateRequest {
    string Base = 1;
    string Destination = 2;
}


message RateResponse{
    float Rate = 1;
}

Not sure if this has any effect but my go.mod content is the following

module github.com/<my_github>/go-modules

go 1.15

The directory structure for the project is

protos (root folder)
------server (folder)
------------currency.go
------currency.proto
------currency (folder)
------go.mod

I use the following command to generate the go code. The command is executed one directory above the protos directory.

protoc -I protos\ protos\currency.proto --go-grpc_out=.\protos\currency

and I receive the following error three times

2021/01/13 20:52:28 WARNING: Malformed 'go_package' option in "currency.proto", please specify:
        option go_package = "github.com/<my_github>/go-modules;go_modules";
A future release of protoc-gen-go will reject this.
See https://developers.google.com/protocol-buffers/docs/reference/go-generated#package for more information.

Despite the error, a file named currency_grpc.pb.go is generated and nested in 3 new folders that were created under the currency folder. The layout is now

currency
------ github.com
------------<my_github>
------------------go-modules
------------------------currency_grpc.pb.go

The contents of currency_grpc.pb.go are nothing like what is displayed in the video (12:15 mark). There are no types for RateRequest or RateResponse created thus breaking the code.

I've been fussing with this for a few days now and would appreciate any help that comes my way. I've read countless SO posts and github issues but haven't been able to piece things together. Happy to provide more info if needed as well.

Thanks

EDIT: 100 lines of generated go code I left out before.

// Code generated by protoc-gen-go-grpc. DO NOT EDIT.

package go_modules

import (
    context "context"
    grpc "google.golang.org/grpc"
    codes "google.golang.org/grpc/codes"
    status "google.golang.org/grpc/status"
)

// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion7

// CurrencyClient is the client API for Currency service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type CurrencyClient interface {
    GetRate(ctx context.Context, in *RateRequest, opts ...grpc.CallOption) (*RateResponse, error)
}

type currencyClient struct {
    cc grpc.ClientConnInterface
}

func NewCurrencyClient(cc grpc.ClientConnInterface) CurrencyClient {
    return &currencyClient{cc}
}

func (c *currencyClient) GetRate(ctx context.Context, in *RateRequest, opts ...grpc.CallOption) (*RateResponse, error) {
    out := new(RateResponse)
    err := c.cc.Invoke(ctx, "/Currency/GetRate", in, out, opts...)
    if err != nil {
        return nil, err
    }
    return out, nil
}

// CurrencyServer is the server API for Currency service.
// All implementations must embed UnimplementedCurrencyServer
// for forward compatibility
type CurrencyServer interface {
    GetRate(context.Context, *RateRequest) (*RateResponse, error)
    mustEmbedUnimplementedCurrencyServer()
}

// UnimplementedCurrencyServer must be embedded to have forward compatible implementations.
type UnimplementedCurrencyServer struct {
}

func (UnimplementedCurrencyServer) GetRate(context.Context, *RateRequest) (*RateResponse, error) {
    return nil, status.Errorf(codes.Unimplemented, "method GetRate not implemented")
}
func (UnimplementedCurrencyServer) mustEmbedUnimplementedCurrencyServer() {}

// UnsafeCurrencyServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to CurrencyServer will
// result in compilation errors.
type UnsafeCurrencyServer interface {
    mustEmbedUnimplementedCurrencyServer()
}

func RegisterCurrencyServer(s grpc.ServiceRegistrar, srv CurrencyServer) {
    s.RegisterService(&Currency_ServiceDesc, srv)
}

func _Currency_GetRate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
    in := new(RateRequest)
    if err := dec(in); err != nil {
        return nil, err
    }
    if interceptor == nil {
        return srv.(CurrencyServer).GetRate(ctx, in)
    }
    info := &grpc.UnaryServerInfo{
        Server:     srv,
        FullMethod: "/Currency/GetRate",
    }
    handler := func(ctx context.Context, req interface{}) (interface{}, error) {
        return srv.(CurrencyServer).GetRate(ctx, req.(*RateRequest))
    }
    return interceptor(ctx, in, info, handler)
}

// Currency_ServiceDesc is the grpc.ServiceDesc for Currency service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Currency_ServiceDesc = grpc.ServiceDesc{
    ServiceName: "Currency",
    HandlerType: (*CurrencyServer)(nil),
    Methods: []grpc.MethodDesc{
        {
            MethodName: "GetRate",
            Handler:    _Currency_GetRate_Handler,
        },
    },
    Streams:  []grpc.StreamDesc{},
    Metadata: "currency.proto",
}
UCProgrammer
  • 517
  • 7
  • 21
  • Why do you have a semicolon in go_package? (try `option go_package = "github.com//go-modules";`). The video is using the [old protobuf package](https://github.com/golang/protobuf); the [new one](https://pkg.go.dev/google.golang.org/protobuf) will generate two files (one for the protobuf and the other for grpc; I suspect the issue with `go_package` means the files are being written to different locations so you are only seeing the grpc one). – Brits Jan 14 '21 at 04:55
  • @Brits I had put the semicolon and what followed in the go_package value due to this same error message and another stackoverflow post that recommended putting it in. Clearly it didn't solve the issue. – UCProgrammer Jan 15 '21 at 02:08
  • OK - using the semi column is [valid syntax but discouraged](https://developers.google.com/protocol-buffers/docs/reference/go-generated#package). The warning will be due to the `-` in the package name. I would suggest starting with the [quickstart](https://grpc.io/docs/languages/go/quickstart/) because there have been significant changes to go GRPC recently (release of [google.golang.org/protobuf](https://pkg.go.dev/google.golang.org/protobuf)). – Brits Jan 15 '21 at 03:38

1 Answers1

-1

Using protos as the root folder is not a good approach. I suggest that you create a proto folder only for the .proto file. Then run the command as below to generate the go file within the same proto folder:

protoc proto/currency.proto --go_out=plugins=grpc:.

I have written a blog post on a Golang gRPC Microservice with simple steps and working code in GitHub. You can use the project folder structure that I have used in this as a reference. Here is the link to my blog post: http://softwaredevelopercentral.blogspot.com/2021/03/golang-grpc-microservice.html