Skip to content

Field behavior documentation

When defining fields in protocol buffers, it is customary to explain to users certain aspects of the field’s behavior (such as whether it is required or optional). Additionally, it can be useful for other tools to understand this behavior (for example, to optimize client library signatures).

Guidance

APIs use the aep.api.field_behavior annotation to describe well-understood field behavior, such as a field being required or immutable.

// The audio data to be recognized.
RecognitionAudio audio = 2 [(aep.api.field_behavior) = REQUIRED];
  • APIs must apply the aep.api.field_behavior annotation on every field on a message or sub-message used in a request.
  • The annotation must include any google.api.FieldBehavior values that accurately describe the behavior of the field.
    • FIELD_BEHAVIOR_UNSPECIFIED must not be used.
  • APIs must at minimum use one of REQUIRED, OPTIONAL, or OUTPUT_ONLY.

field behavior of nested messages

aep.api.field_behavior annotations on a nested message are independent of the annotations of the parent.

For example, a nested message can have a field behavior of REQUIRED while the parent field can be OPTIONAL:

message Title {
string text = 1 [(aep.api.field_behavior) = REQUIRED];
}
message Slide {
Title title = 1 [(aep.api.field_behavior) = OPTIONAL];
}

In the case above, if a title is specified, the text field is required.

Vocabulary

Identifier

The use of IDENTIFIER indicates that a field within a resource message is used to identify the resource. It must be attached to the path field and must not be attached to any other field (see fields representing resource paths).

The IDENTIFIER value conveys that the field is not accepted as input (i.e. OUTPUT_ONLY) in the context of a create method, while also being considered IMMUTABLE and accepted as input for mutation methods that accept the resource as the primary input e.g. Standard Update.

This annotation must not be applied to references to other resources within a message.

Immutable

The use of IMMUTABLE indicates that a field on a resource cannot be changed after it’s creation. This can apply to either fields that are input or outputs, required or optional.

When a service receives an immutable field in an update request (or similar), even if included in the update mask, the service should ignore the field if the value matches, but should error with INVALID_ARGUMENT if a change is requested.

Potential use cases for immutable fields (this is not an exhaustive list) are:

  • Attributes of resources that are not modifiable for the lifetime of the application (e.g. a disk type).

Input only

The use of INPUT_ONLY indicates that the field is provided in requests and that the corresponding field will not be included in output.

Additionally, a field should only be described as input only if it is a field in a resource message or a field of a message included within a resource message. Notably, fields in request messages (a message which only ever acts as an argument to an RPC, with a name usually ending in Request) should not be described as input only because this is already implied.

Potential use cases for input only fields (this is not an exhaustive list) are:

  • The ttl field as described in AEP-214.

Optional

The use of OPTIONAL indicates that a field is not required.

A field may be described as optional if it is a field on a request message (a message that is an argument to an RPC, usually ending in Request), or a field on a submessage.

Output only

The use of OUTPUT_ONLY indicates that the field is provided in responses, but that including the field in a message in a request does nothing (the server must clear out any value in this field and must not throw an error as a result of the presence of a value in this field on input). Similarly, services must ignore the presence of output only fields in update field masks (see: AEP-161).

Additionally, a field should only be described as output only if it is a field in a resource message, or a field of a message farther down the tree. Notably, fields in response messages (a message which only ever acts as a return value to an RPC, usually ending in Response) should not be described as output only because this is already implied.

Output only fields may be set to empty values if appropriate to the API.

Potential use cases for output only fields (this is not an exhaustive list) are:

  • Create or update timestamps.
  • Derived or structured information based on original user input.
  • Properties of a resource assigned by the service which can not be altered.

Required

The use of REQUIRED indicates that the field must be present (and set to a non-empty value) on the request.

A field should only be described as required if either:

  • It is a field on a resource that a user provides somewhere as input.
    • When creating the resource, a value must be provided for the field on the create request.
    • When updating the resource, the user may omit the field provided that the field is also absent from the field mask, indicating no change to the field (otherwise it must be provided).
  • It is a field on a request message (a message that is an argument to an RPC, with a name usually ending in Request). In this case, a value must be provided as part of the request, and failure to do so must cause an error (usually INVALID_ARGUMENT).

Fields should not be described as required in order to signify:

  • A field which will always be present in a response.
  • A field which is conditionally required in some situations.
  • A field on any message (including messages that are resources) which is never used as user input.

Unordered List

The use of UNORDERED_LIST on a repeated field of a resource indicates that the service does not guarantee the order of the items in the list.

A field should be described as an unordered list if the service does not guarantee that the order of the elements in the list will match the order that the user sent, including a situation where the service will sort the list on the user’s behalf.

Backwards compatibility

Adding or changing aep.api.field_behavior values can represent a semantic change in the API that is perceived as incompatible for existing clients. The following are examples of backwards incompatible changes with aep.api.field_behavior:

  • Adding REQUIRED to an existing field previously considered OPTIONAL (implicitly or otherwise)
  • Adding a new field annotated as REQUIRED to an existing request message
  • Adding OUTPUT_ONLY to an existing field previously accepted as input
  • Adding INPUT_ONLY to an existing field previously emitted as output
  • Adding IMMUTABLE to an existing field previously considered mutable
  • Removing OUTPUT_ONLY from an existing field previously ignored as input
  • Removing IDENTIFIER from an existing field.

There are some changes that are backwards compatible, which are as follows:

  • Adding OPTIONAL to an existing field
  • Adding IDENTIFIER to an existing path field
  • Changing from REQUIRED to OPTIONAL on an existing field
  • Changing from OUTPUT_ONLY and/or IMMUTABLE to IDENTIFIER on an existing field
  • Removing REQUIRED from an existing field
  • Removing INPUT_ONLY from an existing field previously excluded in responses
  • Removing IMMUTABLE from an existing field previously considered immutable

Rationale

Identifier field behavior

Resource paths, the primary identifiers for any compliant resource, are never fully constructed by the user on create. Such fields are typically assigned OUTPUT_ONLY field behavior. They are, however, also often consumed as the primary identifier in scenarios where the resource itself is the primary request payload. Such fields could not be considered OUTPUT_ONLY. Furthermore, in mutation requests, like Standard Update, the resource path as the primary identifier cannot be changed in place. Such fields are typically assigned IMMUTABLE field behavior. These conflicting and context-dependent field behaviors meant that a new value was necessary to single out and convey the behavior of the resource path field.

Required set of annotations

A field used in a request message must be either an input or an output.

In the case of an output, the OUTPUT_ONLY annotation is sufficient.

In the case of an input, a field is either required or optional, and therefore should have at least the REQUIRED or OPTIONAL annotation, respectively. Only providing INPUT_ONLY does not convey the necessity of the field, so specifying either REQUIRED or OPTIONAL is still necessary.

Requiring field behavior

By including the field behavior annotation for each field, the overall behavior that the resource exhibits is more clearly defined. Clearly defined field behavior improves programmatic clients and user understanding.

Requiring the annotation also forces the API author to explicitly consider the behavior when initially authoring of the API.

Modifying field behavior after initial authoring can result in backwards-incompatible changes in clients. For example, making an optional field required results in backwards-incompatible changes in the method signature of an RPC or a resource in a Declarative client. See the Backwards compatibility section for more detailed compatibility guidance.

Changelog

  • 2024-04-17: Added initial guidance.