diff --git a/transport/grpc/client.go b/transport/grpc/client.go index acc3189..533c8e2 100644 --- a/transport/grpc/client.go +++ b/transport/grpc/client.go @@ -2,6 +2,7 @@ import ( "fmt" + "reflect" "golang.org/x/net/context" "google.golang.org/grpc" @@ -18,7 +19,7 @@ method string enc EncodeRequestFunc dec DecodeResponseFunc - grpcReply interface{} + grpcReply reflect.Type before []RequestFunc } @@ -33,12 +34,20 @@ options ...ClientOption, ) *Client { c := &Client{ - client: cc, - method: fmt.Sprintf("/pb.%s/%s", serviceName, method), - enc: enc, - dec: dec, - grpcReply: grpcReply, - before: []RequestFunc{}, + client: cc, + method: fmt.Sprintf("/pb.%s/%s", serviceName, method), + enc: enc, + dec: dec, + // We are using reflect.Indirect here to allow both reply structs and + // pointers to these reply structs. New consumers of the client should + // use structs directly, while existing consumers will not break if they + // remain to use pointers to structs. + grpcReply: reflect.TypeOf( + reflect.Indirect( + reflect.ValueOf(grpcReply), + ).Interface(), + ), + before: []RequestFunc{}, } for _, option := range options { option(c) @@ -73,11 +82,12 @@ } ctx = metadata.NewContext(ctx, *md) - if err = grpc.Invoke(ctx, c.method, req, c.grpcReply, c.client); err != nil { + grpcReply := reflect.New(c.grpcReply).Interface() + if err = grpc.Invoke(ctx, c.method, req, grpcReply, c.client); err != nil { return nil, fmt.Errorf("Invoke: %v", err) } - response, err := c.dec(ctx, c.grpcReply) + response, err := c.dec(ctx, grpcReply) if err != nil { return nil, fmt.Errorf("Decode: %v", err) }