View on GitHub

MDSL

A domain-specific language to specify (micro-)service contracts and their data representations (realizing the API Description pattern from MAP)

Data Contracts and Schemas in MDSL

Usage

Concepts

The structure patterns from MAP form the base of the type system that is used in MDSL:

Specifications do not have to be complete to be useful (e.g., in early stages of service design); tools are expected to check completeness, use defaults for missing parts, etc.

Representation element stereotypes

The role within a message payload that is played/taken by a particular part of a header or payload (a representation element in MAP terminology) is the primary specification element; identifiers and data type are optional. This three-part specification (with only one mandatory part) is quite different from the identifier-type pairs typically used in programming languages. It makes it possible to create rather compact (but still incomplete) specifications during agile API modeling.

An abstract, unspecified element is represented as P (for parameter or payload part).

Concrete atomic type refinements of P, matching the element stereotypes in MAP, are:

Base types

The role stereotypes can be combined with the following base types to yield precise specifications of atomic parameters: bool, int, long, double, string, blob, void. So V<int> is an integer value and V<void> is an empty/non-existing payload part/parameter.

Collections and optionality

*, ?, and + turn a type definition into a collection (*: zero or more, ?: one or none, + : at least one). The default is ! (exactly one); it does not have to be modeled.

Parameter trees and atomic parameter lists can be used to express optionality if | (is used rather than ,).

Reusable data

dataContract:
    'data' 'type' name=ID 
    ('version' svi=semanticVersioningIdentifier)? 
    structure=elementStructure;

elementStructure: 
    pf=parameterForest | pt=parameterTree 
  | apl=atomicParameterList  | np=singleParameterNode;

[...]

TreeNode:
    spn=singleParameterNode | apl=atomicParameterList | pt=parameterTree;

SingleParameterNode: 
    genP=genericParameter | atomP=atomicParameter | tr=typeReference;

Example

The following example features a partial specification of nested customer information as the roles/types of all “three plus three” representation elements yet unknown:

data type MoveHistory {"from", "to", "when"}  
data type CustomerWithAddressAndMoveHistory { 
    "CustomerCoreData", 
    "AddressRecords", 
    MoveHistory* // type reference
} 

Alternatively, one can start with element stereotypes and pure structure instead of element names:

data type MoveHistory {V, V, V}  // record, modeled as Parameter Tree
data type CustomerWithAddressAndMoveHistory { 
    V, 
    V, 
    MoveHistory* // type reference
} 

Once some more analysis work has been done, the specification can be refined, but still remain incomplete (as "CustomerCoreData":V does not say anything about the inner structure of the entity value):

data type AddressRecord (
    "street":V<string>, 
    "zipCode":V<int>, 
    "city":V<string>) // Atomic Parameter List in '()' syntax

data type MoveHistory 
    {"from":AddressRecord, "to":AddressRecord, "when":V<"Date">} 

data type CustomerWithAddressAndMoveHistory { 
    <<Entity>>"CustomerCoreData":V, 
    "AddressRecords":AddressRecord+, // one or more
    "MoveHistory": MoveHistory* // type reference, collection
} 

Note that a parameter tree that only contains atomic parameters {V<int>, V<string>} can also be modeled as an Atomic Parameter List (V<int>, V<string>). It is recommended to prefer the Parameter Tree syntax over that of the Atomic Parameter List (to promote information hiding and defer detailed modeling decisions until the last/most responsible moment).

Technology Mappings

JSON/JSON Schema

JSON MDSL Comments
Basic JSON data types Atomic Parameter Base types do not match 100%
Object (flat) Parameter Tree (flat) or Atomic Parameter List Parameter Tree preferred
Object (structured) Parameter Tree (nested) Straightforward
Array Cardinality of * or + Is homogeneous in MDSL/MAP

XML Schema

XML Schema MDSL/MAP Comments
Built-in data types Atomic Parameter Not the same expressiveness
Sequence element (referencing built-in types) Parameter Tree (flat) or Atomic Parameter List Parameter Tree preferred
Complex type Parameter Tree MDSL syntax more compact
Sequence with maxoccurs > 1 Cardinality of * or + n/a

Jolie

The MAP base types map to simple data in Jolie in a straightforward manner.

The same holds for the mapping of parameter trees to Jolie data structures.

An example can be downloaded here.

Limitations

Note that some combinations are syntactically possible at present (to simplify the grammar), but do not make much sense (or create ambiguity):

We expect tools (linters, model validators) to warn about inappropriate specifications and do not recommend to use them.

Back to service endpoint contract types and on to optional runtime language concepts.

Quick reference.

Back to MDSL homepage.

Copyright: Olaf Zimmermann, 2019. All rights reserved.