Chapter 9 · Volume II — The ADL Domain Language

Enumerations


9.1 Overview

Enumerations define fixed sets of allowed values for string fields. ADL supports two forms: simple enums (a list of strings) and rich enums (values with display metadata). Both forms produce identical validation behavior — the difference is in the metadata available to UI rendering and documentation.

Enums are defined in the top-level enums: block of the domain and referenced from resource fields via the enum constraint or $ref. There is no standalone type: enum — enums are a constraint on string fields, not a separate type.


9.2 Simple Enums

A simple enum is a list of allowed string values:

enums:
  PostStatus:
    values: [draft, review, published, archived]

The array syntax and the expanded syntax are equivalent:

enums:
  Priority:
    values:
      - low
      - medium
      - high
      - critical

Simple enum values have no metadata beyond their string name. They are validated on create and update — submitting a value not in the list produces HTTP 422:

{
  "status": "error",
  "code": 422,
  "error_code": "VALIDATION_ERROR",
  "errors": [
    {
      "field": "status",
      "message": "Value 'unknown' is not a valid enum value. Allowed: draft, review, published, archived",
      "rule": "enum"
    }
  ]
}

9.3 Rich Enums

A rich enum attaches display metadata to each value:

enums:
  OrderStatus:
    values:
      pending:
        label: "Pending"
        description: "Order received, awaiting processing"
        color: "#FFA500"
      processing:
        label: "Processing"
        description: "Order is being prepared"
        color: "#3B82F6"
      shipped:
        label: "Shipped"
        description: "Order has been dispatched"
        color: "#22C55E"
      delivered:
        label: "Delivered"
        description: "Order received by customer"
        color: "#008000"
        final: true
      cancelled:
        label: "Cancelled"
        description: "Order was cancelled"
        color: "#6B7280"
        final: true

Metadata Fields

