Как в gRPC (Protobuf) обозначить поле, которое не предназначено для использования клиентом?

Ответ

В 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] для информирования разработчиков, но всегда реализуйте валидацию на стороне сервера для критически важных полей.