Ответ
В Protobuf нет способа полностью запретить клиенту устанавливать значение поля, так как клиент может сформировать запрос с любыми данными. Однако есть несколько механизмов, чтобы сообщить о назначении поля и защитить сервер.
1. Опция deprecated
Это самый простой способ пометить поле как устаревшее. Он не запрещает использование, но может вызывать предупреждения при компиляции .proto файлов в некоторых языках.
message MyRequest {
string public_field = 1;
// Поле только для внутреннего использования. Не используйте его.
string internal_field = 2 [deprecated = true];
}
2. Валидация на стороне сервера (самый надёжный способ)
Это единственный способ гарантированно предотвратить использование поля клиентом. Сервер должен проверять, что "внутреннее" поле не заполнено в запросе.
// Go-код на сервере
import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func (s *Server) MyMethod(ctx context.Context, req *pb.MyRequest) (*pb.MyResponse, error) {
if req.GetInternalField() != "" {
return nil, status.Error(codes.InvalidArgument, "field 'internal_field' is for internal use only and must not be set by clients")
}
// ... остальная логика
return &pb.MyResponse{}, nil
}
3. Ключевое слово reserved
Если поле использовалось ранее, а теперь его нужно полностью убрать, но при этом не допустить его повторного использования с тем же номером (тегом) или именем, используется reserved.
Это защищает от проблем обратной совместимости, когда старые клиенты могут по ошибке отправлять данные в поле, которое в новой версии схемы имеет другое назначение.
message MyRequest {
string public_field = 1;
reserved 2; // Номер тега 2 больше нельзя использовать
reserved "internal_field"; // Имя 'internal_field' больше нельзя использовать
}
Рекомендация: Лучшая практика — комбинировать подходы. Используйте комментарии в .proto и опцию [deprecated = true] для информирования разработчиков, но всегда реализуйте валидацию на стороне сервера для критически важных полей.
Ответ 18+ 🔞
Слушай, смотри, вот такая хуйня с Protobuf. Хочешь запретить клиенту поле трогать? Да нихуя не выйдет, братан! Клиент — он как тот самый Герасим, только немой, а лезет везде, куда не просят. Может нахуячить в запросе чего угодно, хоть поле internal_field засунет, хоть super_secret_admin_key напишет. Полный пиздец.
Но! Есть несколько способов хотя бы попытаться объяснить этому распиздую, что так делать не надо.
1. Опция deprecated — типа «не трожь, а то старым станешь»
Это как на заборе написать «Не лезь, убьёт!». Не запрещает, но предупреждает. В коде .proto это выглядит так:
message MyRequest {
string public_field = 1;
// ЭТО ПОЛЕ ТОЛЬКО ДЛЯ ВНУТРЕННЕГО ИСПОЛЬЗОВАНИЯ, НЕ ТРОГАТЬ, БЛЯДЬ!
string internal_field = 2 [deprecated = true];
}
Клиент прочитает, может, даже в IDE красненьким подчеркнёт, но отправить-то всё равно сможет! Так что это просто вежливая просьба, не более.
2. Валидация на сервере — единственный железобетонный способ
Вот это уже по-взрослому. Тут ты становишься тем самым злым барином, который Герасиму говорит: «Муму — топить!». Если клиент посмел прислать лишнее поле — нахуй его в озеро с ошибкой!
// Серверный код на Go
import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func (s *Server) MyMethod(ctx context.Context, req *pb.MyRequest) (*pb.MyResponse, error) {
// А ну-ка, проверим, не суёт ли он своё рыло куда не надо?
if req.GetInternalField() != "" {
// Вот тебе, сука, InvalidArgument! Получай и распишись!
return nil, status.Error(codes.InvalidArgument, "поле 'internal_field' только для внутреннего использования, клиентам его совать НЕЛЬЗЯ!")
}
// ... дальше уже нормальная логика
return &pb.MyResponse{}, nil
}
Вот это — 100% гарантия. Клиент попробует — получит по ебалу ошибкой и всё. Пиздец его надеждам.
3. Ключевое слово reserved — «место занято, иди нахуй»
Это если поле было, а потом ты такой: «Ой, бля, да нахуй оно надо!». Убираешь поле из схемы, но помечаешь его номер и имя как reserved, чтобы какой-нибудь умник потом не взял и не использовал это же самое место для своей новой хуйни.
message MyRequest {
string public_field = 1;
reserved 2; // Тег номер 2 — занято, иди лесом!
reserved "internal_field"; // И имя 'internal_field' тоже — не трогать!
}
Это защита от самих себя, от проблем с обратной совместимостью. Старый клиент попробует отправить данные в старое поле — схема нового сервера его просто не поймёт, и всё.
Так что, вывод, блядь, какой?
Комбинируй всё, как умный человек. В .proto пиши комментарии жирными буквами и ставь [deprecated] — для воспитания. Но обязательно, ёбта, делай валидацию на сервере! Потому что клиенты — они как дети: пока не дашь по жопе, не поймут.