Schema Definitions in AaC¶
AaC employs a set of specialized definitions, all of which are defined with the schema
, to establish data structures within the AaC Domain-Specific Language (DSL). These schema
-defined data structures encompass various forms, such as internal and external message formats, inputs and outputs for modeled behaviors, custom structures for plugin developers or user libraries, and other essential data constructs needed for your team’s modeling activities.
In the AaC DSL, every definition has its structure defined by a schema
definition, which permits users to tailor the language to their team’s requirements and even craft new DSLs or extensions within AaC.
Users can define these extensions locally in their user-defined AaC files, or they can leverage plugins and user libraries for common structures and functionalities shared across teams and repositories.
Required Fields¶
Fields defined in a schema
definition can be marked as required, meaning that any implementation of that schema MUST contain that field. This is accomplished by setting the is_required
boolean field to true
.
In the definition below, Enum
, the field values
is marked as required. An Enum
MUST include at least one value in the values
field to be a valid definition.
schema:
name: Enum
package: aac.lang
extends:
- package: aac.lang
name: AacType
root: enum
description: |
A definition that represents an enumerated type of value.
An example of when to use an 'enum' is when you want to provide several
different options for a single value.
fields:
- name: values
type: string[]
description: |
A list of strings that encompass the enumeration's possible values.
is_required: true
Utilizing Schema Definitions¶
Schema
definitions serve multiple roles in the AaC DSL. Some examples are provided below for common use cases: crafting message interfaces, custom data structures, and defining new definition instance types.
Crafting Message Interfaces¶
Interface message structures provide structures for communication within your system or between system components. Using schema
s one can define payloads exchanged with external systems, software applications, external actors, input for plugins, and intricate data inputs for constraint purposes. Leveraging a schema
definition as part of a model
definition’s behavior.input
or behavior.output
, the schema
acts as an interface message, documenting the data structure flowing into or out of a component within your modeled system. A useful way of documenting software application behavior inputs or outputs.
In our Alarm Clock model example, the behavior
entry defines the input and behavior of our Alarm Clock model. The behavior
contains an input
named targetTime
, which is a schema
-defined data structure named Timestamp
representing information needed to set the alarm.
model:
name: AlarmClock
description: A simple alarm clock
components:
- name: clock
model: Clock
- name: timer
model: ClockTimer
- name: alarm
model: ClockAlarm
behavior:
- name: setAlarm
description: Set the alarm timer
input:
- name: targetTime
type: Timestamp
acceptance:
- name: Modify Timer State
scenarios:
- name: Set timer
given:
- The alarm timer is not set
when:
- The user sets the alarm timer
then:
- The alarm is triggered when the clock reaches the specified time
- name: Update timer
given:
- The alarm timer is set
when:
- The user sets the alarm timer
then:
- The alarm is triggered when the clock reaches the specified time
The Timestamp
schema
definition below outlines the fields required to define an exact alarm time.
---
schema:
name: Timestamp
package: alarm_clock
fields:
- name: hour
type: int
- name: minute
type: int
- name: second
type: int
- name: year
type: int
- name: month
type: int
- name: day
type: int
- name: timezone
type: TimezoneOffset
While this example is simplified and not representative of a software system, the same approach applies to defining user requests, events from message queues, Swift XML messages in financial applications, or any other input/output data structure within your modeled system.
Crafting Custom Data Structures¶
Given AaC’s self-defining nature, users can employ the schema
definition to craft their own data structures by using the schema
root key. Timestamp
serves as an example of a defined data structure with a schema
root key that can be referenced by name
, as demonstrated in the Alarm Clock model’s behavior
, or used as a component in more intricate data structures.
schema:
name: Timestamp
package: alarm_clock
fields:
- name: hour
type: int
- name: minute
type: int
- name: second
type: int
- name: year
type: int
- name: month
type: int
- name: day
type: int
- name: timezone
type: TimezoneOffset
model:
name: AlarmClock
description: A simple alarm clock
components:
- name: clock
model: Clock
- name: timer
model: ClockTimer
- name: alarm
model: ClockAlarm
behavior:
- name: setAlarm
description: Set the alarm timer
input:
- name: targetTime
type: Timestamp
acceptance:
- name: Modify Timer State
scenarios:
- name: Set timer
given:
- The alarm timer is not set
when:
- The user sets the alarm timer
then:
- The alarm is triggered when the clock reaches the specified time
- name: Update timer
given:
- The alarm timer is set
when:
- The user sets the alarm timer
then:
- The alarm is triggered when the clock reaches the specified time
Constructing Complex Data Structures via Composition¶
Each schema
definition in AaC outlines a set of fields for the definition. These fields can be primitive types as per the AaC DSL, custom enum types, or references to other schema
definitions. When a schema
definition references other schema
definitions within its field types, it assembles more intricate data structures through composition. In our Alarm Clock model example, the definition TimerAlert
references Timestamp
as a field type.
schema:
name: TimerAlert
package: alarm_clock
root: timer_alert
description: Data structure for timer alerts.
fields:
- name: name
type: string
- name: triggeredTime
type: Timestamp
- name: alarmNoise
type: AlarmNoise
Introducing New Definition Types¶
AaC permits users to define new instances of custom data structures. In our Alarm Clock example, you might want to model individual instances of TimerAlert
with varying dates and alarm sounds. To do this, you specify the root
field on the schema to be the YAML root tag to use when declaring instances of your new type. The following example demonstrates how to set the root
field to allow timer_alert
to be used as a YAML root for declaring TimerAlert
instances.
schema:
name: TimerAlert
package: alarm_clock
root: timer_alert
description: Data structure for timer alerts.
fields:
- name: name
type: string
- name: triggeredTime
type: Timestamp
- name: alarmNoise
type: AlarmNoise