gRPCでの更新の際、クライアントからEntity情報をサーバーに渡すが、不要なフィールドは更新しないようにしたい
例えば、以下のようなデータのemail
だけ更新したい場合
{ "user": { "id": "001", "name": "uga", "email": "uga@gmail.com" } }
gRPCでは Protobuf FieldMask
という機能を使ってフィルタリングできる
方法
まず、protoファイル内のUpdateメソッドのリクエストにgoogle.protobuf.FieldMask
フィールドを追加する
... import "google/protobuf/field_mask.proto"; ... message UpdateUserRequest { User user = 1; google.protobuf.FieldMask update_mask = 2; } message UpdateUserReply { User user = 1; }
次に、server側では以下のようにする
... updateUserReply { val responseUser = User.newBuilder() .setId(request.user.id) .setName(request.user.name) .setEmail(request.user.email).build() var userWithMaskedFields = User.newBuilder() FieldMaskUtil.merge( request.updateMask, responseUser, userWithMaskedFields ) var updateUser = userWithMaskedFields.build() // 更新処理 user = updateUser }
この時、FieldMaskUtil.merge(FieldMask, User, User.builder)
を使って必要最低限のデータにフィルタする
最後に、client側で更新するEntityと一緒に、FieldMaskも送信するようにする
val fieldMask = FieldMask.newBuilder().addPaths("email").build() val request = updateUserRequest { this.user = user; // emailを"uga2@gmail.com"に更新したUserエンティティ this.updateMask = fieldMask } val response = stub.sayHello(request) println("Received: ${response.user}") // Received: email: "uga2@gmail.com"
これで、不要なフィールドは更新しないようにすることができた