|
| 1 | +# Common components |
| 2 | + |
| 3 | +In general, APIs should be designed to be self-contained. APIs generally need |
| 4 | +to be able to move forward independently of one another, and mutual |
| 5 | +dependencies can cause downstream APIs to be forced into taking major version |
| 6 | +changes or even lead to dependency conflicts. |
| 7 | + |
| 8 | +However, there are also cases where common structures are valuable, especially |
| 9 | +where a concept is well-known and it is sufficiently clear that it will not |
| 10 | +change. Having a single representation of these common structures is valuable |
| 11 | +because it avoids disrepancies between APIs in things like how dates or |
| 12 | +monetary values are represented. It also enables shared libraries for common |
| 13 | +operations, such as basic arithmetic on monetary values. |
| 14 | + |
| 15 | +Common components serve this use case. |
| 16 | + |
| 17 | +## Guidance |
| 18 | + |
| 19 | +The public representation of APIs **should** be self-contained (for protocol |
| 20 | +buffers, this means that all API protos used by the API originate in the same |
| 21 | +proto `package`), except for common components, which **may** be used freely in |
| 22 | +any API. |
| 23 | + |
| 24 | +An API **must not** define a set of API-specific common components which live |
| 25 | +outside of its versioning structure. This prevents independent movement of |
| 26 | +particular versions and also causes problems for client libraries in many |
| 27 | +languages that compile protobuf messages into classes. |
| 28 | + |
| 29 | +An API **should not** define alternative representations of any of the existing |
| 30 | +common components described below, even within its versioning structure. |
| 31 | + |
| 32 | +## Existing common components |
| 33 | + |
| 34 | +The common components, which public-facing APIs **may** safely depend on, are |
| 35 | +defined canonically in the [AIP common components][] repository. These include |
| 36 | +READMEs with canonical definitions for each component, and -- when applicable |
| 37 | +-- implementations of these definitions, in both JSON Schema and protobuf |
| 38 | +formats. The protobufs are also published to the Buf Schema Sepository at |
| 39 | +[`buf.build/aip/common`][buf], and the JSON schemas are published to the [JSON |
| 40 | +Schema Store][] with names beginning with `aip-`, for example `aip-type-money` |
| 41 | +or `aip-longrunning-operation`. |
| 42 | + |
| 43 | +While the [AIP common components][] repository is canonical and takes |
| 44 | +precedence over this list, some of the common components defined there include |
| 45 | +representations of the following concepts: |
| 46 | + |
| 47 | +### API design patterns |
| 48 | + |
| 49 | +- `StatusMonitor` / `Operation`: Represents the status of a long-running |
| 50 | + request (see [AIP-151][] for details). |
| 51 | + |
| 52 | +#### gRPC-specific API design patterns |
| 53 | + |
| 54 | +- [`google.api.*`][api] (but _not_ subpackages of `google.api`): Annotations |
| 55 | + useful for gRPC/JSON transcoding, supported by frameworks including .NET 7. |
| 56 | + |
| 57 | +- [`google.rpc.*`][rpc]: A small number of components related to gRPC |
| 58 | + request/response status and errors. |
| 59 | + |
| 60 | +### Common types |
| 61 | + |
| 62 | +This section provides examples for the sake of illustration; it may not be |
| 63 | +exhaustive. The [AIP common components][] repo is canonical. |
| 64 | + |
| 65 | +#### General common types |
| 66 | + |
| 67 | +- [`Color`][color]: RGB or RGBA colors. |
| 68 | + |
| 69 | +- [`Fraction`][fraction]: A numeric fraction. |
| 70 | + |
| 71 | +- [`LatLng`][lat_lng]: Geographic coordinates. |
| 72 | + |
| 73 | +- [`Money`][money]: An amount of money in a given currency. |
| 74 | + |
| 75 | +- [`PhoneNumber`][phone_number]: A phone number in most countries. |
| 76 | + |
| 77 | +- [`PostalAddress`][postal_address]: Postal addresses in most countries. |
| 78 | + |
| 79 | +- [`Quaternion`][quaternion]: A geometric quaternion. |
| 80 | + |
| 81 | +#### Date- and time-related types |
| 82 | + |
| 83 | +- [`Date`][date]: A calendar date, with no time or time zone component. |
| 84 | + |
| 85 | +- [`DateTime`][date_time]: A calendar date and wall-clock time, with optional |
| 86 | + time zone or UTC offset information. |
| 87 | + |
| 88 | +- [`DayOfWeek`][day_of_week]: An enumeration representing the day of the week. |
| 89 | + |
| 90 | +- [`Duration`][duration]: A duration with nanosecond-level precision. |
| 91 | + |
| 92 | +- [`Interval`][interval]: An interval between two timestamps. |
| 93 | + |
| 94 | +- [`Month`][month]: An enumeration representing the Gregorian month. |
| 95 | + |
| 96 | +- [`TimeOfDay`][time_of_day]: Wall-clock time, with no date or time zone |
| 97 | + component. |
| 98 | + |
| 99 | +- [`Timestamp`][timestamp]: A timestamp with nanosecond-level precision. |
| 100 | + |
| 101 | +#### Protobuf types |
| 102 | + |
| 103 | +The [`google.protobuf`][protobuf] package is shipped with protocol buffers |
| 104 | +itself, rather than with API tooling. The Well-Known Types defined in this |
| 105 | +package should always be used when appropriate, and the [AIP common |
| 106 | +components][] repo does not define any protos for these types, even when it |
| 107 | +defines a corresponding JSON Schema. These include: |
| 108 | + |
| 109 | +- [`google.protobuf.Duration`][duration]: Durations, with nanosecond-level |
| 110 | + precision. The protobuf runtime provides helper functions to convert to and |
| 111 | + from language-native duration objects where applicable (such as Python's |
| 112 | + [`timedelta`][timedelta]). |
| 113 | +- [`google.protobuf.Timestamp`][timestamp]: Timestamps, with nanosecond-level |
| 114 | + precision. The protobuf runtime provides helper functions in most languages |
| 115 | + to convert to and from language-native timestamp objects (such as Python's |
| 116 | + [`datetime`][datetime]). |
| 117 | + |
| 118 | +`google.protobuf` also provides some useful components that correspond to JSON |
| 119 | +primitives (and so have no representation at all in the [AIP common |
| 120 | +components][] repo), namely: |
| 121 | + |
| 122 | +- [`google.protobuf.Value`][struct]: An arbitrary JSON value. The protobuf |
| 123 | + runtime provides helper functions in most languages to convert `Value` |
| 124 | + objects to and from JSON. |
| 125 | +- [`google.protobuf.Struct`][struct]: JSON-like structures (a dictionary of |
| 126 | + primitives, lists, and other dictionaries). The protobuf runtime provides |
| 127 | + helper functions in most languages to convert `Struct` objects to and from |
| 128 | + JSON. |
| 129 | + |
| 130 | +`google.protobuf.Struct` and `google.protobuf.Value` are designated common |
| 131 | +components by this AIP; proto-based APIs **should** use them when representing |
| 132 | +arbitrary JSON-like structures. |
| 133 | + |
| 134 | +## Libraries for common types |
| 135 | + |
| 136 | +For the common components in the `aip.type` namespace, which represent common |
| 137 | +data types, the [AIP common components][] repo may contain canonical libraries |
| 138 | +in a number of languages. These libraries are designed to be idiomatic in a |
| 139 | +given language, and should feel similar to using the language's standard |
| 140 | +libraries. They should provide basic functionality like adding two `Money` |
| 141 | +values, or determining if one `Date` comes before another. |
| 142 | + |
| 143 | +When a language already has a standard library representation of a common type |
| 144 | +(such as Python's `datetime` for the `Timestamp` type), there may instead be a |
| 145 | +library for converting the JSON or protobuf representation to the standard |
| 146 | +library representation. |
| 147 | + |
| 148 | +If a library you want does not exist, and you want to contribute one, please |
| 149 | +[open an issue][] on the [AIP common components][] repository in GitHub. |
| 150 | + |
| 151 | +## Appendix: Adding to common components |
| 152 | + |
| 153 | +Occasionally, it may be useful to add protos to these packages or to add to the |
| 154 | +list of common components. In order to do this, [open an issue][] on the [AIP |
| 155 | +common components][] repository in GitHub. |
| 156 | + |
| 157 | +However, some general guidelines are worth noting for this: |
| 158 | + |
| 159 | +- Schemas **should** only be granted common component status if it is certain |
| 160 | + that they will never change (at all -- even in ways that would normally be |
| 161 | + considered backwards compatible). Common components are not versioned, and it |
| 162 | + must be the case that API creators and consumers can rely on the component to |
| 163 | + be a complete and accurate representation indefinitely. |
| 164 | +- Schemas must be applicable to a significant number of APIs for consideration |
| 165 | + as common components. |
| 166 | +- Even after a common component is added, APIs using local versions **must** |
| 167 | + continue to do so until they go to the next major version. |
| 168 | + |
| 169 | +<!-- prettier-ignore-start --> |
| 170 | +[api]: https://github.com/googleapis/googleapis/tree/master/google/api |
| 171 | +[rpc]: https://github.com/googleapis/googleapis/tree/master/google/rpc |
| 172 | + |
| 173 | +[color]: https://github.com/aip-dev/common-components/tree/master/aip/type/color |
| 174 | +[fraction]: https://github.com/aip-dev/common-components/tree/master/aip/type/fraction |
| 175 | +[lat_lng]: https://github.com/aip-dev/common-components/tree/master/aip/type/lat_lng |
| 176 | +[money]: https://github.com/aip-dev/common-components/tree/master/aip/type/money |
| 177 | +[phone_number]: https://github.com/aip-dev/common-components/tree/master/aip/type/phone_number |
| 178 | +[postal_address]: https://github.com/aip-dev/common-components/tree/master/aip/type/postal_address |
| 179 | +[quaternion]: https://github.com/aip-dev/common-components/tree/master/aip/type/quaternion |
| 180 | + |
| 181 | +[date]: https://github.com/aip-dev/common-components/tree/master/aip/type/date |
| 182 | +[date_time]: https://github.com/aip-dev/common-components/tree/master/aip/type/date_time |
| 183 | +[day_of_week]: https://github.com/aip-dev/common-components/tree/master/aip/type/day_of_week |
| 184 | +[duration]: https://github.com/aip-dev/common-components/tree/master/aip/type/duration |
| 185 | +[interval]: https://github.com/aip-dev/common-components/tree/master/aip/type/interval |
| 186 | +[month]: https://github.com/aip-dev/common-components/tree/master/aip/type/month |
| 187 | +[time_of_day]: https://github.com/aip-dev/common-components/tree/master/aip/type/time_of_day |
| 188 | +[timestamp]: https://github.com/aip-dev/common-components/tree/master/aip/type/timestamp |
| 189 | + |
| 190 | +[datetime]: https://docs.python.org/3/library/datetime.html#datetime.datetime |
| 191 | +[duration]: https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/duration.proto |
| 192 | +[protobuf]: https://github.com/protocolbuffers/protobuf/tree/main/src/google/protobuf |
| 193 | +[struct]: https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/struct.proto |
| 194 | +[timedelta]: https://docs.python.org/3/library/datetime.html#datetime.timedelta |
| 195 | +[timestamp]: https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/timestamp.proto |
| 196 | + |
| 197 | +[open an issue]: https://github.com/aip-dev/common-components/issues |
| 198 | +[aip common components]: https://github.com/aip-dev/common-components |
| 199 | +[json schema store]: https://www.schemastore.org/json/ |
| 200 | +[aip-151]: ../0151 |
| 201 | +[buf]: https://buf.build/aip/type |
| 202 | +<!-- prettier-ignore-end --> |
0 commit comments