AIP-149

Unset field values

In many messages, many fields are optional: the user is not required to provide them, or for output fields, the service might not populate the field.

In most cases, there is no meaningful difference between setting it to a default value (such as 0) as opposed to not setting it at all; however, occasionally this distinction is meaningful.

Guidance

Services defined in protocol buffers should use the optional keyword for primitives if and only if it is necessary to distinguish setting the field to its default value (0, false, or empty string) from not setting it at all:

// A representation of a book in a library.
message Book {
  option (google.api.resource) = {
    type: "library.googleapis.com/Book"
    pattern: "publishers/{publisher}/books/{book}"
  };

  // The name of the book.
  string name = 1 [(google.api.field_behavior) = IDENTIFIER];

  // The rating for the book, from 0 to 5.
  // 0 is distinct from no rating.
  optional int32 rating = 2;
}

Important: Services should not need to distinguish between the default value and unset most of the time; if an alternative design does not require such a distinction, it is usually preferred. In practice, this means optional should only ever be used for integers and floats.

Important: Tracking field presence is not the same as documenting API field behavior as defined in AIP-203. For example, a field labeled with optional for presence tracking may also be annotated as google.api.field_behavior = REQUIRED if the field must be set. If you only want to document the server perceived behavior of a field, read AIP-203.

Backwards compatibility

It is a backwards incompatible change to add or remove the optional qualifier to an existing field. This is because the compiled src API is changed (in some languages). For example, in Golang, adding optional changes the field type of primitives to be the pointer variant of their original type, e.g. a field formerly of type string becomes *string, etc. Accordingly, this change requires that both clients and servers update their usage of the changed field in unison, which is risky and error prone. Additional information is documented by Protobuf.

Rationale

field behavior and optional

The field behavior annotation and optional label are not mutually exclusive, because they address different problems. The former, google.api.field_behavior, focuses on communicating the server's perception of a field within the API e.g. if it is required or not, if it is immutable, etc. The latter, proto3's optional, is a wire format and code generation option that is strictly for toggling field presence tracking. While it might be confusing for a field to be simultaneously annotated with google.api.field_behavior = REQUIRED and labeled as optional, they are unrelated in practice and can reasonably be used together.

Changelog

  • 2024-06-05: Add backwards compatibility considerations
  • 2023-06-20: Differentiate from field behavior documentation