grpc-node icon indicating copy to clipboard operation
grpc-node copied to clipboard

if the message has an optional field with a return value, the proto will attach a same name field with `_` prefix. why?

Open wang-xiaowu opened this issue 1 year ago • 4 comments

Problem description

if the message has an option field with a return value, the proto will attach a same name field with _ prefix. why?

Reproduction steps

  • message like this
message Res {
    uint32 code = 1;
    optional string msg = 2;
    string status = 3;
    optional string error = 4;
    optional uint32 count = 5;
}
  • server retun image

  • real result client got image

Environment

  • OS name, version and architecture: windows11
  • Node version : 16.15
  • Node installation method. binary
  • If applicable, compiler version [e.g. clang 3.8.0-2ubuntu4]
  • Package name and version: 1.10.8

Additional context

wang-xiaowu avatar May 22 '24 09:05 wang-xiaowu

This is controlled by the message decoding code on the client. What protobuf implementation are you using on the client?

murgatroid99 avatar May 22 '24 16:05 murgatroid99

proto3 with @grpc/proto-loader. this is protoLoaderOptions,

const protoLoaderOptions = {
  keepCase: true,
  longs: String,
  enums: String,
  defaults: true,
  oneofs: true,
};

wang-xiaowu avatar May 23 '24 04:05 wang-xiaowu

We got bit by this in our application recently where we were passing the response from a gRPC response through camelcase-keys, where when we got something like { msg: 'foo', _msg: 'msg' }, the camelcase version was { msg: 'msg' }.

While we can modify our usage of camelcase-keys, it'd be nice if the loader could just not have these _ fields as we don't view them as useful at all.

For reference, we're also using @grpc/proto-loader with the same settings as above.

MasterOdin avatar Oct 28 '24 16:10 MasterOdin

OK, I see what's happening here: Protobuf.js internally represents optional fields as a single-member oneof group named as the underscore-prefixed field name. The plain object message representation includes the oneof group as a separate key to indicate which member is set because you set the oneofs option to true.

You can disable this behavior by setting the oneofs option to false.

This behavior can only be changed in Protobuf.js, so I have filed an issue there: https://github.com/protobufjs/protobuf.js/issues/2037.

murgatroid99 avatar Oct 28 '24 22:10 murgatroid99