Skip to content

Commit 738c455

Browse files
Adopt AIP-216: States from google.aip.dev. (#161)
* Adopt AIP-216: States from google.aip.dev. * De-Google * Light copy-editing, and strengthen some guidance from should to must. * Add proto and OAS tabs. * Rephrase to remove redundancy with custom method guidance. * Linkify first mention of custom methods. * typo * Update aep/general/0216/aep.md.j2 Co-authored-by: Yusuke Tsutsumi <tsutsumi.yusuke@gmail.com> * Remove redundant enum content. --------- Co-authored-by: Yusuke Tsutsumi <tsutsumi.yusuke@gmail.com>
1 parent 4fb5062 commit 738c455

2 files changed

Lines changed: 212 additions & 5 deletions

File tree

aep/general/0216/aep.md.j2

Lines changed: 210 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,212 @@
11
# States
22

3-
**Note:** This AEP has not yet been adopted. See
4-
[this GitHub issue](https://github.com/aep-dev/aep.dev/issues/30) for more
5-
information.
3+
Many API resources carry a concept of "state": ordinarily, the resource's place
4+
in its lifecycle. For example, a virtual machine may be being provisioned,
5+
available for use, being spun down, or potentially be in one of several other
6+
situations. A job or query may be preparing to run, be actively running, have
7+
completed, and so on.
8+
9+
## Guidance
10+
11+
Resources needing to communicate their state **should** use an enum, which
12+
**should** be called `State` (or, if more specificity is required, end in the
13+
word `State`). This enum **should** be nested within the message it describes
14+
when only used as a field within that message.
15+
16+
**Important:** We use the term `State`, and _not_ `Status` (which is reserved
17+
for the HTTP and gRPC statuses).
18+
19+
### Enum values
20+
21+
Ideally, APIs use the same terminology throughout when expressing the same
22+
semantic concepts. There are usually many words available to express a given
23+
state, but our customers often use multiple APIs together, and it is easier for
24+
them when our terms are consistent.
25+
26+
At a high level:
27+
28+
- Resources that are available for use are `ACTIVE` (preferred over terms such
29+
as "ready" or "available").
30+
- Resources that have completed a (usually terminal) requested action use past
31+
participles (usually ending in `-ED`), such as `SUCCEEDED` (not
32+
"successful"), `FAILED` (not "failure"), `DELETED`, `SUSPENDED`, and so on.
33+
- Resources that are currently undergoing a state change use present
34+
participles (usually ending in `-ING`), such as `RUNNING`, `CREATING`,
35+
`DELETING`, and so on. In this case, it is expected that the state is
36+
temporary and will resolve to another state on its own, with no further user
37+
action.
38+
39+
**Note:** Only add states that are useful to customers. Exposing a
40+
large number of states simply because they exist in your internal system is
41+
unnecessary and adds confusion for customers. Each state **must** come with a
42+
use case for why it is necessary.
43+
44+
### Output only
45+
46+
The field referencing the `State` enum in a resource **must** behave and be
47+
documented as "Output only", in accordance with
48+
[field behavior documentation](./field-behavior-documentation).
49+
50+
APIs **must not** allow a `State` enum to be directly updated through an
51+
"update" method (or directly set through the "create" method), and **must**
52+
instead use custom state transition methods.
53+
54+
This is because update methods are generally not expected to have side effects,
55+
and also because updating state directly implies that it is possible to set the
56+
state to any available value, whereas states generally reflect a resource's
57+
progression through a lifecycle.
58+
59+
### State transition methods
60+
61+
State transition methods are a special type of
62+
[custom method](./custom-methods) that are responsible for transitioning a
63+
state field from one enum value to another. As part of the transition, other
64+
fields may also change, e.g. an `update_time` field. In addition to the general
65+
guidance for custom methods on resources, the following guidance applies for
66+
method definitions:
67+
68+
- The name of the method **should** be a verb followed by the singular form of
69+
the resource's message name.
70+
- The HTTP verb **must** be `POST`.
71+
72+
In addition to the general guidance for custom methods on resources, the
73+
following guidance applies for request definitions:
74+
75+
- A resource path field **must** be included. It **should** be called `path`.
76+
- The comment for the field **should** document the resource pattern.
77+
- Other fields **may** be included.
78+
79+
{% tab proto %}
80+
81+
```proto
82+
// Publishes a book.
83+
// The `state` of the book after publishing is `PUBLISHED`.
84+
// `PublishBook` can be called on Books in the state `DRAFT`; Books in a
85+
// different state (including `PUBLISHED`) returns an error.
86+
rpc PublishBook(PublishBookRequest) returns (Book) {
87+
option (google.api.http) = {
88+
post: "/v1/{path=publishers/*/books/*}:publish"
89+
body: "*"
90+
};
91+
}
92+
```
93+
94+
- The request message **must** match the RPC name, with a `Request` suffix.
95+
- The response message **should** be the resource itself.
96+
- If the RPC is [long-running](./lro), the response message **should** be an
97+
`aep.api.Operation` which resolves to the resource itself.
98+
- The `body` clause in the `google.api.http` annotation **must** be `"*"`.
99+
- The request message field receiving the resource path **should** map to the
100+
URI path.
101+
- This field **should** be called `path`.
102+
- The `path` field **should** be the only variable in the URI path. All
103+
remaining parameters **should** map to URI query parameters.
104+
- If the state transition is not allowed, the service **must** error with
105+
`FAILED_PRECONDITION` (HTTP 400).
106+
107+
The request message should look like this:
108+
109+
```proto
110+
message PublishBookRequest {
111+
// The path of the book to publish.
112+
// Format: publishers/{publisher}/books/{book}
113+
string path = 1 [
114+
(google.api.field_behavior) = REQUIRED,
115+
(google.api.resource_reference) = {
116+
type: "library.example.com/Book"
117+
}];
118+
}
119+
```
120+
121+
{% tab oas %}
122+
123+
**Note:** OAS content not yet written.
124+
125+
{% endtabs %}
126+
127+
## Additional Guidance
128+
129+
### Value uniqueness
130+
131+
Multiple top-level enums within the same package **must** not share the same
132+
values. This is because the C++ protoc code generator flattens top-level enum
133+
values into a single namespace.
134+
135+
State enums **should** live inside the resource definition.
136+
137+
### Prefixes
138+
139+
Using a `STATE_` prefix on every enum value is unnecessary. State enum values
140+
**should not** be prefixed with the enum name, except for the default value
141+
`STATE_UNSPECIFIED`.
142+
143+
### Breaking changes
144+
145+
**TL;DR:** Clearly communicate to users that state enums may receive new values
146+
in the future, and be conscientious about adding states to an existing enum.
147+
148+
Even though adding states to an existing states enum _can_ break existing user
149+
code, adding states is not considered a breaking change. Consider a state with
150+
only two values: `ACTIVE` and `DELETED`. A user may add code that checks
151+
`if state == ACTIVE`, and in the else cases simply assumes the resource is
152+
deleted. If the API later adds a new state for another purpose, that code will
153+
break.
154+
155+
API documentation **should** actively encourage users to code against state
156+
enums with the expectation that they may receive new values in the future.
157+
158+
APIs **may** add new states to an existing State enum when appropriate, and
159+
adding a new state is _not_ considered a breaking change.
160+
161+
### When to avoid states
162+
163+
Sometimes, a `State` enum may not be what is best for your API, particularly in
164+
situations where a state has a very small number of potential values, or when
165+
states are not mutually exclusive.
166+
167+
Consider the example of a state with only `ACTIVE` and `DELETED`, as discussed
168+
above. In this situation, the API may be better off exposing a
169+
`google.protobuf.Timestamp delete_time`, and instructing users to rely on
170+
whether it is set to determine deletion.
171+
172+
### Common states
173+
174+
The following is a list of states in common use. APIs **should** consider prior
175+
art when determining state names, and **should** value local consistency above
176+
global consistency in the case of conflicting precedent.
177+
178+
#### Resting states
179+
180+
"Resting states" are lifecycle states that, absent user action, are expected to
181+
remain indefinitely. However, the user can initiate an action to move a
182+
resource in a resting state into certain other states (resting or active).
183+
184+
- `ACCEPTED`
185+
- `ACTIVE`
186+
- `CANCELLED`
187+
- `DELETED`
188+
- `FAILED`
189+
- `SUCCEEDED`
190+
- `SUSPENDED`
191+
- `VERIFIED`
192+
193+
#### Active states
194+
195+
"Active states" are lifecycle states that typically resolve on their own into a
196+
single expected resting state.
197+
198+
**Note:** Remember only to expose states that are useful to customers. Active
199+
states are valuable only if the resource will be in that state for a sufficient
200+
period of time. If state changes are immediate, active states are not
201+
necessary.
202+
203+
- `CREATING` (usually becomes `ACTIVE`)
204+
- `DELETING` (usually becomes `DELETED`)
205+
- `PENDING` (usually becomes `RUNNING`)
206+
- `REPAIRING` (usually becomes `ACTIVE`)
207+
- `RUNNING` (usually becomes `SUCCEEDED`)
208+
- `SUSPENDING` (usually becomes `SUSPENDED`)
209+
210+
## Further reading
211+
212+
- For information on enums generally, see [enumerations](./enumerations).

aep/general/0216/aep.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
id: 216
3-
state: reviewing
3+
state: approved
44
slug: states
5-
created: 2023-01-22
5+
created: 2024-03-29
66
placement:
77
category: design-patterns

0 commit comments

Comments
 (0)