KeyTypeDefaultDescription
labelstringValue nameHuman-readable display label. Used in UI dropdowns, badges, and data tables.
descriptionstring""Extended description. Used in tooltips and documentation.
colorstring""Hex color code (#RRGGBB). Used for badge backgrounds, status pills, and chart segments.
iconstring""Icon identifier. Used alongside label for visual distinction.
finalbooleanfalseIf true, marks this as a terminal value. A UI hint — it does not enforce any behavioral constraint.

All metadata fields are optional. A rich enum value with no metadata keys is functionally identical to a simple enum value.

Detection

The parser tracks whether an enum uses the simple form (array of strings) or the rich form (object with metadata). This distinction is exposed via the is_rich attribute on the EnumDefinition in the parsed domain model. UI generators can use this to switch between a flat dropdown (simple) and a colored badge selector (rich).


9.4 Referencing Enums from Fields

Enum values are applied to fields in three ways:

Inline Values

resources:
  Task:
    object:
      priority:
        type: string
        enum: [low, medium, high, critical]
        default: medium

Inline enums define the allowed values directly on the field. They are not reusable across resources and do not carry rich metadata.

Enum Name Reference

resources:
  Task:
    object:
      status:
        type: string
        enum: PostStatus
        default: draft

The enum key references a domain-level enum by name. The parser resolves the reference at parse time and attaches the allowed values to the field.

$ref Reference

resources:
  Task:
    object:
      status:
        $ref: '#/enums/PostStatus'
        default: draft

The $ref form is preferred when the enum carries rich metadata, because the resolved field inherits the full enum definition including labels, colors, and descriptions. Sibling keys (like default) override the resolved definition.

All Three Forms Are Equivalent

All three referencing forms produce identical validation behavior at runtime. The stored field value is always a plain string (e.g., "draft"). The metadata (labels, colors) is available through the schema introspection endpoint and the OpenAPI spec, not in the data record itself.


9.5 Enum Validation

Enum validation is enforced on every create and update operation. The runtime checks that the submitted value is a member of the allowed value set. The comparison is exact-match and case-sensitive — "Draft" does not match "draft".

Validation Timing

OperationBehavior
CreateValue MUST be in the allowed set, or the field MUST have a default.
Update (PATCH)If the field is included in the request body, the value MUST be in the allowed set. If the field is omitted, the existing value is unchanged.
Update (PUT)Value MUST be in the allowed set, or the field MUST have a default (since PUT replaces all fields).

Null Handling

If the enum field is not required, a null value is accepted regardless of the allowed set. Null means “no value selected” — it is not an enum member.


9.6 OpenAPI Extensions

The OpenAPI generator includes rich enum metadata in the generated specification using extension fields:

{
  "type": "string",
  "enum": ["pending", "processing", "shipped", "delivered", "cancelled"],
  "x-enum-descriptions": {
    "pending": "Order received, awaiting processing",
    "processing": "Order is being prepared",
    "shipped": "Order has been dispatched",
    "delivered": "Order received by customer",
    "cancelled": "Order was cancelled"
  },
  "x-enum-colors": {
    "pending": "#FFA500",
    "processing": "#3B82F6",
    "shipped": "#22C55E",
    "delivered": "#008000",
    "cancelled": "#6B7280"
  },
  "x-enum-labels": {
    "pending": "Pending",
    "processing": "Processing",
    "shipped": "Shipped",
    "delivered": "Delivered",
    "cancelled": "Cancelled"
  }
}

These extensions are non-standard OpenAPI (prefixed with x-) and are consumed by UI generators to render colored badges, labeled dropdowns, and status indicators. Standard OpenAPI consumers ignore them.

The schema introspection endpoint (GET /api/v1/domains/:name/schema) also includes the full enum metadata in the resource’s field definitions.


9.7 Enums and State Machines

Enums and state machines are related but distinct concepts:

AspectEnum FieldState Machine Field
Allowed valuesFixed set, any value on any writeFixed set, transitions define legal movements
TransitionsNone — any value can be set at any timeGuarded — only declared transitions from the current state
Side effectsNonesets, requiredFields, on_enter/on_exit hooks
API surfaceStandard PATCH/PUTPOST /:id/transitions/{name}
ValidationValue must be in the setTransition must be valid from current state

An enum field is appropriate when any value can be set at any time (e.g., priority: [low, medium, high]). A state machine is appropriate when values represent a lifecycle with ordered progressions and business rules (e.g., status: draft → review → published). See §12 for state machine specification.

A state machine field often uses an enum to define its allowed states, but the state machine adds transition rules, guards, and side effects on top of the enum’s value constraint.


9.8 Enum Design Patterns

Status Enums with Terminal States

Use final: true to mark values that represent completed lifecycles:

enums:
  TicketStatus:
    values:
      open:       { label: "Open",       color: "#3B82F6" }
      inProgress: { label: "In Progress", color: "#F59E0B" }
      resolved:   { label: "Resolved",   color: "#22C55E", final: true }
      closed:     { label: "Closed",     color: "#6B7280", final: true }

The final flag is a UI hint — it signals that records in this state are “done” and MAY be visually de-emphasized, excluded from active counts, or filtered by default. It does not enforce any behavioral constraint at the API level.

Color Palette Consistency

Use a consistent color palette across enums in the same domain:

SemanticColorHex
Informational / neutralGray#6B7280
Active / in progressBlue#3B82F6
Warning / attentionAmber#F59E0B
Success / completeGreen#22C55E
Error / rejectedRed#EF4444
Pending / waitingOrange#F97316

Shared vs Inline

Promote an enum to the domain-level enums: block when:

  • It is referenced by 2+ resources
  • It carries rich metadata (labels, colors)
  • It represents a domain concept that may be referenced in state machines, reports, or dashboards

Keep an enum inline when:

  • It is used by exactly one field on one resource
  • It is a simple constraint with no display metadata
  • It is unlikely to change or be referenced elsewhere

End of Chapter 9.

Next: Chapter 10 — Shared Objects & Composition