gprc ruby で、UInt64Value タイプのフィールドにnilを設定する時に以下のミスをしてた。
再現手順
syntax = "proto3";
package myapp.post;
option ruby_package = "PostPb";
import "google/protobuf/wrappers.proto";
message GetLatestPostIdRequest {
uint64 user_id = 1;
}
message GetLatestPostIdResponse {
google.protobuf.UInt64Value post_id = 1; /// 注目!
}
このprotoを使用して生成したgrpc rubyサーバーにおいて、post_idにnullを設定したいときに前者の方法で設定してしまっていた。
case1 post_id = nil
を与える場合
以下。Google::Protobuf::UInt64Value.new
の出番はない。
### 間違った使用法
> MyApp::PostPb::GetLatestPostIdResponse.new(post_id: Google::Protobuf::UInt64Value.new(value: nil))
=> <MyApp::PostPb::GetLatestPostIdResponse: post_id: <Google::Protobuf::UInt64Value: value: 0>>
> MyAapp::PostPb::GetLatestPostIdResponse.new(post_id: Google::Protobuf::UInt64Value.new(value: nil)).post_id
=> <Google::Protobuf::UInt64Value: value: 0>
### 正しい使用法
> MyApp::PostPb::GetLatestPostIdResponse.new(post_id: nil)
=> <MyApp::PostPb::GetLatestPostIdResponse: >
> MyApp::PostPb::GetLatestPostIdResponse.new(post_id: nil).post_id
=> nil
### 正しい使用法2 (そもそも{post_id: nil}を初期時の引数に与えなくてもよい)
> MyApp::PostPb::GetLatestPostIdResponse.new()
=> <MyApp::PostPb::GetLatestPostIdResponse: >
> MyApp::PostPb::GetLatestPostIdResponse.new().post_id
=> nil
case2 post_id != nil
を与える場合
以下。Google::Protobuf::UInt64Value.new
を使わないといけない。
### 間違った使用法
> MyApp::PostPb::GetLatestPostIdResponse.new(post_id: 909)
"Google::Protobuf::TypeError: Invalid type Integer to assign to submessage field 'story_id'."
"from (pry):8:in `initialize'"
### 正しい使用法
> MyApp::PostPb::GetLatestPostIdResponse.new(Google::Protobuf::UInt64Value.new(value: 909))
> MyApp::PostPb::GetLatestPostIdResponse.new(Google::Protobuf::UInt64Value.new(value: 909)).post_id
=> <Google::Protobuf::UInt64Value: value: 909>
> MyApp::PostPb::GetLatestPostIdResponse.new(Google::Protobuf::UInt64Value.new(value: 909)).post_id
=> 909
注意点
初期化時にnilの値を詰めるかどうかで条件分岐が必要っぽい。また、上記の挙動により、grpc client側のコードで、story_idを取り出す場合には、ぼっち演算子を使うことが必要になる。
story_id = responst_object.story_id&.value