Проблема сериализации в шлюзе grpc (go)

Я пытаюсь создать приложение для микросервиса, используя шлюз grpc, но столкнулся с небольшой проблемой. Когда я пытаюсь отправить запрос в API, мои поля инициализируются как нулевое значение. Я впервые пробую шлюз grpc, так что проблема может быть довольно глупой.

Вот мой запрос:

{
    "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"
}

Вот прототип файла шлюза grpc

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;
}

У меня есть метод, который инициализирует мой сервер

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
}

И 3 метода, инициализирующих шлюз:

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
}

И вот структура, которая реализует мой сгенерированный код прото-файла

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
}

И когда я пытаюсь отправить запрос, в моей сгенерированной структуре есть такие поля

В чем может быть проблема? Заранее спасибо!

Пожалуйста, уточните «мои поля инициализируются как нулевое значение». Вы используете термин «шлюз». Могу ли я предположить, что вы не имеете в виду grpc-шлюз? Как именно вы вызываете службу?

DazWilkin 29.05.2024 17:32

Ну, я отправляю http-запрос на свой сервис через почтальона. «Пожалуйста, уточните «мои поля инициализируются как нулевое значение»» — ну, вы можете видеть это на моем скриншоте. Структура имеет поля с нулевым значением.

Cross 29.05.2024 17:52

Можете ли вы попробовать добавить строку body: "*" в прототип службы и убедиться, что ваша проблема решена? ``` service PaymentService { rpc PayIn(PayInRequest) return(PayInResponse) { option(google.api.http) = { post: "/paid/pay_in" body: "*" }; } } ```

Arjan Singh Bal 11.06.2024 19:20
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
4
3
80
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В вашем прототипе сервиса отсутствует body: "*", что может быть причиной проблемы. Можете ли вы попробовать добавить его и посмотреть, решит ли это проблему?

service PaymentService {
    rpc PayIn(PayInRequest) returns(PayInResponse) {
        option(google.api.http) = {
            post: "/payment/pay_in"
            body: "*"
        };
    }
}

Как упоминается в прототипе аннотации Google API:

Любые поля в сообщении запроса, которые не связаны шаблоном пути, автоматически становятся параметрами HTTP-запроса, если нет тела HTTP-запроса.

Поэтому я подозреваю, что ваше сообщение получает нулевые значения для полей, поскольку не указаны параметры запроса URL-адреса и отсутствует аннотация тела.

Другие вопросы по теме