Lessons learned from API client generation - 02 Enumerations

Oct 1, 2022

First pattern of our series: enumerations. They are essential to any programing language to describe a discrete set of options. Consider the following examples:

components:
  schemas:
    Model:
      type: object
      properties:
        enumString:
          type: string
          enum:
          - value1
          - value2
        enumInteger:
          type: integer
          enum:
          - 1
          - 2
        enumBoolean:
          type: boolean
          enum:
          - true
          - false

EnumString describes two possible values, however it’s missing a lot of information:

  • We can’t specify a different serialization value from the symbol.
  • We can’t specify a description which would be helpful to developers who discover the API surface through a client.

EnumInteger describes an integer type enumeration, where each option is a number. While this is a valid scenario, it makes code generation harder as most programming languages don’t accept numbers or strings starting with numbers as valid symbols which leads to compilation errors. Additionally, if the enumeration values are powers of 2, the enumeration is flaggable (supports compounded values through a bitwise or). But we have no way to convey this information.

EnumBoolean is a Boolean type enumeration. In my opinion, it is completely useless. A boolean is an enumeration that can only hold two possible values.

Suggestions

Interestingly enough, autorest already has an extension defined to bridge some of those gaps and I believe the solution should be based on that early work. First, we need to introduce the placeholder for the missing information, and if possible, avoid breaking existing descriptions out there. The enum property should be extended in the OpenAPI JSON schema vocabulary to be an array of symbols (like it is today) or an object with the following properties:

  • Items, array of objects (value, name, description).
  • Composable (Boolean).
  • Description.
  • Summary.

Second, we must encourage people to do the right thing when describing their APIs and I think linting tools like spectral should introduce the following rules:

  • Error if the description contains an enum of type Boolean, just use a Boolean.
  • Error if the description contains a number enum item without the name property we introduced above.
  • Error if the description contains a composable enum, but the values are not powers of 2.
  • Warning if enum items don’t have descriptions.

The resulting enum would look like this:

components:
  schemas:
    Model:
      type: object
      properties:
        enumInteger:
          type: integer
          default: 1
          enum:
          - 1
          - 2
          x-ms-enum:
            name: EnumInteger
            flags: true # this doesn't exist in the extension today
            values:
            - value: 1
              name: Value1
              description: Value 1
            - value: 2
              name: Value2
              description: Value 2

Last edited Apr 15, 2024 by Vincent Biret


Tags: