AIP-126

Enumerations

It is common for a field to only accept or provide a discrete and limited set of values. In these cases, it can be useful to use enumerations (generally abbreviated "enums") in order to clearly communicate what the set of allowed values are.

Guidance

APIs may expose enum objects for sets of values that are expected to change infrequently:

// A representation of an invoice.
message Invoice {
  // Other fields...

  // Possible delivery methods for the invoice.
  enum DeliveryMethod {
    // Default value. This value is unused.
    DELIVERY_METHOD_UNSPECIFIED = 0;

    // The invoice is delivered via email.
    EMAIL = 1;

    // The invoice is delivered via postal mail.
    POSTAL = 2;
  }

  // The delivery method of the invoice.
  DeliveryMethod delivery_method = 8;

  // Other fields...
}
  • All enum values must use UPPER_SNAKE_CASE.
  • The first value of the enum should be the name of the enum itself followed by the suffix _UNSPECIFIED.
    • An exception to this rule is if there is a clearly useful zero value. In particular, if an enum needs to present an UNKNOWN, it is usually clearer and more useful for it to be a zero value rather than having both.
  • Enum values should not be prefixed by the name of the enum itself.
    • Some languages (including C++, Go) hoist enum values into the parent namespace, which can result in conflicts for enums with the same values. To avoid sharing values, enum values should have distinctive names.
  • Enums which will only be used in a single message should be nested within that message. In this case, the enum should be declared immediately before it is used.
  • Enums which will be used by multiple messages should be defined at the package level and should be defined at the bottom of the proto file (see AIP-191).
  • Enums should document whether the enum is frozen or they expect to add values in the future.

When to use enums

Enums can be more accessible and readable than strings or booleans in many cases, but they do add overhead when they change. Therefore, enums should receive new values infrequently. While the definition of "infrequently" may change based on individual use cases, a good rule of thumb is no more than once a year. For enums that change frequently, the API should use a string and document the format.

Additionally, enums should not be used when there is a competing, widely-adopted standard representation (such as with language codes or media types).

Note: If an enumerated value needs to be shared across APIs, an enum may be used, but the assignment between enum values and their corresponding integers must match.

HTTP JSON Representation

When Protocol Buffer enums are used in HTTP JSON APIs, specific serialization rules apply. Enum values must be represented as strings in JSON, with the enum name converted to lowercase.

Default or unspecified enum values must be serialized as explicit null values in JSON responses. APIs must include all enum fields in responses, even when they contain the default/unspecified value, ensuring consistent field presence.

For unmarshaling JSON to Protocol Buffers, APIs must implement case-insensitive parsing. This ensures that clients can send enum values in any case and have them correctly mapped to the corresponding enum value.

APIs must not support filtering on the unspecified value of enums (see AIP-132).

Note: This approach replaces a legacy system where default/unspecified enum values were omitted from JSON responses.

Alternatives

For enumerated values where the set of allowed values changes frequently, APIs should use a string field instead, and must document the allowed values. String fields with enumerated values should use kebab-case for their values.

For enumerated values where there is a competing, widely-adopted standard representation (generally, but not necessarily, a string), that standard representation should be used. This is true even if only a small subset of values are permitted, because using enums in this situation often leads to frustrating lookup tables when trying to use multiple APIs together.

Boolean fields may be used in situations where it is clear that no further flexibility will be needed. The default value must be false.

Note: When using protocol buffers, it is impossible to distinguish between false and unset. If this is a requirement, an enum may be a better design choice (although google.protobuf.BoolValue is also available).

Rationale

Enum name prefixing constraints

Despite potential namespace conflicts in languages that hoist enum values (like C++ and Go), enum values are not prefixed with their enum name in protobuf definitions. This is because the implementation does not differentiate between proto names and JSON names for enum values. For example, if an enum value were named STATUS_ACTIVE, it would be serialized as "status_active" in JSON, not as "active".

In languages like Go, enum name context is lost since nested enum values are automatically prefixed with the message name but not the enum name (e.g., Invoice_ACTIVE rather than Invoice_Status_ACTIVE). For package-level enums, the enum name context is similarly lost. While prefixing enum values with the enum name might preserve this context, the JSON serialization constraints take precedence.

This approach may be revisited when the implementation allows for separate naming between proto definitions and JSON serialization.

History

Divergence from Google AIP

This AIP diverges from Google's AIP-126 in several key ways.

Specific guidance on JSON representation of enums is provided that Google's AIP does not address. Explicit null values for default/unspecified enum values in JSON responses are required, and case-insensitive parsing when unmarshaling JSON to Protocol Buffers is mandated.

Go-specific guidance on how nested enum values are prefixed is included, offering more language-specific context. Additionally, a detailed rationale section explains the constraints around enum name prefixing and JSON serialization that influenced the design.

Further reading

  • For states, a special type of enum, see AIP-216.
  • For list filtering, including enum handling, see AIP-132.

Changelog

  • 2025-05-21: Forked from Google's AIP-126, adding specific guidance on JSON representation of enums, including null handling, case-insensitive parsing, and Go-specific enum prefixing.