AIP-146
Generic fields 通用字段
Most fields in any API, whether in a request, a resource, or a custom response, have a specific type or schema. This schema is part of the contract that developers write their code against. 任何 API 中的大多数字段,无论是在请求、资源还是自定义响应中,都具有特定的类型或架构。 此模式是开发人员编写代码所依据的合同的一部分。
However, occasionally it is appropriate to have a generic or polymorphic field of some kind that can conform to multiple schemata, or even be entirely free-form. 然而,偶尔有一个通用的或多态的字段是合适的,它可以符合多个模式,甚至是完全自由的形式。
Guidance
While generic fields are generally rare, a service may introduce generic field where necessary. There are several approaches to this depending on how generic the field needs to be; in general, services should attempt to introduce the "least generic" approach that is able to satisfy the use case. 虽然通用字段通常很少见,但服务可能在必要时引入通用字段。 有几种方法可以解决这个问题,具体取决于该字段需要的通用程度; 一般来说,服务应该尝试引入能够满足用例的“最不通用”的方法。
Oneof
A oneof
may be used to introduce a type union: the user or service is able to specify one of the fields inside the oneof
. Additionally, a oneof
may be used with the same type (usually strings) to represent a semantic difference between the options.
oneof
可以用于引入类型联合:用户或服务能够指定 oneof
内的字段之一。 此外,oneof
可以与相同类型(通常是字符串)一起使用,以表示选项之间的语义差异。
Because the individual fields in the oneof
have different keys, a developer can programmatically determine which (if any) of the fields is populated.
因为 oneof
中的各个字段具有不同的键,开发人员可以以编程方式确定填充哪些字段(如果有)。
A oneof
preserves the largest degree of type safety and semantic meaning for each option, and services should generally prefer them over other generic or polymorphic options when feasible. However, the oneof
construct is
ill-suited when there is a large (or unlimited) number of potential options, or when there is a large resource structure that would require a long series of "cascading oneofs".
oneof
为每个选项保留了最大程度的类型安全性和语义含义,并且服务应该通常在可行的情况下比其他通用或多态选项更喜欢它们.
但是,当存在大量(或无限)潜在选项时,或者当存在需要一长串“级联 oneofs”的大型资源结构时,'oneof' 结构不适合。
Note: Adding additional possible fields to an existing oneof
is a non-breaking change, but moving existing fields into or out of a oneof
is breaking (it creates a backwards-incompatible change in Go protobuf stubs).
向现有的 oneof
添加额外的可能字段是一项非破坏性更改,但将现有字段移入或移出 oneof
是破坏性的(它在 Go protobuf 存根中创建了向后不兼容的更改)。
Maps
Maps may be used in situations where many values of the same type are needed, but the keys are unknown or user-determined. Maps 可能用于需要许多相同类型的值,但键未知或用户确定的情况。
Maps are usually not appropriate for generic fields because the map values all share a type, but occasionally they are useful. In particular, a map can sometimes be suited to a situation where many objects of the same type are needed, with different behavior based on the names of their keys (for example, using keys as environment names). 映射通常不适用于通用字段,因为映射值都共享一个类型,但有时它们很有用。 特别是,映射有时可以适用于需要许多相同类型的对象的情况,它们的行为基于其键的名称(例如,使用键作为环境名称)。
Struct
The google.protobuf.Struct
object may be used to represent arbitrary nested JSON. Keys can be strings, and values can be floats, strings, booleans, arrays, or additional nested structs, allowing for an arbitrarily nested structure that can be represented as JSON (and is automatically represented as
JSON when using REST/JSON).
google.protobuf.Struct
对象可用于表示任意嵌套的 JSON。 键可以是字符串,值可以是浮点数、字符串、布尔值、数组或其他嵌套结构,允许任意嵌套结构,可以表示为 JSON(并自动表示为
使用 REST/JSON 时的 JSON)。
A Struct
is most useful when the service does not know the schema in advance, or when a service needs to store and retrieve arbitrary but structured user data. Using a Struct
is convenient for users in this case because they can easily get JSON objects that can be natively manipulated in their environment of choice.
当服务事先不知道架构时,或者当服务需要存储和检索任意但结构化的用户数据时,“结构”最有用。 在这种情况下,使用 Struct
对用户来说很方便,因为他们可以很容易地获得可以在他们选择的环境中本地操作的 JSON 对象。
If a service needs to reason about the schema of a Struct
, it should use JSONSchema for this purpose. Because JSONSchema is itself JSON, a valid JSONSchema document can itself be stored in a Struct
.
如果服务需要推理 Struct
的模式,它应该为此使用 JSONSchema。 因为 JSONSchema 本身就是 JSON,所以一个有效的 JSONSchema 文档本身可以存储在一个 Struct
中。
Any
The google.protobuf.Any
object can be used to send an arbitrary serialized protocol buffer and a type definition.
google.protobuf.Any
对象可用于发送任意序列化协议缓冲区和类型定义。
However, this introduces complexity, because an Any
becomes useless for any task other than blind data propagation if the consumer does not have access to the proto. Additionally, even if the consumer does have the proto, the consumer has to ensure the type is registered and then deserialize manually,
which is an often-unfamiliar process.
但是,这会带来复杂性,因为如果消费者无法访问原型,那么除了盲数据传播之外的任何任务都将变得无用。 此外,即使消费者确实拥有原型,消费者也必须确保类型已注册,然后手动反序列化,这是一个经常不熟悉的过程。
Because of this, Any
should not be used unless other options are infeasible.
因此,除非其他选项不可行,否则不应使用 Any
**。