AIP-216

States

Many API resources carry a concept of “state”: ordinarily, the resource’s place in its life cycle. For example, a virtual machine may be being provisioned, available for use, being spun down, or potentially be in one of several other situations. A job or query may be preparing to run, be actively running, have completed, and so on.

Guidance

Resources needing to communicate their state should use an enum, which should be called State (or, if more specificity is required, end in the word State). This enum should be nested within the message it describes when only used as a field within that message.

Important: We use the term State, and not Status (which is reserved for the HTTP and gRPC statuses).

Enum values

Ideally, Google APIs use the same terminology throughout when expressing the same semantic concepts. There are usually many words available to express a given state, but our customers often use multiple APIs together, and it is easier for them when our terms are consistent.

At a high level:

  • Resources that are available for use are ACTIVE (preferred over terms such as “ready” or “available”).
  • Resources that have completed a (usually terminal) requested action use past participles (usually ending in -ED), such as SUCCEEDED (not “successful”), FAILED (not “failure”), DELETED, SUSPENDED, and so on.
  • Resources that are currently undergoing a state change use present participles (usually ending in -ING), such as RUNNING, CREATING, DELETING, and so on. In this case, it is expected that the state is temporary and will resolve to another state on its own, with no further user action.

Note: Remember to only add states that are useful to customers. Exposing a large number of states simply because they exist in your internal system is unnecessary and adds confusion for customers. Each state must come with a use case for why it is necessary.

A list of commonly used enum values for states is in the appendix of this document.

Output only

The field referencing the State enum in a resource should behave and be documented as “Output only”, in accordance with AIP-203.

APIs should not allow a State enum to be directly updated through an “update” method, and should instead use a custom state transition method.

This is because update methods are generally not expected to have side effects, and also because updating state directly implies that it is possible to set the state to any available value, whereas states generally reflect a resource’s progression through a lifecycle.

State transition methods

State transition methods are a special type of custom method that are responsible for transitioning a state field from one enum value to another. As part of the transition, other fields may also change, e.g. an update_time field. The method definition should look like the following:

// Publishes a book.
// The `state` of the book after publishing will be PUBLISHED.
// `PublishBook` can be called on Books in the state DRAFT; Books in a
// different state (including PUBLISHED) will return an error.
rpc PublishBook(PublishBookRequest) returns (Book) {
  option (google.api.http) = {
    post: "/v1/{name=publishers/*/books/*}:publish"
    body: "*"
  };
}
  • The name of the method should be a verb followed by the singular form of the resource’s message name.
  • The request message must match the RPC name, with a -Request suffix.
  • The response message must be the resource itself.
    • If the RPC is long-running, the response message must be a google.longrunning.Operation which resolves to the resource itself.
  • The HTTP verb must be POST.
  • The HTTP URI must use a : character followed by the custom verb (:publish in the above example), and the verb in the URI must match the verb in the name of the RPC.
    • If word separation is required, camelCase must be used.
  • The body clause in the google.api.http annotation must be "*".
  • The request message field receiving the resource name should map to the URL path.
    • This field should be called name.
    • The name field should be the only variable in the URI path. All remaining parameters should map to URI query parameters.
  • If the state transition is not allowed, the service must error with FAILED_PRECONDITION (HTTP 400).

The request message should look like this:

message PublishBookRequest {
  // The name of the book to publish.
  // Format: publishers/{publisher}/books/{book}
  string name = 1;
}
  • A resource name field must be included. It should be called name.
  • The comment for the field should document the resource pattern.
  • Other fields may be included.

Additional Guidance

Default value

The zero value of each state enum should adhere to the following convention:

enum State {
  // The default value. This value is used if the state is omitted.
  STATE_UNSPECIFIED = 0;

  // Other values...
}

Resources should not provide an unspecified state to users, and this value should not actually be used.

Value uniqueness

Multiple top-level enums within the same package must not share the same values. This is because the C++ protoc code generator flattens top-level enum values into a single namespace.

State enums should live inside the resource definition.

Breaking changes

TL;DR: Clearly communicate to users that state enums may receive new values in the future, and be conscientious about adding states to an existing enum.

Even though adding states to an existing states enum can break existing user code, adding states is not considered a breaking change. Consider a state with only two values: ACTIVE and DELETED. A user may add code that checks if state == ACTIVE, and in the else cases simply assumes the resource is deleted. If the API later adds a new state for another purpose, that code will break.

We ultimately can not control this behavior, but API documentation should actively encourage users to code against state enums with the expectation that they may receive new values in the future.

APIs may add new states to an existing State enum when appropriate, and adding a new state is not considered a breaking change.

When to avoid states

Sometimes, a State enum may not be what is best for your API, particularly in situations where a state has a very small number of potential values, or when states are not mutually exclusive.

Consider the example of a state with only ACTIVE and DELETED, as discussed above. In this situation, the API may be better off exposing a google.protobuf.Timestamp delete_time, and instructing users to rely on whether it is set to determine deletion.

Appendix: Common states

The following is a list of states in common use. APIs should consider prior art when determining state names, and should value local consistency above global consistency in the case of conflicting precedent.

Resting states

“Resting states” are lifecycle states that, absent user action, are expected to remain indefinitely. However, the user can initiate an action to move a resource in a resting state into certain other states (resting or active).

  • ACCEPTED
  • ACTIVE
  • CANCELLED
  • DELETED
  • FAILED
  • SUCCEEDED
  • SUSPENDED
  • VERIFIED

Active states

“Active states” are lifecycle states that typically resolve on their own into a single expected resting state.

Note: Remember only to expose states that are useful to customers. Active states are valuable only if the resource will be in that state for a sufficient period of time. If state changes are immediate, active states are not necessary.

  • CREATING (usually becomes ACTIVE)
  • DELETING (usually becomes DELETED)
  • PENDING (usually becomes RUNNING)
  • REPAIRING (usually becomes ACTIVE)
  • RUNNING (usually becomes SUCCEEDED)
  • SUSPENDING (usually becomes SUSPENDED)

Further reading

  • For information on enums generally, see AIP-126.

Changelog

  • 2019-08-16: Added guidance for state transition methods.
  • 2019-07-18: Added explicit guidance on the unspecified value.