diff --git a/aip/general/0146.md b/aip/general/0146.md index 08bd9cc672..67c70fda94 100644 --- a/aip/general/0146.md +++ b/aip/general/0146.md @@ -88,8 +88,28 @@ which is an often-unfamiliar process. Because of this, `Any` **should not** be used unless other options are infeasible. +If an `Any` is used it **must** be annotated with the type(s) it references. See +[AIP-202 Type References][typeref] for more details. + +## Rationale + +### Declaring `Any` type references + +At runtime, an `Any` will have the fully-qualified type name in the `type_url` +field to enable the runtime consumer to look up the descriptor and unpack the +message. However, there is no machine-readable indicator in the API +specification itself as to what type(s) could possible be packed in a given +`Any` field. This prevents development of static analysis and runtime compliance +tools, as well as accurate documentation and client library support. As such, an +annotation is necessary to forward declare what an `Any` could contain. + +## Changelog + +- **2024-08-19:** Add `Any` type reference requirement and rationale. + [any]: https://github.com/protocolbuffers/protobuf/tree/master/src/google/protobuf/any.proto [struct]: https://github.com/protocolbuffers/protobuf/tree/master/src/google/protobuf/struct.proto [JSONSchema]: https://json-schema.org/ +[typeref]: ./0202.md#type-references diff --git a/aip/general/0202.md b/aip/general/0202.md index ede221b359..462cc618af 100644 --- a/aip/general/0202.md +++ b/aip/general/0202.md @@ -81,6 +81,39 @@ backwards compatible. Any new `FieldInfo.Format` value **must** be governed by an [IETF-approved RFC][ietf rfc] or a [Google-approved AIP](./0001.md). +### Type References + +Some generic field types (AIP-146), like `google.protobuf.Any`, can still have +a limited set of possible types. Identifying the type(s) of said field can be +done with the `google.api.TypeReference` via the +`google.api.FieldInfo.referenced_types` field, like so: + +```proto +message ModelResponse { + google.protobuf.Any raw_response = 1 [(google.api.field_info) = { + referenced_types: {type_name: "google.library.v1.TitleGenerationResponse"} + referenced_types: {type_name: "google.library.v1.ChapterGenerationResponse"} + referenced_types: {type_name: "google.library.v1.SummaryGenerationResponse"} + }]; +} +``` + +If the set of possible types is unknown to the specification author, e.g. the +*client* packs the field with its own type, then a single `referenced_types` +entry with `type_name : "*"` can be used. The wildcard value **must not** be +used in conjunction with fully-qualified references. + +Currently, the field annotated with `referenced_types` **must** be of type +`google.protobuf.Any`. + +#### Type Reference Compatibility + +Adding a new type reference to an existing field is **backwards compatible**, so +long as it matches what the field has always contained. + +Changing a type reference in place or removing a possible type is +**not backwards compatible**, and should be considered a breaking change. + ## Rationale #### Why add a format specifier? @@ -112,6 +145,27 @@ and see usage in Google APIs. Requiring such extra guidance means that governing the format specification is not the responsibility of the `FieldInfo.Format` enumeration itself. +#### Why annotate type reference on generic-typed fields? + +Without this statically defined type information, tools consuming the API +specification have no indicator of the types that the generic field could +contain, limiting their ability to facilitate accurate API consumption. See +[AIP-146 Declaring `Any` type references][generics] for more specific rationale. + +#### Why support a wildcard value for type references? + +There are cases where the set of possible types for a generic field is not known +to the author/service implementor. For example, when a generic is used as part +of a shared interface, like a platform logging framework, or when it is used to +accept generic user input. In these cases, the wildcard value explicitly states +the ambiguous nature of the field to consumers, tools, etc. to be handled +accorindgly. Without it, the alternative is simply not annotating a generic +field, which conveys nothing. + +## Changelog + +- **2024-08-19:** Add Type References section for new `referenced_types` field. + [field info proto]: https://github.com/googleapis/googleapis/blob/master/google/api/field_info.proto [rfc 4122]: https://datatracker.ietf.org/doc/html/rfc4122 [rfc 791]: https://datatracker.ietf.org/doc/html/rfc791 @@ -119,3 +173,4 @@ enumeration itself. [rfc 5952]: https://datatracker.ietf.org/doc/html/rfc5952 [ietf rfc]: https://www.ietf.org/standards/rfcs [java uuid]: https://docs.oracle.com/javase/8/docs/api/java/util/UUID.html +[generics]: ./0146.md#declaring-any-type-references