Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 110 additions & 30 deletions aip/client-libraries/4236.md
Original file line number Diff line number Diff line change
@@ -1,53 +1,133 @@
---
id: 4236
state: reviewing
state: approved
created: 2024-05-16
---

# Version-aware clients

APIs can annotate services with [`google.api.api_version`][]. If
`google.api.api_version` is specified, version-aware clients **must**
include the value of `google.api.api_version` in the request to the API.
APIs can annotate [API interfaces][interface def] with
[`google.api.api_version`][annotation]. If `google.api.api_version` is
specified, version-aware clients **must** include the value of
`google.api.api_version` in the request to the API and in the documentation of
the per-API interface clients.

### Expected Generator and Client Library Behavior
## Generator and client library behavior

If a service is annotated with `google.api.api_version`, client library
generators **must** include either an HTTP query parameter `$apiVersion`
or HTTP header `X-Goog-Api-Version`, but a request **must not** contain both.
If an API interface is annotated with `google.api.api_version`, client
library generators **must** include either an HTTP query parameter `$apiVersion`
or HTTP header/gRPC metadata key `X-Goog-Api-Version`, but a request
**must not** contain both.

Generated documentation for a given service **may** include the value of
`google.api.api_version`, if it exists in the source protos.
### Generated client documentation

Clients **must** treat the value of `google.api.api_version` as opaque to ensure
robust compatibility. This means that the specific format or structure of the
version string **must not** be parsed or interpreted for any purpose beyond identifying
the intended API version.
Generated client documentation for a given API interface **must** include the
value of `google.api.api_version`, if it exists in the source protos. The
comment **must** include the original API interface name and the exact contents
of the annotation.

**Note:** The text does not need to match exactly to the examples below, but it
still needs to fulfill the requirements desribed herein.

For example, the following API interface definition would produce the following
Go client documentation:

```proto
service LibraryService {
option (google.api.api_version) = "2026-01-01";
}
```

```go
// The LibraryClient is a client for interacting with the Cloud Library...
//
// This client uses LibraryService version 2026-01-01.
type LibraryClient struct {}
```

Any generated documentation for an entire [API service's][service def] client
package **must** include a section that lists the client-interface-version
tuples present in the package. For example, the following API interface
defintions would produce the following client package documentation section:

```proto
service LibraryService {
option (google.api.api_version) = "2026-01-01";
}
service BookService {
option (google.api.api_version) = "2026-05-15";
}
service ShelfService {
option (google.api.api_version) = "2026-02-05";
}
```

```md
## API Versions

* LibraryClient uses LibraryService version 2026-01-01
* BookClient uses BookService version 2026-05-15
* ShelfClient uses ShelfService version 2026-02-05

```

If all API interfaces share the same API version, this list **should** be
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to also add a clause that the if there are multiple versions, the list may be indexed by version identifier?

version-X → Service A, Service B
version-Y → Service C, Service D

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, when do you think that would be better than what is suggested (individual items per-client-interface-version tuple)?

I'm not super picky, but I'd also like to minimize variance unless it is necessary (since I'm implementing this in most languages 😄 )

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, I was suggesting an additional clause, not a replacement.

When all the services use the same version, then the suggested concise sentences is best. If there are multiple services using distinct versions, then having the reverse list might be easier to read.

Rationale: number-of-service-versions ≤ number-of-services, so indexing by the service versions will lead to a shorter list than indexing by services.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, I was suggesting an additional clause, not a replacement.

I understand, but it is one more thing to implement, one more conditional to figure out, so I want to understand when it would be most valuable.

If there are multiple services using distinct versions, then having the reverse list might be easier to read.

If there are 15 services, 14 on the same version and 1 on a different one, it might not be easier to read while trying to find one of those 14 that have the same version:

* versionA: service, service, service, service, service, service, service, service, service, service, service, service, service, service
* versionB: service

But maybe I'm nit picking. How would the client type factor into such a list? I think that is valuable information b.c it shows them exactly which client to initialize rather than having to work it out from the service name.

Rationale: number-of-service-versions ≤ number-of-services, so indexing by the service versions will lead to a shorter list than indexing by services.

So only when each service has its own version would their be a flat list? Trying to understand the heuristic that would be applied.

reduced to a single sentence for brevity. For example, if all versions were the
same in the definitions above, the generated client package documentation would
be as follows:

```md
## API Versions

All clients use API version 2026-01-01.
```

### Version opacity

Clients and generators **must** treat the value of `google.api.api_version` as
opaque to ensure robust compatibility. This means that the specific format or
structure of the version string **must not** be parsed or interpreted for any
purpose beyond identifying the intended API version.

## Rationale

### Necessity for Versioning

Explicit API versioning using the `google.api.api_version` annotation is essential
for maintaining compatibility between clients and services over time. As services
evolve, their schemas and behaviors may change. By specifying the API version, a
client communicates its expectations to the service. This allows the service to
respond in a manner consistent with the client's understanding, preventing errors
or unexpected results due to incompatible changes.
Explicit API versioning using the `google.api.api_version` annotation is
essential for maintaining compatibility between clients and services over time.
As services evolve, their schemas and behaviors may change. By specifying the
API version, a client communicates its expectations to the API service. This
allows the API service to respond in a manner consistent with the client's
intended semantics, preventing errors or unexpected results due to incompatible
changes.

### Importance of Opaque Treatment

Treating the `google.api.api_version` value as opaque is important for ensuring robust
compatibility guarantees. By relying on this opaque identifier, clients avoid making
assumptions about the underlying versioning scheme, which may change independently of
the API itself. This flexibility allows service providers to evolve their versioning
strategies without impacting client compatibility.
Treating the `google.api.api_version` value as opaque is important for ensuring
robust compatibility guarantees. By using this identifier opaquely, clients
avoid making assumptions about the underlying versioning scheme, which may
change independently of the API itself. This flexibility allows API service
providers to evolve their versioning strategies without impacting client
compatibility.

### Mutual Exclusivity of Query and Header

Both the query parameter and header mechanisms exist to provide flexibility for different
client environments. However, allowing both simultaneously could lead to ambiguity if the
values differ. To ensure consistent version identification and prevent potential conflicts,
only one mechanism should be used at a time.
Both the query parameter and header mechanisms exist to provide flexibility for
different client environments. However, allowing both simultaneously could lead
to ambiguity if the values differ. To ensure consistent version identification
and prevent potential conflicts, only one mechanism should be used at a time.

### Inclusion in documentation

The API version identifies the iteration of the API contract being consumed by
the client and thus the end user. The end user needs a means of relating the
API version in use by the client to other API artifacts (such as product
documentation and other client surfaces) and vice versa.

[annotation]: https://github.com/googleapis/googleapis/blob/master/google/api/client.proto
[interface def]: https://google.aip.dev/9#api-interface
[service def]: https://google.aip.dev/9#api-service

## Changelog

[`google.api.api_version`]: https://github.com/googleapis/googleapis/blob/master/google/api/client.proto
- **2025-12-08**: Add documentation generation requirements and reformat.