|
| 1 | +# Enumerations |
| 2 | + |
| 3 | +It is common for a field to only accept or provide a discrete and limited set |
| 4 | +of values. In these cases, it can be useful to use enumerations (generally |
| 5 | +abbreviated "enums") in order to clearly communicate what the set of allowed |
| 6 | +values are. |
| 7 | + |
| 8 | +## Guidance |
| 9 | + |
| 10 | +APIs **may** expose enum objects for sets of values that are expected to change |
| 11 | +infrequently: |
| 12 | + |
| 13 | +```typescript |
| 14 | +// Possible formats in which a book may be published. |
| 15 | +enum Format { |
| 16 | + // The printed format, in hardback. |
| 17 | + Hardback = 'HARDBACK', |
| 18 | + |
| 19 | + // The printed format, in paperback. |
| 20 | + Paperback = 'PAPERBACK', |
| 21 | + |
| 22 | + // An electronic book format. |
| 23 | + Ebook = 'EBOOK', |
| 24 | + |
| 25 | + // An audio recording. |
| 26 | + Audiobook = 'AUDIOBOOK', |
| 27 | +} |
| 28 | +``` |
| 29 | + |
| 30 | +- All enum values **should** use a consistent case format across an |
| 31 | + organization. In many cases, this is dictated by the IDL the organization |
| 32 | + uses. |
| 33 | +- Enums **should** document whether the enum is frozen or they expect to add |
| 34 | + values in the future. |
| 35 | + |
| 36 | +### When to use enums |
| 37 | + |
| 38 | +Enums can be more accessible and readable than strings or booleans in many |
| 39 | +cases, but they do add overhead when they change. Therefore, enums **should** |
| 40 | +receive new values infrequently. While the definition of "infrequently" may |
| 41 | +change based on individual use cases, a good rule of thumb is no more than once |
| 42 | +a year. For enums that change frequently, the API **should** use a string and |
| 43 | +document the format. |
| 44 | + |
| 45 | +**Note:** If an enumerated value needs to be shared across APIs, an enum |
| 46 | +**may** be used, but the assignment between enum values and their wire |
| 47 | +representation **must** match. |
| 48 | + |
| 49 | +### Alternatives |
| 50 | + |
| 51 | +Enums **should not** be used when there is a competing, widely-adopted standard |
| 52 | +representation (such as with [language codes][bcp-47] or [media types][]). |
| 53 | +Instead, that standard representation **should** be used. This is true even if |
| 54 | +only a small subset of values are permitted, because using enums in this |
| 55 | +situation often leads to frustrating lookup tables when trying to use multiple |
| 56 | +APIs together. |
| 57 | + |
| 58 | +For enumerated values where the set of allowed values changes frequently, APIs |
| 59 | +**should** use a `string` field instead, and **must** document the allowed |
| 60 | +values. String fields with enumerated values **should** use a uniform case |
| 61 | +system (`snake_case`, `kebab-case`, etc.) throughout an organization. |
| 62 | + |
| 63 | +Boolean fields **may** be used in situations where it is clear that no further |
| 64 | +flexibility will be needed. The default value **must** be `false`. |
| 65 | + |
| 66 | +### Compatibility |
| 67 | + |
| 68 | +Adding values to an enum has the potential to be disruptive to existing |
| 69 | +clients. Consider code written against the `Format` enum in an earlier version |
| 70 | +where only the first two options were available: |
| 71 | + |
| 72 | +```typescript |
| 73 | +switch (book.format) { |
| 74 | + case Format.Hardback: |
| 75 | + // Do something... |
| 76 | + break; |
| 77 | + case Format.Paperback: |
| 78 | + // Do something... |
| 79 | + break; |
| 80 | + default: |
| 81 | + // When new enum values are introduced, pre-existing client code may |
| 82 | + // throw errors or act in unexpected ways. |
| 83 | + throw new Error('Unrecognized value.'); |
| 84 | +} |
| 85 | +``` |
| 86 | + |
| 87 | +Services **may** add new values to existing enums; however, they **should** add |
| 88 | +enums carefully; think about what will happen if a client system does not know |
| 89 | +about a new value. |
| 90 | + |
| 91 | +Additionally, in IDLs where enum values are presented in a specific order, |
| 92 | +services **should** only add new values to the end. An exception to this rule |
| 93 | +is if the enum conforms to an external standard (for example, an enum |
| 94 | +representing HTTP status codes would add a new 3xx value alongside the others, |
| 95 | +not at the end). |
| 96 | + |
| 97 | +## Interface Definitions |
| 98 | + |
| 99 | +{% tab proto %} |
| 100 | + |
| 101 | +{% sample 'enum.proto', 'enum Format' %} |
| 102 | + |
| 103 | +- The zero value of the enum **should** be the name of the enum itself followed |
| 104 | + by the suffix `_UNSPECIFIED`. The service **may** either allow or prohibit |
| 105 | + use of this value. |
| 106 | +- Enums which will only be used in a single message **should** be nested within |
| 107 | + that message. In this case, the enum **should** be declared immediately |
| 108 | + before it is used. |
| 109 | +- If multiple enums are in the same namespace, they **must not** share any |
| 110 | + values. (This is because enums do not provide their own namespace for their |
| 111 | + values in some languages.) |
| 112 | +- If an enumerated value needs to be shared across APIs, an enum **may** be |
| 113 | + used, but the assignment between the value names and the tag numbers **must** |
| 114 | + match. |
| 115 | + |
| 116 | +**Note:** When using protocol buffers, it is impossible to distinguish between |
| 117 | +`false` and unset. If this is a requirement, an enum **may** be a better design |
| 118 | +choice (although `google.protobuf.BoolValue` is also available). |
| 119 | + |
| 120 | +{% tab oas %} |
| 121 | + |
| 122 | +{% sample 'enum.oas.yaml', 'format' %} |
| 123 | + |
| 124 | +- Enumerated fields **should** be strings. |
| 125 | +- If the enum is optional, The `null` value **should** be used as the empty |
| 126 | + value, and **should** be the first value specified. |
| 127 | + |
| 128 | +**Note:** If `null` is a valid value, OpenAPI 3.0 also requires that |
| 129 | +`nullable: true` is specified for the field. |
| 130 | + |
| 131 | +{% endtabs %} |
| 132 | + |
| 133 | +## Further reading |
| 134 | + |
| 135 | +- For states, a special type of enum, see AIP-216. |
| 136 | + |
| 137 | +[bcp-47]: https://en.wikipedia.org/wiki/IETF_language_tag |
| 138 | +[media types]: https://en.wikipedia.org/wiki/Media_type |
0 commit comments