Home — Endpoint Type — Data Type — Provider and Client — Bindings — Cheat Sheet — Tools
MDSL Tutorial
Getting Started
Let us assume we want to create an HTTP resource API that supports upload and download of spreadsheets. The structure of these sheets resembles that of the popular CSV format and supporting tools. We choose a contract-first approach to design this API.1
Unlike Swagger/OpenAPI Specification, Microservice Domain-Specific Language (MDSL) is a technology-neutral notation; see MDSL home page for more positioning information.
Modeling Representation Elements
Let’s start with data modeling. A spreadsheet may contain several sheet tabs (sometime also called worksheets). This multiplicity can be indicated by an asterisk *
:
data type CSVSpreadsheet CSVSheetTab*
The content of such sheet tabs is usually structured into rows, and the tabs usually also have unique names. Hence, we model them as Parameter Trees, a pattern from the MAP language. In MDSL, parameter trees are represented by curly braces {}
:
data type CSVSheetTab {"name": D<string>, "content": Rows*}
"name": D<string>
is a fully specified Atomic Parameter (scalar). "content": Rows*
is the second parameter, referencing yet another data type definition. Each sheet may have an arbitrary number of rows (indicated by an asterisk *
).
Each row is identified by a line
number and features data in at least one column
(which is indicated by a plus +
):
data type Rows {"line": ID<int>, "columns":Column+}
This atomic parameter is not characterized as a plain value D
as the name in CSVSheetTab
above, but as a unique identifier ID
. Id(entifier) Element is another MAP leveraged by and integrated into MDSL. 2
Columns are often identified by characters position
and, optionally, a more expressive text header
(optionality is indicated by the ?
modifier in MDSL):
data type Column {"position": ID<string>,
"header": D<string>?,
"cell": Cell}
The combination of columns and rows gives us the powerful matrix/cell structure that we would expect from spreadsheets. We have now arrived at the cell level. Cells either contain text, numbers or formulas (in this example):3
data type Cell { "text":D<string>
| "integerValue": D<int>
| "longValue": D<long>
| "formula": D<string> }
Modeling Operations and Endpoints
We are now ready to send instances of the complex (nested, repetitive) CSVSpreadsheet
over the wire; it can serve as a Data Transfer Object (DTO).4 We need a service contract to do that.
Operation specifications in MDSL are quite talkative (unlike the rather compact data type definitions we have worked with so far):
operation downloadSpreadsheet
expecting payload ID
delivering payload CSVSpreadsheet
reporting error "204":D<int> // numeric error code only (OpenAPI generator limitation)
The request and response messages of downloadSpreadsheet
are defined via their data type structures. Here, the expected request message contains a simple ID
(entifier) that is not specified any further at this point; the delivered response is the CSVSpreadsheet
DTO from above.
Optionally, error reporting information can be added (which comes in the form of a parameter specification; see “Reporting” section on the quick reference page for an example). In the above example, one error message is defined, reporting that the received ID does not match any existing spreadsheet.
To complete the example, we should also model an upload operation:
operation uploadSpreadsheet
expecting payload CSVSpreadsheet
delivering payload {"successFlag":D<bool>, ID}
The two operation specifications appear inside an endpoint specification (which corresponds to a resource definition in REST):
endpoint type SpreadSheetExchangeEndpoint
exposes
[operations go here]
Final Step and Full Specification
We are still missing an API description wrapper:
API description SpreadSheetExchangeAPI
data type CSVSpreadsheet CSVSheetTab*
data type CSVSheetTab {"name": D<string>,
"content": Rows*}
data type Rows {"line": ID<int>,
"columns":Column+}
data type Column {"position": ID<string>,
"header": D<string>?,
<<Entity>> "cell": Cell}
data type Cell {"formula":D<string>
| "intValue": D<int>
| "longValue": D<long>
| "text": D<string>}
endpoint type SpreadSheetExchangeEndpoint
exposes
operation uploadSpreadsheet
expecting payload CSVSpreadsheet
delivering payload {"successFlag":D<bool>, ID}
operation downloadSpreadsheet
expecting payload ID
delivering payload CSVSpreadsheet
reporting error "204" // No Content, aka "SheetNotFound"
We are done modeling and now would be ready to implement the contract and deploy a provider supporting it.
Outlook: Advanced Contract Modeling
MDSL supports more concepts to model endpoint types and their operations:
- Error reporting
- Security policy
- State transitions and compensating operations
- Default values
These language features are not demonstrated in this tutorial; please refer to the example in the MDSL Primer.
Outlook: Protocol Bindings
An intermediate step probably would be to create a platform- and technology-specific contract such as a OpenAPI/Swagger specification, gRPC Protocol Buffers, GraphQL schema language, Jolie ports and interfaces or plain Java interfaces; see MDSL tools.
A protocol binding might be needed for that step. Here is an example of an HTTP binding (note: technology preview, still work in progress):
API provider SpreadSheetExchangeAPIProvider
offers SpreadSheetExchangeEndpoint
at endpoint location "https://some.domain.name/relativePath"
via protocol HTTP
binding
operation uploadSpreadsheet to PUT
operation downloadSpreadsheet to GET
API client SpreadSheetExchangeAPIClient
consumes SpreadSheetExchangeEndpoint
The binding concepts are explained on this page.
Outlook: MAP Decorators
MDSL is aware of the Microservice API Patterns; these patterns can be used to annotate endpoints, operations, and representation elements. This makes the machine-readable specification more expressive (in comparison to formatted comments or free-form texts accompanying the formal specification):
API description SpreadSheetExchangeAPI
data type CSVSpreadsheet CSVSheetTab*
data type CSVSheetTab {"name": D<string>,
"content": Rows*}
data type Rows {"line": ID<int>,
"columns":Column+}
data type Column {"position": ID<string>,
"header": D<string>?,
<<Entity>> "cell": Cell}
data type Cell {"formula":D<string>
| "intValue": D<int>
| "longValue": D<long>
| "text": D<string>}
endpoint type SpreadSheetExchangeEndpoint serves as DATA_TRANSFER_RESOURCE
exposes
operation uploadSpreadsheet with responsibility STATE_CREATION_OPERATION
expecting payload CSVSpreadsheet
delivering payload {"successFlag":D<bool>, ID}
operation downloadSpreadsheet with responsibility RETRIEVAL_OPERATION
expecting payload ID
delivering payload CSVSpreadsheet
reporting error SheetNotFound "e204":ID<int> // 204: No Content
API provider SpreadSheetExchangeAPIProvider
offers SpreadSheetExchangeEndpoint
at endpoint location "https://some.domain.name/relativePath"
via protocol HTTP
binding
resource CSVResource
operation uploadSpreadsheet to PUT
operation downloadSpreadsheet to GET
report SheetNotFound realized as 204 with "No Content"
API client SpreadSheetExchangeAPIClient
consumes SpreadSheetExchangeEndpoint
This enhanced specification states that SpreadSheetExchangeEndpoint
serves as a TRANSFER_RESOURCE
; upSpreadsheet
is an NOTIFICATION_OPERATION
and downloadSpreadsheet
is a RETRIEVAL_OPERATION
. The cell content in the Column
data type is an <<Entity>>
. All these decorators are defined as patterns in the MAP language.
In addition to MAP patterns, any string can decorate endpoints and operations; if this capability is used, it is undefined how tools will process them (as these tools cannot know the meaning of free-form decorators).
Links
- MDSL homepage and MDSL tools
- MDSL Primer and quick fix transformations
- Service endpoint contract types, data contracts (schemas), bindings and other runtime language concepts.
- Quick reference skeleton
- Microservice API Patterns.
Copyright: Olaf Zimmermann, 2018-2022. All rights reserved. See license information.
-
There are two ways to approach API design, code first and contract first. With code first, one writes an API implementation, annotates the API with the required routing and (de)serialization information and lets tools and middleware generate a contract. In contract first, one authors an interface description, for instance in Swagger/OpenAPI Specification and then (optionally) lets tools generate client and server stubs. MDSL supports contract-first service design at present. ↩
-
The other two element stereotypes in MAP, are Metadata
MD
and LinkL
. ↩ -
ignoring special types of cells such as pivot tables and data visualizations, as supported for instance in Microsoft Excel, in/for this simplified example. ↩
-
In our integration context, Data Transfer Representation (DTR) is a better name, actually. ↩