Skip to main content
Adopt

IPA-123: Enums

By leveraging enumerations (enums) whenever a field only accepts a discrete set of values and documenting those values, an API communicates to consumers the expectation for that data field.

Guidance

  1. API producers should use enumeration objects for sets of values for a field that are expected to remain relatively static.

    components:
    schemas:
    Order:
    type: object
    properties:
    status:
    type: string
    enum:
    - PENDING
    - SHIPPED
    - DELIVERED
    Why:

    The set of order statuses is small and stable, so an enum documents the exact values a consumer can expect and lets tooling validate them.

    components:
    schemas:
    Order:
    type: object
    properties:
    status:
    type: string
    description: One of PENDING, SHIPPED, or DELIVERED.
    Why:

    The allowed values live only in prose, so nothing validates them and tooling cannot generate a typed value set from a fixed, stable list.

    1. For each schema under $.components.schemas, list the string properties that accept a fixed set of values.

    2. For each such property, check whether the allowed values are declared as an enum or only described in the description text.

    3. Decide whether the value set is expected to stay relatively static, using the property name, description, and any example.

    4. Flag any property with a small, stable value set whose values are documented only in prose rather than as an enum.

  2. API producers may include additional documentation explaining each of the allowable values.

  3. Enumeration values must be UPPER_SNAKE_CASE.

    status:
    type: string
    enum:
    - IN_PROGRESS
    - ON_HOLD
    - COMPLETED
    Why:

    Every value uses uppercase letters with underscores between words, so the casing is consistent across the whole API.

    status:
    type: string
    enum:
    - inProgress
    - on-hold
    - Completed
    Why:

    The values mix camelCase, kebab-case, and capitalized words, so casing is inconsistent and harder to predict across endpoints.

  4. API producers should default to making enums extensible, so new values can be added freely.

    priority:
    type: string
    description: >
    Priority of the task. Additional values may be added over time; clients
    should tolerate values they do not recognize.
    enum:
    - LOW
    - MEDIUM
    - HIGH
    Why:

    Treating the enum as extensible means a later value such as URGENT can be added without forcing a breaking change on existing clients.

    priority:
    type: string
    description: >
    Priority of the task. These are the only values that will ever exist and
    clients may reject anything else.
    enum:
    - LOW
    - MEDIUM
    - HIGH
    Why:

    Declaring the set permanently closed leaves no room to grow, so adding any future value becomes a breaking change.

    1. For each enum-typed property in $.components.schemas, read its description and any client-facing documentation.

    2. Determine whether the documentation treats the value set as fixed and closed or as open to future additions.

    3. Flag enums that are documented as permanently closed without a stated reason that the set is genuinely fixed.

  5. Enums must not be extended in a non-compatible fashion, such as splitting one existing value into two.

    state:
    type: string
    enum:
    - ACTIVE
    - SUSPENDED
    - ACTIVE_TRIAL
    Why:

    A new value is appended while the existing values keep their meaning, so a consumer that already handles ACTIVE is unaffected.

    state:
    type: string
    enum:
    - ACTIVE_PAID
    - ACTIVE_TRIAL
    - SUSPENDED
    Why:

    The previous ACTIVE value was split into ACTIVE_PAID and ACTIVE_TRIAL, so a value a consumer relied on disappears and existing integrations break.

    1. Identify the enum and retrieve its previously published value set from version control history or the prior released spec.

    2. Compare the current values against the previous set: list values that were added, removed, or renamed.

    3. For each removed or renamed value, check whether its meaning was redistributed across two or more new values.

    4. Report any change where a previously published value was removed, renamed, or split, since each breaks consumers that depended on the old value.

  6. API producers should use a string field rather than an enum when the set of allowable values exceeds 20.

    regionCode:
    type: string
    description: >
    Identifier of the region. The list of allowed values is extensive (>20);
    refer to the API documentation for the current list.
    example: NORTH_AMERICA_EAST
    Why:

    With more than 20 possible values, a free-form string with documented values avoids an unwieldy enum that must change every time a value is added.

    regionCode:
    type: string
    enum:
    - REGION_01
    - REGION_02
    - REGION_03
    # ...continues past 20 entries
    - REGION_25
    Why:

    An enum with more than 20 entries is hard to maintain and grows with every new region, so a documented string is the better fit.

  7. API producers should use a string field rather than an enum when the set of allowable values changes often.

    categoryCode:
    type: string
    description: >
    Identifier of the document category. The list of allowed values changes
    frequently; refer to the API documentation for the current list.
    example: FINANCE_REPORT
    Why:

    A frequently changing value set modeled as a documented string avoids a spec change for every new category, which an enum would require.

    categoryCode:
    type: string
    enum:
    - FINANCE_REPORT
    - HR_POLICY
    - LEGAL_NOTICE
    Why:

    The category set turns over frequently, so pinning it to an enum forces a breaking spec change each time a category is added or retired.

    1. For each enum-typed property in $.components.schemas, gather how often its value set has changed across recent spec revisions.

    2. Use the property description and release history to judge whether the values turn over frequently.

    3. Flag any enum whose value set changes often, since a documented string field is the better model for it.

  8. When a string field is used in place of an enum, API producers must document the allowable values.

    categoryCode:
    type: string
    description: >
    Identifier of the document category. Refer to the API documentation for the
    current list of allowed values.
    example: FINANCE_REPORT
    externalDocs:
    description: Current list of allowed category codes
    url: https://example.com/docs/category-codes
    Why:

    The description and externalDocs point a consumer to the authoritative list, so the allowable values remain discoverable even though they are not enumerated.

    categoryCode:
    type: string
    Why:

    The string carries no description, example, or link to the allowed values, so a consumer has no way to know which values are valid.

    1. For each schema under $.components.schemas, find string properties that stand in for an enum because the value set is large or changes often.

    2. For each such property, check that the allowable values are documented through the description, an example, or an externalDocs link to the current list.

    3. Flag any such string property that omits documentation of its allowable values.

  9. The API must not accept invalid enum values and silently modify them to make them valid; instead it returns a validation error (see Validation Errors).

    # Request body sends status: "open"
    # Response:
    status: 400
    body:
    error: VALIDATION_ERROR
    detail: "status must be one of: OPEN, CLOSED"
    Why:

    An invalid value is rejected with a validation error, so the caller learns the input was wrong rather than having it changed without notice.

    # Request body sends status: "open"
    # Response:
    status: 200
    body:
    status: OPEN
    Why:

    The invalid open is silently coerced to OPEN, so the caller never learns the input was wrong and the silent rewrite can mask real client bugs.

    1. Enumerate the enum-typed request fields and their declared value sets.

    2. From the source or by exercising the endpoint, submit a value that is invalid only by casing or formatting, such as a lowercase variant of a valid value.

    3. Inspect the response: confirm the request is rejected with a validation error rather than accepted and normalized to a valid value.

    4. Report any endpoint that rewrites an invalid enum value into a valid one instead of returning a validation error.