Skip to content

Commit

Permalink
Update to reflect new common components and live discussion.
Browse files Browse the repository at this point in the history
  • Loading branch information
rofrankel committed Dec 14, 2023
1 parent f4573c2 commit 30bb416
Showing 1 changed file with 62 additions and 19 deletions.
81 changes: 62 additions & 19 deletions aep/general/0155/aep.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ only processed once.

## Guidance

APIs **may** add a `string idempotency_key` parameter to request messages
(including those of standard methods) in order to uniquely identify particular
requests.
APIs **may** add a `aep.api.IdempotencyKey idempotency_key` parameter to
request messages (including those of standard methods) in order to uniquely
identify particular requests. API servers **must not** execute requests with
the same `idempotency_key` more than once.

```proto
message CreateBookRequest {
Expand All @@ -33,28 +34,57 @@ message CreateBookRequest {
// The book to create.
Book book = 2 [(google.api.field_behavior) = REQUIRED];
// A unique identifier for this request. Restricted to 36 ASCII characters.
// A random UUID is recommended.
// This request is only idempotent if a `idempotency_key` is provided.
string idempotency_key = 3 [(google.api.field_info).format = UUID4];
// This request is only idempotent if `idempotency_key` is provided.
//
// This key will be honored for at least one hour after the first time it is
// seen by the server.
//
// The key is restricted to 36 ASCII characters. A random UUID is recommended.
aep.api.IdempotencyKey idempotency_key = 3 [
(aep.api.field_info).minimum_lifetime = { seconds: 3600 }
];
}
```

- [`aep.api.IdempotencyKey`][] has a `key` and a `first_sent` timestamp.

- `key` is simply a unique identifier.

- Providing an idempotency key **must** guarantee idempotency.
- If a duplicate request is detected, the server **should** return the
response for the previously successful request, because the client most
likely did not receive the previous response.

- If a duplicate request is detected, the server **must** return either:

- A response equivalent to the response for the previously successful
request, because the client most likely did not receive the previous
response; OR
- An error indicating that the `first_sent` field of the idempotency key is
invalid (expired, in the future, or differs from a previous `first_sent`
value with the same `key`); OR
- An error, if returning an equivalent response is not possible.

For example, if a resource was created, then deleted, and then a
duplicate request to create the resource is received, the server **may**
return an error if returning the previously created resource is not
possible.

- APIs **should** honor idempotency keys for at least an hour.
- When using protocol buffers, idempotency keys that are UUIDs **must** be
annotated with a minimum lifetime using the extension
[`(aep.api.field_info).minimum_lifetime`].

- The `idempotency_key` field **must** be provided on the request message to
which it applies (and it **must not** be a field on resources themselves).

- The `first_sent` field can be used by API servers to determine if a key is
expired. API servers **must** reject requests with expired keys, and
**must** reject requests with keys that are in the future. When feasible,
API servers **should** reject requests that use the same `key` but have a
different `first_sent` timestamp.
- The `key` field **must** be able to be a UUID, and **may** allow UUIDs to
be the only valid format. The format restrictions for idempotency keys
**must** be documented.

- Idempotency keys **should** be optional.
- Idempotency keys **must** be able to be UUIDs, and **may** allow UUIDs to be
the only valid format. The format restrictions for idempotency keys **must**
be documented.
- When using protocol buffers, idempotency keys that are UUIDs **must** be
annotated with the `google.api.FieldInfo.Format` value `UUID4` using the
extension `(google.api.field_info).format = UUID4`. See
[AEP-202](../0202/aep.md) for more.

### Stale success responses

Expand Down Expand Up @@ -91,6 +121,8 @@ field; we define `idempotency_key` instead for two reasons:

<!-- prettier-ignore-start -->
[idempotency-key-draft]: https://datatracker.ietf.org/doc/draft-ietf-httpapi-idempotency-key-header/
[`aep.api.IdempotencyKey`]: https://buf.build/aep/api/file/main:aep/api/idempotency_key.proto#L21
[`(aep.api.field_info).minimum_lifetime`]: https://buf.build/aep/api/file/main:aep/api/field_info.proto#L35
<!-- prettier-ignore-end -->

### Using UUIDs for request identification
Expand All @@ -102,8 +134,19 @@ for collisions when done correctly.

## Changelog

- **2023-11-21**: Adopt AEP from from Google's AIP; rename field from
`request_id` to `idempotency_key`.
- **2023-11-21**: Adopt AEP from from Google's AIP with the following changes:
- Rename field from `request_id` to `idempotency_key` (plus some minor
releated rewording).
- Add a common component [`aep.api.IdempotencyKey`][] and use this rather
than `string` for the `idempotency_key` field; add related guidance about
`IdempotencyKey.first_seen`.
- Remove guidance about annotating `idempotency_key` with
`(google.api.field_info).format`.
- Add guidance about annotating `idempotency_key` with
[`(aep.api.field_info).minimum_lifetime`].
- Update guidance about responses to be more explicit about success and error
cases, while allowing "equivalent" rather than identical responses for
subsequent requests.
- **2023-10-02**: Add UUID format extension guidance.
- **2019-08-01**: Changed the examples from "shelves" to "publishers", to
present a better example of resource ownership.

0 comments on commit 30bb416

Please sign in to comment.