外部と内部では異なる定義ファイルを使用すること
例えば BFF(backend for frontend) と InternalAPI のような構成の場合に、同じ定義ファイルを参照していると時間の経過とともに問題が出てきます。
BFF に影響の出ないよう InternalAPI の変更をしたい場合など、同一のメッセージを参照していると困難です。
こうならないよう、レイヤー構造のように別々のメッセージ定義をしておくことを推奨します。
例外は次のとおりです。
- proto フィールドが google.type や google.protobuf のような一般的な型である
- サービスのパフォーマンスが極めて重要な場合
- 柔軟性を犠牲にして実行速度を上げる価値があるかもしれません
- サービスが数百万 QPS でミリ秒単位のレイテンシを求めるような場合においては
更新は完全な置換ではなく、部分的な更新または追加のみの更新をサポートすること
例えば以下のようなメッセージにフィールド追加したい場合に、
クライアントが追加フィールドを保持しない旧versionのメッセージ定義を利用する場合、追加のフィールドを取得できずラウンドトリップでデータが失われます。
message User {
string id = 1;
string name = 2;
// string address = 3; <- 追加したい項目
}
Fix #1: 更新用のフィールドマスクを使用する
クライアントが変更したいフィールドを渡し、そのフィールドだけを 更新リクエストに含めるようにする。
サーバーは他のフィールドはそのままにしておき、マスクで指定されたフィールドだけを更新します。
一般的に、マスクの構造はレスポンスのメッセージ定義の構造を反映したものであるべきです。
つまり、FooがBarを含んでいれば、FooMaskはBarMaskを含んでいます。
フィールドマスクの利用については、ただ有ればよいというものではなく注意点なども多いのでよく理解してから定義したほうがよい。
Fix #2: 個々のフィールドに限定した、より狭い範囲の API を定義する
例でいうと UpdateUser() にフィールド追加するのではなく、新たに UpdateUserAddress() を定義しようということ。
あまりに数が増えるとメンテナンスコストや認知負荷も高まるので程々に。