I'm trying to create a microservice app using grpc gateway, but faced with a small problem. When I try to send request to api, my fields initialize as zero-value. It's the first time when I'm trying grpc gateway so the problem can be kinda stupid.
Here's my request:
{
"amount": 20000,
"bill": 1010,
"email": "aaa@www.com",
"employeeID": 1,
"userID": 1,
"orgID": 1,
"feedback": "good",
"grade": 5,
"isCommissionCompensated": true,
"redirectURL": "https://google.com",
"failRedirectURL": "https://google.com",
"paymentMethod": "CARD"
}
Here's the proto file of grpc gateway
syntax = "proto3";
option go_package = "/paymentProto";
import "google/api/annotations.proto";
package payment;
service PaymentService {
rpc PayIn(PayInRequest) returns(PayInResponse) {
option(google.api.http) = {
post: "/payment/pay_in"
};
}
}
message PayInRequest {
uint64 userID = 1;
uint64 employeeID = 2;
uint64 orgID = 3;
string redirectURL = 4;
string failRedirectURL = 5;
double amount = 6;
string email = 7;
string feedback = 8;
uint32 grade = 9;
bool isCommissionCompensated = 10;
optional double bill = 11;
string paymentMethod = 12;
}
message PayInResponse {
string payInForm = 1;
}
I have a method that initialize my server
func (s *Server) Run() error {
s.MapHandlers()
var eg errgroup.Group
eg.Go(s.RunPaymentGRPC)
eg.Go(s.RunPaymentHTTP)
if err := eg.Wait(); err != nil {
return errors.Wrap(err, "Server.Run")
}
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
logger.Info("Shutting down Payment server...")
s.grpcServer.GracefulStop()
logger.Info("Success!")
return nil
}
And 3 methods that initialize the gateway:
func (s *Server) MapHandlers() {
logger.Info("Trying to map handlers...")
paymentUC := paymentUsecase.NewPaymentUC()
paymentHandlers := paymentDelivery.NewHandlers(paymentUC)
paymentProto.RegisterPaymentServiceServer(s.grpcServer, paymentHandlers)
logger.Info("Success!")
}
func (s *Server) RunPaymentHTTP() error {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
logger.Info("Trying to run http server")
opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
err := paymentProto.RegisterPaymentServiceHandlerFromEndpoint(ctx, s.mux, s.cfg.PaymentServer.Grpc.Host, opts)
if err != nil {
return errors.Wrap(err, "failed to register gRPC gateway")
}
logger.Infof("Serving http on %s", s.cfg.PaymentServer.Http.Host)
if err := http.ListenAndServe(s.cfg.PaymentServer.Http.Host, s.mux); err != nil {
return errors.Wrap(err, "failed to serve")
}
logger.Info("Success!")
return nil
}
func (s *Server) RunPaymentGRPC() error {
lis, err := net.Listen("tcp", s.cfg.PaymentServer.Grpc.Host)
if err != nil {
return errors.Wrapf(err, "failed to listen: %v", s.cfg.PaymentServer.Grpc.Host)
}
logger.Infof("Serving gRPC on %s", s.cfg.PaymentServer.Grpc.Host)
if err := s.grpcServer.Serve(lis); err != nil {
return errors.Wrap(err, "failed to serve gRPC server")
}
return nil
}
And here's the struct that implements my genered proto file code
type PaymentHandlers struct {
paymentUC PaymentUC
paymentProto.UnimplementedPaymentServiceServer
}
func NewHandlers(paymentUC PaymentUC) *PaymentHandlers {
return &PaymentHandlers{
paymentUC: paymentUC,
}
}
func (h *PaymentHandlers) PayIn(
ctx context.Context,
request *paymentProto.PayInRequest,
) (*paymentProto.PayInResponse, error) {
ctx, span := otel.Tracer("api-gateway").Start(ctx, "PaymentHandlers.PayIn")
defer span.End()
return &paymentProto.PayInResponse{
PayInForm: "success",
}, nil
}
And when I try to send request, my genered struct has such fields
What can be the problem? Thank u in advance!
Your service proto is missing the body: "*"
which may be causing the issue. Can you try adding it to see if it fixes the issue?
service PaymentService {
rpc PayIn(PayInRequest) returns(PayInResponse) {
option(google.api.http) = {
post: "/payment/pay_in"
body: "*"
};
}
}
As the google api annotation proto mentions:
Any fields in the request message which are not bound by the path template automatically become HTTP query parameters if there is no HTTP request body.
So I suspect your message is getting zero values for the fields because there are no URL query parameters provided and the body annotation is missing.