Protocol Buffers 眾所周知的類型

google.protobuf 套件的 API 文件。

索引

以 "Value" 結尾的眾所周知的類型是其他類型的包裝訊息,例如 BoolValueEnumValue。這些現在已經過時。今天使用包裝器的唯一原因是

  • 與已使用它們的訊息的線路相容性。
  • 如果您想將純量值放入 Any 訊息中。

在大多數情況下,有更好的選項

  • 對於新的訊息,最好使用常規的明確存在欄位(在 proto2/proto3 中為 optional,在版本 >= 2023 中為常規欄位)。
  • 擴充通常是比 Any 欄位更好的選擇。

Any

Any 包含任意序列化的訊息以及描述序列化訊息類型的 URL。

JSON

Any 值的 JSON 表示法使用還原序列化、嵌入訊息的常規表示法,以及包含類型 URL 的額外欄位 @type。範例

package google.profile;
message Person {
  string first_name = 1;
  string last_name = 2;
}
{
  "@type": "type.googleapis.com/google.profile.Person",
  "firstName": <string>,
  "lastName": <string>
}

如果嵌入訊息類型是眾所周知的,並且具有自訂的 JSON 表示法,則該表示法將被嵌入,並添加一個欄位 value,該欄位除了 @type 欄位之外,還保存自訂 JSON。範例(對於訊息 google.protobuf.Duration

{
  "@type": "type.googleapis.com/google.protobuf.Duration",
  "value": "1.212s"
}
欄位名稱Type描述
type_url字串

一個 URL/資源名稱,其內容描述序列化訊息的類型。

對於使用 schema httphttps 或無 schema 的 URL,適用以下限制和解釋

  • 如果未提供 schema,則假設為 https
  • URL 路徑的最後一段必須表示類型的完整限定名稱(如 path/google.protobuf.Duration)。
  • 對 URL 進行 HTTP GET 必須產生二進位格式的 google.protobuf.Type 值,或產生錯誤。
  • 允許應用程式根據 URL 快取查詢結果,或將它們預先編譯到二進位檔案中,以避免任何查詢。因此,需要在類型變更時保留二進位相容性。(使用版本化的類型名稱來管理重大變更。)

httphttps(或空 schema)之外的 Schema 可能會與實作特定的語意一起使用。

value位元組必須是上述指定類型的有效序列化資料。

Api

Api 是通訊協定緩衝區服務的輕量級描述符。

欄位名稱Type描述
name字串此 API 的完整限定名稱,包括套件名稱,後跟 API 的簡單名稱。
methodsMethod此 API 的方法,順序未指定。
optionsOption附加到 API 的任何中繼資料。
version字串

此 API 的版本字串。如果指定,則必須採用 major-version.minor-version 的形式,如 1.10。如果省略次要版本,則預設為零。如果整個版本欄位為空,則主要版本從套件名稱中衍生,如下所述。如果欄位不為空,則會驗證套件名稱中的版本是否與此處提供的版本一致。

版本控制結構使用 語意版本控制,其中主要版本號表示重大變更,而次要版本號表示新增、非重大變更。兩個版本號都向使用者發出訊號,說明不同版本的預期結果,應根據產品計劃仔細選擇。

主要版本也反映在 API 的套件名稱中,該名稱必須以 v<major-version> 結尾,如 google.feature.v1。對於主要版本 0 和 1,可以省略後綴。零主要版本只能用於實驗性、非 GA API。

source_contextSourceContext此訊息表示的通訊協定緩衝區服務的來源內容。
mixinsMixin包含的 API。請參閱 Mixin
syntaxSyntax服務的來源語法。

BoolValue

bool 的包裝訊息。

BoolValue 的 JSON 表示法是 JSON truefalse

欄位名稱Type描述
valuebool布林值。

BytesValue

bytes 的包裝訊息。

BytesValue 的 JSON 表示法是 JSON 字串。

欄位名稱Type描述
value位元組位元組值。

DoubleValue

double 的包裝訊息。

DoubleValue 的 JSON 表示法是 JSON 數字。

欄位名稱Type描述
valuedouble雙精度值。

Duration

持續時間表示有符號、固定長度的時間跨度,表示為秒數和奈秒解析度的秒數分數。它獨立於任何日曆和「天」或「月」等概念。它與時間戳相關,因為兩個時間戳值之間的差異是一個持續時間,並且可以從時間戳中添加或減去持續時間。範圍約為 +-10,000 年。

範例 1:在偽代碼中從兩個時間戳計算持續時間。

Timestamp start = ...;
Timestamp end = ...;
Duration duration = ...;

duration.seconds = end.seconds - start.seconds;
duration.nanos = end.nanos - start.nanos;

if (duration.seconds < 0 && duration.nanos > 0) {
  duration.seconds += 1;
  duration.nanos -= 1000000000;
} else if (duration.seconds > 0 && duration.nanos < 0) {
  duration.seconds -= 1;
  duration.nanos += 1000000000;
}

範例 2:在偽代碼中從時間戳 + 持續時間計算時間戳。

Timestamp start = ...;
Duration duration = ...;
Timestamp end = ...;

end.seconds = start.seconds + duration.seconds;
end.nanos = start.nanos + duration.nanos;

if (end.nanos < 0) {
  end.seconds -= 1;
  end.nanos += 1000000000;
} else if (end.nanos >= 1000000000) {
  end.seconds += 1;
  end.nanos -= 1000000000;
}

Duration 的 JSON 表示法是一個以 s 結尾表示秒的 String,前面是秒數,奈秒表示為秒的小數部分。

欄位名稱Type描述
secondsint64時間跨度的有符號秒數。必須介於 -315,576,000,000 到 +315,576,000,000(含)之間。
nanosint32時間跨度的奈秒解析度有正負號的分數秒。小於一秒的持續時間以 0 的 seconds 欄位和正或負的 nanos 欄位表示。對於一秒或更長的持續時間,nanos 欄位的非零值必須與 seconds 欄位的符號相同。必須介於 -999,999,999 到 +999,999,999(含)之間。

Empty

一個通用的空訊息,您可以重複使用它,以避免在您的 API 中定義重複的空訊息。一個典型的例子是將它用作 API 方法的請求或回應類型。例如

service Foo {
  rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
}

Empty 的 JSON 表示法為空的 JSON 物件 {}

Enum

列舉類型定義

欄位名稱Type描述
name字串列舉類型名稱。
enumvalueEnumValue列舉值定義。
optionsOptionProtocol buffer 選項。
source_contextSourceContext來源上下文。
syntaxSyntax來源語法。

EnumValue

列舉值定義。

欄位名稱Type描述
name字串列舉值名稱。
numberint32列舉值數字。
optionsOptionProtocol buffer 選項。

Field

訊息類型中的單一欄位。

欄位名稱Type描述
kindKind欄位類型。
cardinalityCardinality欄位基數。
numberint32欄位號碼。
name字串欄位名稱。
type_url字串訊息或列舉類型的欄位類型 URL,不含協定。範例:"type.googleapis.com/google.protobuf.Timestamp"
oneof_indexint32訊息或列舉類型的欄位類型在 Type.oneofs 中的索引。第一個類型的索引為 1;零表示類型不在列表中。
packedbool是否使用替代的封裝連線表示法。
optionsOptionProtocol buffer 選項。
json_name字串欄位的 JSON 名稱。
default_value字串此欄位預設值的字串值。僅限 Proto2 語法。

Cardinality

欄位是可選、必要還是重複。

列舉值描述
CARDINALITY_UNKNOWN用於具有未知基數的欄位。
CARDINALITY_OPTIONAL用於可選欄位。
CARDINALITY_REQUIRED用於必要欄位。僅限 Proto2 語法。
CARDINALITY_REPEATED用於重複欄位。

Kind

基本欄位類型。

列舉值描述
TYPE_UNKNOWN欄位類型未知。
TYPE_DOUBLE欄位類型 double。
TYPE_FLOAT欄位類型 float。
TYPE_INT64欄位類型 int64。
TYPE_UINT64欄位類型 uint64。
TYPE_INT32欄位類型 int32。
TYPE_FIXED64欄位類型 fixed64。
TYPE_FIXED32欄位類型 fixed32。
TYPE_BOOL欄位類型 bool。
TYPE_STRING欄位類型 string。
TYPE_GROUP欄位類型 group。僅限 Proto2 語法,且已過時。
TYPE_MESSAGE欄位類型 message。
TYPE_BYTES欄位類型 bytes。
TYPE_UINT32欄位類型 uint32。
TYPE_ENUM欄位類型 enum。
TYPE_SFIXED32欄位類型 sfixed32。
TYPE_SFIXED64欄位類型 sfixed64。
TYPE_SINT32欄位類型 sint32。
TYPE_SINT64欄位類型 sint64。

FieldMask

FieldMask 代表一組符號欄位路徑,例如

paths: "f.a"
paths: "f.b.d"

這裡 f 代表某個根訊息中的欄位,ab 代表在 f 中找到的訊息中的欄位,而 d 代表在 f.b 中的訊息中找到的欄位。

欄位遮罩用於指定一個欄位子集,該子集應該由 get 操作傳回(一個投影),或由更新操作修改。欄位遮罩也有一個自訂的 JSON 編碼(見下文)。

投影中的欄位遮罩

FieldMask 指定一個投影時,API 會篩選回應訊息(或子訊息),使其僅包含遮罩中指定的欄位。例如,考慮這個「遮罩前」的回應訊息

f {
  a : 22
  b {
    d : 1
    x : 2
  }
  y : 13
}
z: 8

在套用前一個範例中的遮罩後,API 回應將不包含欄位 x、y 或 z 的特定值(它們的值將設定為預設值,並在 proto 文字輸出中省略)

f {
  a : 22
  b {
    d : 1
  }
}

不允許重複欄位,除非它位於欄位遮罩的最後一個位置。

如果 get 操作中不存在 FieldMask 物件,則操作會套用至所有欄位(如同已指定所有欄位的 FieldMask)。

請注意,欄位遮罩不一定會套用至最上層的回應訊息。在 REST get 操作的情況下,欄位遮罩會直接套用至回應,但在 REST list 操作的情況下,遮罩會改為套用至傳回資源清單中的每個個別訊息。在 REST 自訂方法的情況下,可以使用其他定義。遮罩的套用位置會在其於 API 中宣告時清楚記錄。在任何情況下,對傳回資源/資源的影響都是 API 的必要行為。

更新操作中的欄位遮罩

更新操作中的欄位遮罩指定目標資源的哪些欄位將被更新。API 必須僅變更遮罩中指定欄位的值,而保持其他欄位不變。如果傳入資源來描述更新後的值,API 會忽略遮罩未涵蓋的所有欄位的值。

為了將欄位的值重設為預設值,該欄位必須在遮罩中,並在提供的資源中設定為預設值。因此,為了重設資源的所有欄位,請提供資源的預設實例,並設定遮罩中的所有欄位,或者不提供遮罩(如下所述)。

如果更新時不存在欄位遮罩,則操作會套用至所有欄位(如同已指定所有欄位的欄位遮罩)。請注意,在出現結構描述演化的情況下,這可能表示用戶端不知道且因此未填入請求的欄位將重設為其預設值。如果這是非預期的行為,特定服務可能會要求用戶端始終指定欄位遮罩,如果沒有指定,則會產生錯誤。

與 get 操作一樣,請求訊息中描述更新值的資源位置取決於操作類型。在任何情況下,API 都必須遵守欄位遮罩的效果。

HTTP REST 的考量

使用欄位遮罩的更新操作的 HTTP 類型必須設定為 PATCH 而不是 PUT,才能滿足 HTTP 語意(PUT 只能用於完整更新)。

欄位遮罩的 JSON 編碼

在 JSON 中,欄位遮罩編碼為單一字串,其中路徑以逗號分隔。每個路徑中的欄位名稱會轉換為/從較低駝峰式命名慣例轉換。

例如,考慮以下訊息宣告

message Profile {
  User user = 1;
  Photo photo = 2;
}
message User {
  string display_name = 1;
  string address = 2;
}

在 proto 中,Profile 的欄位遮罩可能如下所示

mask {
  paths: "user.display_name"
  paths: "photo"
}

在 JSON 中,相同的遮罩表示如下

{
  mask: "user.displayName,photo"
}
欄位名稱Type描述
paths字串欄位遮罩路徑的集合。

FloatValue

float 的包裝訊息。

FloatValue 的 JSON 表示法為 JSON 數字。

欄位名稱Type描述
valuefloatfloat 值。

Int32Value

int32 的包裝訊息。

Int32Value 的 JSON 表示法為 JSON 數字。

欄位名稱Type描述
valueint32int32 值。

Int64Value

int64 的包裝訊息。

Int64Value 的 JSON 表示法為 JSON 字串。

欄位名稱Type描述
valueint64int64 值。

ListValue

ListValue 是動態類型值的重複欄位的包裝器。

ListValue 的 JSON 表示法為 JSON 陣列。

欄位名稱Type描述
valuesValue動態類型值的重複欄位。

Method

Method 代表 API 的方法。

欄位名稱Type描述
name字串此方法的簡單名稱。
request_type_url字串輸入訊息類型的 URL。
request_streamingbool如果為 true,則請求會串流。
response_type_url字串輸出訊息類型的 URL。
response_streamingbool如果為 true,則回應會串流。
optionsOption附加到方法的所有中繼資料。
syntaxSyntax此方法的來源語法。

Mixin

宣告要包含在此 API 中的 API。包含的 API 必須重新宣告來自包含 API 的所有方法,但會如下繼承文件和選項

  • 如果在註解和空白字元去除後,重新宣告方法的文件字串為空,則會從原始方法繼承。

  • 每個屬於服務組態的註釋(http、可見性),如果未在重新宣告方法中設定,則將會繼承。

  • 如果繼承 http 註釋,則路徑模式會如下修改。任何版本前置詞都會被包含 API 的版本加上指定的 root 路徑取代。

簡單 mixin 的範例

package google.acl.v1;
service AccessControl {
  // Get the underlying ACL object.
  rpc GetAcl(GetAclRequest) returns (Acl) {
    option (google.api.http).get = "/v1/{resource=**}:getAcl";
  }
}

package google.storage.v2;
service Storage {
  //       rpc GetAcl(GetAclRequest) returns (Acl);

  // Get a data record.
  rpc GetData(GetDataRequest) returns (Data) {
    option (google.api.http).get = "/v2/{resource=**}";
  }
}

mixin 組態的範例

apis:
- name: google.storage.v2.Storage
  mixins:
  - name: google.acl.v1.AccessControl

mixin 建構表示 AccessControl 中的所有方法也會在 Storage 中以相同的名稱和請求/回應類型宣告。文件產生器或註釋處理器會在繼承文件和註釋後,看到有效的 Storage.GetAcl 方法,如下所示

service Storage {
  // Get the underlying ACL object.
  rpc GetAcl(GetAclRequest) returns (Acl) {
    option (google.api.http).get = "/v2/{resource=**}:getAcl";
  }
  ...
}

請注意路徑模式中的版本如何從 v1 變更為 v2

如果 mixin 中指定了 root 欄位,則它應該是繼承 HTTP 路徑所放置的相對路徑。範例

apis:
- name: google.storage.v2.Storage
  mixins:
  - name: google.acl.v1.AccessControl
    root: acls

這表示以下繼承的 HTTP 註釋

service Storage {
  // Get the underlying ACL object.
  rpc GetAcl(GetAclRequest) returns (Acl) {
    option (google.api.http).get = "/v2/acls/{resource=**}:getAcl";
  }
  ...
}
欄位名稱Type描述
name字串包含的 API 的完整名稱。
root字串如果非空,則指定繼承 HTTP 路徑所植根的路徑。

NullValue

NullValue 是一個單例列舉,用於表示 Value 類型聯集的 null 值。

NullValue 的 JSON 表示法為 JSON null

列舉值描述
NULL_VALUENull 值。

Option

一個 protocol buffer 選項,可以附加到訊息、欄位、列舉等。

欄位名稱Type描述
name字串選項的名稱。例如,"java_package"
valueAny選項的值。例如,"com.google.protobuf"

SourceContext

SourceContext 表示有關 protobuf 元素的來源資訊,例如它所定義的檔案。

欄位名稱Type描述
file_name字串包含關聯 protobuf 元素的 .proto 檔案的路徑限定名稱。例如:"google/protobuf/source.proto"

StringValue

string 的包裝訊息。

StringValue 的 JSON 表示法為 JSON 字串。

欄位名稱Type描述
value字串string 值。

Struct

Struct 表示結構化資料值,包含對應至動態類型值的欄位。在某些語言中,原生表示法可能會支援 Struct。例如,在 JS 等指令碼語言中,結構表示為物件。該表示法的詳細資訊與語言的 proto 支援一起描述。

Struct 的 JSON 表示法為 JSON 物件。

欄位名稱Type描述
fieldsmap<string, Value>動態類型值的對應。

Syntax

定義 protocol buffer 元素的語法。

列舉值描述
SYNTAX_PROTO2語法 proto2
SYNTAX_PROTO3語法 proto3

Timestamp

Timestamp 代表時間上的某一點,它獨立於任何時區或日曆,表示為自 UTC Epoch 時間起算的秒數和分數秒數(奈秒解析度)。它使用 Proleptic Gregorian Calendar 進行編碼,該日曆將 Gregorian Calendar 向後延伸到第一年。它的編碼假設所有分鐘都是 60 秒長,也就是說,閏秒是「抹除」的,因此不需要閏秒表進行解釋。範圍從 0001-01-01T00:00:00Z 到 9999-12-31T23:59:59.999999999Z。透過限制在這個範圍內,我們可以確保能夠轉換成和轉換自 RFC 3339 日期字串。請參閱 https://www.ietf.org/rfc/rfc3339.txt

範例 1:從 POSIX time() 計算 Timestamp。

Timestamp timestamp;
timestamp.set_seconds(time(NULL));
timestamp.set_nanos(0);

範例 2:從 POSIX gettimeofday() 計算 Timestamp。

struct timeval tv;
gettimeofday(&tv, NULL);

Timestamp timestamp;
timestamp.set_seconds(tv.tv_sec);
timestamp.set_nanos(tv.tv_usec * 1000);

範例 3:從 Win32 GetSystemTimeAsFileTime() 計算 Timestamp。

FILETIME ft;
GetSystemTimeAsFileTime(&ft);
UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;

// A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
// is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
Timestamp timestamp;
timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));

