Protobuf: proto-контракты, типы, эволюция схем

↑ 5.2 gRPC · ← Предыдущая · → Следующая

Обязательно~3 мин чтенияУровень: middle

Зачем это на собесе

Как менять контракт gRPC/Kafka, не ломая клиентов: номера полей, reserved, обратная совместимость.

Объяснение

syntax = "proto3";
option csharp_namespace = "Orders.Contracts";
 
service OrderService {
  rpc GetOrder (GetOrderRequest) returns (OrderReply);
  rpc Watch (WatchRequest) returns (stream OrderEvent);
}
 
message GetOrderRequest { string id = 1; }
 
message OrderReply {
  string id = 1;
  string customer = 2;
  repeated Item items = 3;
  google.protobuf.Timestamp created_at = 4;
  Status status = 5;
  reserved 6, 7;             // удалённые поля
  reserved "old_name";
}
 
enum Status { STATUS_UNSPECIFIED = 0; NEW = 1; PAID = 2; }
Тип protoC#
int32/int64, uint32int, long, uint
double, float, bool, string, bytesодноимённые / ByteString
repeated TRepeatedField<T>
map<K,V>MapField<K,V>
google.protobuf.Timestamp/DurationTimestamp, Duration (конвертация в DateTime)
oneofвзаимоисключающие поля
optionalразличает «не задано» и значение по умолчанию

Эволюция схемы

Безопасно: добавлять новые поля с новыми номерами, добавлять значения enum, менять имена полей (по сети идут номера). Опасно: менять номер или тип поля, переиспользовать удалённый номер, менять repeated/скаляр. Удаляя поле, помечайте его reserved.

Нюансы и подводные камни

  • В proto3 у скаляров нет null: значение по умолчанию (0, "", false) неотличимо от «не задано» без optional.
  • Первое значение enum должно быть 0 (UNSPECIFIED).
  • Деньги не храните в double: string/int64 в минимальных единицах или Money-сообщение.
  • Ошибки контракта лучше ловить проверками совместимости (buf breaking).

Практика

  1. Опишите контракт заказов и сгенерируйте C#-код.
  2. Добавьте поле, затем удалите его с reserved, проверьте совместимость buf breaking.
  3. Используйте oneof для разных способов оплаты.

Вопросы с ответами

Связанные темы