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
| Key | Type | Default | Description |
|---|---|---|---|
label | string | Value name | Human-readable display label. Used in UI dropdowns, badges, and data tables. |
description | string | "" | Extended description. Used in tooltips and documentation. |
color | string | "" | Hex color code (#RRGGBB). Used for badge backgrounds, status pills, and chart segments. |
icon | string | "" | Icon identifier. Used alongside label for visual distinction. |
final | boolean | false | If 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
| Operation | Behavior |
|---|---|
| Create | Value 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:
| Aspect | Enum Field | State Machine Field |
|---|---|---|
| Allowed values | Fixed set, any value on any write | Fixed set, transitions define legal movements |
| Transitions | None — any value can be set at any time | Guarded — only declared transitions from the current state |
| Side effects | None | sets, requiredFields, on_enter/on_exit hooks |
| API surface | Standard PATCH/PUT | POST /:id/transitions/{name} |
| Validation | Value must be in the set | Transition 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:
| Semantic | Color | Hex |
|---|---|---|
| Informational / neutral | Gray | #6B7280 |
| Active / in progress | Blue | #3B82F6 |
| Warning / attention | Amber | #F59E0B |
| Success / complete | Green | #22C55E |
| Error / rejected | Red | #EF4444 |
| Pending / waiting | Orange | #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