|
| 1 | +--- |
| 2 | +title: Asynchronous Microservice Domain-Specific Language (AsynchMDSL) |
| 3 | +author: Giacomo Di Liberali, Olaf Zimmermann |
| 4 | +copyright: The authors, 2020-2021. All rights reserved. |
| 5 | +--- |
| 6 | + |
| 7 | +[Home (Language Reference)](./index) — [MDSL Data Types](./datacontract) — [MDSL Tools](./tools) — [AsyncAPI Generator](./generators/async-api) |
| 8 | + |
| 9 | +AsyncMDSL |
| 10 | +========= |
| 11 | + |
| 12 | +_Note:_ The status of the Asynchronous Microservice Domain Specific Language (AsynchMDSL), created by Giacomo Di Liberali, is [*Technology Preview*](https://microservice-api-patterns.org/patterns/evolution/ExperimentalPreview.html), standing at Version 1.1 at present. |
| 13 | + |
| 14 | +AsyncMDSL aims at modeling asynchronous, messaging APIs while exploiting the [design goals of core MDSL](./index). Extending core MDSL, AsyncMDSL derives its abstract syntax from the state-of-the-art patterns and concepts described in the [Enterprise Integration Patterns](https://www.enterpriseintegrationpatterns.com/) book. The language is fully specified in Giacomo Di Liberali's [master thesis](UNIPI-AsyncMDSL-MasterThesis-2020-GiacomoDeLiberali-v1.3.pdf). |
| 15 | + |
| 16 | +## Use Cases |
| 17 | + |
| 18 | +AsyncMDSL can be used to model scenarios where communication between systems is accomplished by the use of queue-based *messaging*, i.e., systems are not communicating through synchronous calls. In this asynchronous context, indeed, a request might not expect a reply, and message producers might not know the message consumers because *channels* and *message brokers* decouple them from each other. |
| 19 | + |
| 20 | +## Concepts |
| 21 | + |
| 22 | +An AsyncMDSL document uses the same structure as core MDSL, including its [data transfer representations](./datacontract): |
| 23 | + |
| 24 | +~~~ |
| 25 | +API description HelloWorldAPI |
| 26 | +
|
| 27 | +data type SampleDTO {ID, D} |
| 28 | +
|
| 29 | +channel SayHello |
| 30 | +of type PUBLISH_SUBSCRIBE |
| 31 | +on path "/public/sayHello" |
| 32 | +produces message HelloMessage |
| 33 | + delivering payload SampleDTO |
| 34 | +
|
| 35 | +message broker HelloWorldAmqpProvider |
| 36 | +exposes SayHello |
| 37 | +at location "amqp.example.com" |
| 38 | +via protocol AMQP |
| 39 | +
|
| 40 | +message endpoint HelloWorldAmqpClient |
| 41 | +uses from HelloWorldAmqpProvider: |
| 42 | + SayHello |
| 43 | +~~~ |
| 44 | + |
| 45 | +The example defines an API which has a single channel, `SayHello`, to which many [Message Endpoints](https://www.enterpriseintegrationpatterns.com/patterns/messaging/MessageEndpoint.html) can consume from. The channel is a [Publish-Subscribe Channel](https://www.enterpriseintegrationpatterns.com/patterns/messaging/PublishSubscribeChannel.html) and delivers a `SampleDTO` as output to subscribers. A Message Broker exposes the `SayHello` channel via AMQP protocol, and the Message Endpoint `HelloWorldAmqpClient` uses the channel from this broker (i.e., consumes messages from it). <!-- where do the messages come from? --> |
| 46 | + |
| 47 | +### Message Channels |
| 48 | + |
| 49 | +~~~ |
| 50 | +channel [name] |
| 51 | +of type [type] |
| 52 | +delivery guarantee [deliveryGuarantee] // optional, default UNKNOWN |
| 53 | +description [description] // optional |
| 54 | +on path [path] |
| 55 | + with // optional path parameters |
| 56 | + [pathParamName]: [pathParamType], [pathParamDescription], |
| 57 | + [...] |
| 58 | +produces message [messageName] // or accepts [and produce] |
| 59 | + description [messageDescription] |
| 60 | + delivering // or expecting |
| 61 | + headers [...] // optional |
| 62 | + payload [...] // mandatory, e.g., {V} |
| 63 | + as [messageIntent] // optional |
| 64 | + where // optional message constraints |
| 65 | + [expression], |
| 66 | + [...] |
| 67 | +bindings for [protocol] { |
| 68 | + // JSON object |
| 69 | +} |
| 70 | +~~~ |
| 71 | + |
| 72 | +#### Root |
| 73 | + |
| 74 | +- |
| 75 | + A channel type can assume one (or a combination of) the following values: |
| 76 | + > POINT_TO_POINT | PUBLISH_SUBSCRIBE | DATA_TYPE |
| 77 | + > INVALID_MESSAGE | DEAD_LETTER | GUARANTEED_DELIVERY |
| 78 | + |
| 79 | + Invalid combinations will be notified by the API Linter that comes with the [editor and generator plugin](./generators/async-api) for ASyncMDSL. |
| 80 | + |
| 81 | +- |
| 82 | + A channel deliveryGuarantee can be any of: |
| 83 | + > UNKNOWN | AT_LEAST_ONCE | AT_MOST_ONCE | EXACTLY_ONCE |
| 84 | + |
| 85 | +#### Channel path |
| 86 | + |
| 87 | +- |
| 88 | + A path param type can assume any of teh basic data types of MDSL: |
| 89 | + > bool | int | long | double | string |
| 90 | + |
| 91 | +#### Message |
| 92 | + |
| 93 | +- |
| 94 | + A message intent can assume one of the following three [EIP patterns](https://www.enterpriseintegrationpatterns.com/patterns/messaging/MessageConstructionIntro.html): |
| 95 | + > COMMAND_MESSAGE | EVENT_MESSAGE | DOCUMENT_MESSAGE |
| 96 | + |
| 97 | +- A `WHERE` expression can specify: |
| 98 | + > MESSAGE_EXPIRES in [number] `s | m` (where `s` stands for _seconds_ and `m` for _minutes_) |
| 99 | +
|
| 100 | + > CORRELATION_ID is [payloadExpression] |
| 101 | + |
| 102 | + > SEQUENCE_ID is [payloadExpression] |
| 103 | + |
| 104 | + `payloadExpression` has the format `$message.(payload | header)#/path/to/property` (from AsyncAPI). More examples are [here](https://www.asyncapi.com/docs/specifications/2.0.0#runtimeExpression). |
| 105 | + |
| 106 | + |
| 107 | +#### Bindings |
| 108 | + |
| 109 | +- Protocol can assume one of the [supported protocols](./bindings). As the list of properties is protocol-specific, a single flat JSON object is expected as configuration. |
| 110 | + |
| 111 | +An example of a _binding_ definition can be found in [examples/AsyncMDSL/bindings.mdsl](../examples/AsyncMDSL/bindings.mdsl). |
| 112 | + |
| 113 | +#### Channel definition example |
| 114 | + |
| 115 | +[Message Channels](https://www.enterpriseintegrationpatterns.com/patterns/messaging/MessagingChannelsIntro.html) are defined as this: |
| 116 | + |
| 117 | +~~~ |
| 118 | +channel PatientMeasurements |
| 119 | +of type PUBLISH_SUBSCRIBE, DATA_TYPE |
| 120 | +delivery guarantee AT_LEAST_ONCE |
| 121 | +description "Notifies whenever a new measurement comes" |
| 122 | +on path "/patients/${patientId}/measurement" |
| 123 | + with |
| 124 | + patientId: int, "The patient identifier" |
| 125 | +accepts message Measurement |
| 126 | + description "Contains the value and the type of the measurement" |
| 127 | + expecting |
| 128 | + headers HeadersDTO |
| 129 | + payload MeasurementDTO as EVENT_MESSAGE |
| 130 | + where |
| 131 | + MESSAGE_EXPIRES in 60m |
| 132 | +bindings for MQTT { |
| 133 | + "qos": 1 |
| 134 | +} |
| 135 | +~~~ |
| 136 | + |
| 137 | +In the above example we define a `PUBLISH_SUBSCRIBE` channel called _PatientMeasurements_; this type of channel can have multiple subscribers at the same time, and the message will be delivered to each of them as a copy. As a `DATA_TYPE` channel, this channel will only carry messages with the same schema. |
| 138 | + |
| 139 | +The quality of service of the messages that will be sent to this channel is declared as the delivery guarantee `AT_LEAST_ONCE`: every message will be received by each subscriber at least one time. |
| 140 | + |
| 141 | +We then inform subscribers that the path on which this channel will be exposed by a broker contains a parameter (_patientId_), which is determined at runtime by publishers subscribers. <!-- check edit --> |
| 142 | + |
| 143 | +Since we stated that the channel is a `DATA_TYPE` channel, we specify the schema of the message that will be sent to subscribers _MeasurementDTO_ as well as the intent of such message (for example `EVENT_MESSAGE` or `DOCUMENT_MESSAGE`). We may also include other relevant information such as the message expiration time or a correlation identifier (if present). |
| 144 | + |
| 145 | +We can finalize the channel definition by specifying optional _bindings_ for concrete protocols (here: MQTT). |
| 146 | + |
| 147 | +### Request-Reply Channels |
| 148 | + |
| 149 | +[Request-Reply messages](https://www.enterpriseintegrationpatterns.com/patterns/messaging/RequestReply.html) require distinct logical channels to communicate: one channel for the request and one channel for the reply. A Request-Reply Channel allows the definition of both logical channels, where each of them contains the payload they expect/deliver. Also, in this type of communication, it might be useful to specify further information, such as the Correlation Identifier of a message: |
| 150 | + |
| 151 | +~~~ |
| 152 | +channel [requestReplyChannelName] |
| 153 | +request message [requestChannelName] |
| 154 | + description [description] |
| 155 | + on path [requestPath] |
| 156 | + expecting |
| 157 | + headers [...] |
| 158 | + payload [...] |
| 159 | +reply message [replyChannelName] |
| 160 | + description [description] |
| 161 | + on path [replyPath] |
| 162 | + delivering |
| 163 | + headers [...] |
| 164 | + payload [...] |
| 165 | + where |
| 166 | + CORRELATION_ID is [expression] |
| 167 | +~~~ |
| 168 | + |
| 169 | +`expression` has the format `$message.(payload | header)#/path/to/property`. |
| 170 | + |
| 171 | +### Message Brokers |
| 172 | + |
| 173 | +Message brokers expose previously defined message channels and make them available to consumption under a concrete protocol: |
| 174 | + |
| 175 | +~~~ |
| 176 | +message broker [name] |
| 177 | +description [description] |
| 178 | +exposes |
| 179 | + [channelName], |
| 180 | + [otherChannelName] |
| 181 | + at location [url] |
| 182 | + via protocol [protocol], |
| 183 | + bindings { |
| 184 | + // JSON object with protocol-specific options |
| 185 | + } |
| 186 | + policy [policyName] // optional security policy |
| 187 | + realized using [policyType] in [payloadExpression], |
| 188 | + [...] // expose other channels under different protocols and policies |
| 189 | +~~~ |
| 190 | + |
| 191 | +#### Parameters |
| 192 | + |
| 193 | +- |
| 194 | + Protocol can assume one of the [supported protocols](./bindings). Examples are: |
| 195 | + > AMPQ | MQTT | Kafka |
| 196 | + |
| 197 | +- |
| 198 | + Bindings is single flat JSON object: |
| 199 | + > Notice that no protocol-specific validation is applied. |
| 200 | + |
| 201 | +- |
| 202 | + Security policy type. MDSL security policies are not yet fully supported. The available values are: |
| 203 | + > JWT | API_KEY |
| 204 | + |
| 205 | + <!-- TODO OAS binding does a lot more since core MDSL 5.0, could bring some of that support here --> |
| 206 | + |
| 207 | +- |
| 208 | + Security policy expression specifies where to find the value and has the format: |
| 209 | + > `$message.(payload | header)#/path/to/property` |
| 210 | + |
| 211 | +### Message Endpoints |
| 212 | + |
| 213 | +Message Endpoints are clients that connect to Message Brokers. Message Endpoints can use one or more Message Brokers, and for each one of them, they can specify which channels they are going to use to produce and/or consume messages: |
| 214 | + |
| 215 | +~~~ |
| 216 | +message endpoint [name] |
| 217 | +of type [type] // EIP pattern (optional) |
| 218 | +serves as [role_enum] // MAP tag(s) (optional) |
| 219 | +description [description] |
| 220 | +uses |
| 221 | + from [broker]: |
| 222 | + [channel], |
| 223 | + [channel1], |
| 224 | +
|
| 225 | + [...] // declare dependency from other brokers/channels |
| 226 | +~~~ |
| 227 | + |
| 228 | +## Generator Tool: AsyncMDSL to AsyncAPI |
| 229 | + |
| 230 | +Valid AsyncMDSL specifications can be mapped to [AsyncAPI](https://www.asyncapi.com/). See [this page](./generators/async-api) for instructions. |
| 231 | + |
| 232 | +# Site Navigation |
| 233 | + |
| 234 | +* Language specification: |
| 235 | + * Service [endpoint contract types](./servicecontract) (this page) and [data contracts (schemas)](./datacontract). |
| 236 | + * [Bindings](./bindings) and [instance-level concepts](./optionalparts). |
| 237 | +* [Quick reference](./quickreference), [tutorial](./tutorial) and [tools](./tools) |
| 238 | +* Back to [MDSL homepage](./index). |
| 239 | + |
| 240 | +*See [license information](https://github.com/socadk/MDSL/blob/master/LICENSE).* |
| 241 | + |
| 242 | +<!-- *EOF* --> |
0 commit comments