範例 4:從 Java System.currentTimeMillis() 計算 Timestamp。

long millis = System.currentTimeMillis();

Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
    .setNanos((int) ((millis % 1000) * 1000000)).build();

範例 5:從 Python 中的目前時間計算 Timestamp。

now = time.time()
seconds = int(now)
nanos = int((now - seconds) * 10**9)
timestamp = Timestamp(seconds=seconds, nanos=nanos)
欄位名稱Type描述
secondsint64代表自 Unix epoch 1970-01-01T00:00:00Z 以來的 UTC 時間秒數。必須介於 0001-01-01T00:00:00Z 到 9999-12-31T23:59:59Z(含)之間。
nanosint32奈秒解析度的非負數分數秒。具有分數的負秒值仍然必須具有計時前進的非負 nanos 值。必須介於 0 到 999,999,999(含)之間。

Type

一個 protocol buffer 訊息類型。

欄位名稱Type描述
name字串完整訊息名稱。
fieldsField欄位列表。
oneofs字串此類型中 oneof 定義中出現的類型列表。
optionsOptionProtocol buffer 選項。
source_contextSourceContext來源上下文。
syntaxSyntax來源語法。

UInt32Value

uint32 的包裝訊息。

UInt32Value 的 JSON 表示法為 JSON 數字。

欄位名稱Type描述
valueuint32uint32 值。

UInt64Value

uint64 的包裝訊息。

UInt64Value 的 JSON 表示法為 JSON 字串。

欄位名稱Type描述
valueuint64uint64 值。

Value

Value 表示一個動態型別的值,可以是 null、數字、字串、布林值、遞迴結構值或值列表。值的產生器應設定其中一個變體,任何變體的缺失表示錯誤。

Value 的 JSON 表示法為 JSON 值。

欄位名稱Type描述
聯合欄位,只能是以下其中一個
null_valueNullValue表示一個 null 值。
number_valuedouble表示一個雙精度浮點數值。請注意,嘗試序列化 NaN 或 Infinity 會導致錯誤。(我們不能像處理一般欄位那樣將它們序列化為字串 "NaN" 或 "Infinity" 值,因為它們會被解析為 string_value,而不是 number_value)。
string_value字串表示一個字串值。
bool_valuebool表示一個布林值。
struct_valueStruct表示一個結構化值。
list_valueListValue表示重複的 Value