.proto - источник правды о сообщениях и методах. В отличие от JSON, на провод уходят номера полей, а не имена. Поэтому совместимость начинается с дисциплины контракта.
Базовая структура
syntax = "proto3";
package orders.v1;
message GetOrderRequest {
string id = 1;
}
message Order {
string id = 1;
string status = 2;
int64 amount_minor = 3;
string currency = 4;
}
amount_minor хранит копейки или центы, а не дробную сумму. Номер после = нельзя переиспользовать: по нему клиент читает данные.
optional и присутствие
В proto3 обычное поле не отличает «не прислали» от значения по умолчанию. Для частичного обновления это важно:
message UpdateOrderRequest {
string id = 1;
optional string status = 2;
}
optional добавляет отслеживание присутствия. Без него сервер может принять пустой статус за настоящий.
repeated, map и oneof
repeated описывает список, map - пары ключ-значение. oneof означает одно значение из нескольких вариантов:
message Payment {
oneof method {
string card_token = 1;
string bank_account = 2;
}
}
oneof проверяет активный вариант, а не заполняет все поля сразу.
enum
Значение enum передаётся числом. Его нельзя переименовывать: новый клиент может присвоить другое смысловое значение старому числу. Добавлять новые значения безопаснее, чем менять старые.
Удалённые поля и номера помечают reserved, чтобы никто не занял их снова.
Как это выглядит в Go
Для optional генератор создаёт указатель: nil означает «поле не прислали», а указатель на пустую строку - «прислали пустое». Поэтому обновление начинается с проверки указателя, а не сравнения со значением по умолчанию.
oneof тоже имеет активный вариант: сначала определяют его через сгенерированный switch, затем читают только это поле. Нельзя бездумно заполнять все варианты сразу - контракт перестанет быть однозначным.
Неизвестное значение enum не обязано быть ошибкой десериализации. Если клиент и сервер разных версий, на стороне приложения нужен явный default: либо отклонить значение, либо обработать как неизвестное, но не присваивать ему смысл другого статуса.
Коротко
- Номера полей неприкосновенны.
optionalнужен там, где присутствие отличается от умолчания.oneofвыбирает один вариант,repeatedиmapописывают коллекции.- Enum не переименовывают, удалённые поля резервируют.