Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serialization problem in grpc gateway(go)

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": "[email protected]",
    "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 fieldsenter image description here

What can be the problem? Thank u in advance!

like image 508
Cross Avatar asked Feb 01 '26 08:02

Cross


1 Answers

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.

like image 123
Arjan Singh Bal Avatar answered Feb 04 '26 01:02

Arjan Singh Bal