AIP-146 泛化域
编号 | 146 |
---|---|
原文链接 | https://google.aip.dev/146 |
状态 | 批准 |
创建日期 | 2019-05-28 |
更新日期 | 2019-05-28 |
API中的大多数域,无论是在请求、资源还是自定义应答中,都有具体的类型或模式。这个模式是约定的一部分,开发者依此约定进行编码。
然而,偶尔会有一些泛化或多态域,可以符合多种模式,甚至是完全可以是任意形式的。
指南
虽然泛化域往往很少见,服务 可以 在必要时使用泛化域。根据域需要的泛化程度,有几种方法可以做到这一点;一般来说,服务 应当 尝试使用能够满足用例的“最低泛化”方法。
Oneof
oneof
可以 用于引入联合类型:用户或服务可以指定 oneof
中的一个域。此外 oneof
可以 可以包含同类型域(通常是字符串),表示选项之间存在语义差异。
由于 oneof
中的各个域使用不同的键,开发者可以通过编程确定使用哪个(如果有)域。
oneof
在最大程度上保留了每个选项的类型安全和语义信息,相对于其他泛化或多态选项,服务 应当 优先使用 oneof
。然而,如果存在大量(或无限)的备选项,或者对于需要一系列“级联oneof”的大型资源结构, oneof
结构是不合适的。
注意 向现有的
oneof
添加额外的备选域是非破坏性变更,但将现有域移入或移出oneof
是破坏性变更(这会在Go protobuf stubs中产生无法向后兼容的变更)。
Maps
Maps 可以 用于存在许多 同类型 值,但键未知或键由用户决定的情况。
Maps通常不适合泛化域,因为map值共享同一类型。偶尔也是有用的。特别是map有时可以用于存在许多同类型对象,并根据键的 名字 产生不同行为的情况(如使用键作为环境 名字 )。
Struct
google.protobuf.Struct对象 可以 用于表示任意嵌套JSON。键是字符串,值可以是浮点数、字符串、布尔值、数组或者另外的嵌套结构,允许表示为JSON的任意嵌套结构(并且在使用REST/JSON时自动表示为JSON)。
如果服务预先不指导模式,或者服务需要存储和检索任意的结构化用户数据, Struct
用处最大。此时使用 Struct
对用户来说非常方便,可以轻松获得JSON对象,在客户端环境中方便的操作。
如果服务需要推理 Struct
的 模式 , 应当 使用JSONSchema实现这一目的。JSONSchema本身就是JSON,可以存储在 Struct
中。
Any
google.protobuf.Any对象可用于发送任意序列化的protocol buffer消息和类型定义。
但这增加了复杂性,如果消费者无法访问proto定义, Any
除了传递无效数据外,对任何实际任务都没有用处。即使消费者 确实 有proto定义,也必须确保类型已注册,并执行手动反序列化。开发者往往不熟悉这个过程。
因此,除非其他方案行不通, 不应 使用 Any
。