Расширьте функции, сгенерированные grpc-gateway, с помощью специальной логики декодирования в proto.Message

В ходе работы возникла необходимость выполнить strings.TrimSpace на всех полях с типом protobufstring

В результате было решено написать плагин, генерирующий необходимые функции для каждой структуры: trimAll (для создания функции обрезки полей типа string) и UnmarshalJSON (мы думали, что это функция, используемая grpc-gateway для перевода из http.Request.Body в proto.Message).

func (m *GetLogbookCall_Request) trimAll() {
    if m == nil {
        return
    }
    m.Id = strings.TrimSpace(m.Id)
}

func (m *GetLogbookCall_Request) UnmarshalJSON(data []byte) error {
    err := proto.Unmarshal(data, m)
    if err != nil {
        return err
    }

    m.trimAll()

    return nil
}

Но в результате ничего не получилось)

Вопрос в следующем: есть ли способ добавить собственную логику при переводе http.Request.Body в proto.Message?

ПС:

Вот функции, созданные плагином grpc-gateway.

func request_AccountService_UpdatePassword_0(ctx context.Context, marshaler runtime.Marshaler, client AccountServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
    var protoReq account.UpdatePasswordCall_Request
    var metadata runtime.ServerMetadata

    if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
        return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
    }

    msg, err := client.UpdatePassword(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
    return msg, metadata, err

}

Меня совершенно сбивало с толку, когда я получал обрезанные строки в JSON API, но разные ответы от вызовов gRPC. Это, казалось бы, «необходимость», указывает на более серьезные проблемы в архитектуре.

eik 09.06.2024 13:08
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
1
1
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Я нашел решение своей проблемы. Вы можете написать собственный маршалер, а затем использовать его для создания прокси-сервера.

type Marshaler struct {
    runtime.JSONPb
}

func (m *Marshaler) NewDecoder(r io.Reader) runtime.Decoder {
    d := json.NewDecoder(r)
    return Decoder{
        decoder: &runtime.DecoderWrapper{
            Decoder:          d,
            UnmarshalOptions: m.UnmarshalOptions,
        },
    }
}

type Decoder struct {
    decoder *runtime.DecoderWrapper
}

func (d Decoder) Decode(v interface{}) error {
    err := d.decoder.Decode(v)
    if err != nil {
        return err
    }
    
    // Write your own custom logic here. In my case it's use TrimAll method

    type Trimmable interface {
        TrimAll()
    }

    if v, ok := v.(Trimmable); ok {
        v.TrimAll()
    }

    return nil
}

    mux := runtime.NewServeMux(
        runtime.WithMetadata(func(ctx context.Context, r *http.Request) metadata.MD {
        runtime.WithMarshalerOption(runtime.MIMEWildcard, &Marshaler{
            runtime.JSONPb{
                MarshalOptions: protojson.MarshalOptions{
                    EmitUnpopulated: true,
                },
            },
        }),
    )

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