Home — Data Types — Bindings — Provider and Client — Tutorial — Cheat Sheet — Tools
Service Endpoint Contracts in MDSL
Use Cases for MDSL Specifications
- Creation, review and evolution of elaborate API Descriptions as featured in Microservice API Patterns (MAP), in forward engineering:
- Reverse engineering:
- Discover contracts, clients, providers in existing systems
- Analysis support (metrics)
Concepts
The contract syntax (grammar) of MDSL is inspired by the API domain model from Microservice API Patterns (MAP): An API description features one or more endpoints, which expose operations that expect and deliver messages.1:
ServiceSpecification:
'API' 'description' name=ID
('version' svi=SemanticVersioningIdentifier)? // plain STRING
('usage' 'context' reach=Visibility ('for' direction+=DirectionList)?)?
('overview' description=STRING)?
types+=DataContract*
contracts+=EndpointContract+
providers+=Provider*
clients+=Client*
gateways+=Gateway*
orchestrations+=Orchestration*
scenarios+=IntegrationScenario*
('IPA')?;
EndpointContract:
'endpoint' 'type' name=ID
('version' svi=SemanticVersioningIdentifier)? // plain STRING
('serves' 'as' primaryRole=ResourceRole
('and' otherRoles+=ResourceRole)* 'role'?)? // pattern decorator
('identified' 'by' pathParameters=ElementStructure)?
('exposes' ops+=operation+)?;
('receives' events+=Event+)?
Operation:
'operation'
name=ID
('version' svi=SemanticVersioningIdentifier)?
('with' 'responsibility' responsibility=OperationResponsibility)? // pattern decorator
('in' mep=MessageExchangePattern 'conversation')?
('expecting' requestMessage=DataTransferRepresentation)?
('delivering' responseMessage=DataTransferRepresentation
('links' relations+=RelationshipLink+)? // optional within 'delivering'
('reporting' reports=StatusReports)? // optional within 'delivering'
)? // response is optional
('transitions' st=StateTransition)?
('emitting' events+=Event+)?
('compensated' 'by' undo=[Operation])?
('protected' 'by' policies=SecurityPolicies)?
DataTransferRepresentation:
('headers' headers=ElementStructure)?
'payload' payload=ElementStructure
('structured' 'as' ts=TypeSystem)?;
The notation used above is the grammar language of Xtext (which is close to that of antlr4). The full MSDL grammar can be found here.
Endpoint types correspond to ports in the Hexagonal Architecture terminology; adapters are represented by technology bindings The request and response messages consist of headers and payloads, whose content is modelled with MDSL data transfer representations.
Note: The above MDSL grammar also has language concepts to model compensating operations, states and their transitions, event emission and reception, and security policies. These features are still under design and development. The MDSL Primer shows them, and sample specifications featuring these advanced concepts can also be found here and here. Please view these grammar extensions as technology previews subject to change in future versions.
Example
The following exemplary API specification compiles against the MDSL grammar sketched above:
API description SampleCustomerManagementAPI version "1.0.0"
usage context PUBLIC_API for FRONTEND_INTEGRATION
endpoint type CustomerManagementContract
version "1.0.0"
serves as INFORMATION_HOLDER_RESOURCE
exposes
operation lookupSingleCustomer version "1.0.1"
with responsibility RETRIEVAL_OPERATION in REQUEST_REPLY conversation
expecting
payload ID<string>
delivering
payload {"customerId":ID<int>,
"name":D,
"address"}
operation lookupCustomerDirectory // no version information
with responsibility RETRIEVAL_OPERATION in REQUEST_REPLY conversation
expecting
payload <<Request_Bundle>> "customerId":ID<int>+ // at least one
delivering
payload
"customerRecord": {
"cid":ID!, // ! mandatory, exactly one
"nameTuple":("firstname":D, "lastname":D),
"addressTuple":(
"street":D<string>,
"poBox":D?, // optional
"zipCode":D,
"city":D)+,
"segment":("REGULAR":D|"VIP":D) // choice
}* // zero or more
The described API SampleCustomerManagementAPI
supports one endpoint type CustomerManagementContract
that exposes two operations lookupSingleCustomer
, lookupCustomerDirectory
to retrieve some customer data in a Customer Relationship Management (CRM) scenario. While request messages (expecting
) are mandatory, response messages (delivering
) are optional.
The specification of the message exchange pattern is optional; permitted values are REQUEST_REPLY
, ONE_WAY
and NOTIFICATION
. Request-reply operations must have a request and a response message; one way operations only have a requests message.
Several Microservice API Patterns (MAPs) are used to annotate endpoint, operation, and one representation element (INFORMATION_HOLDER_RESOURCE
, RETRIEVAL_OPERATION
).2 Moreover, foundation patterns from MAP may comment on the usage scenario for the described API; this is optional (here: PUBLIC_API
for FRONTEND_INTEGRATION
). The MAP decorators are supported as explicit enum values in the grammar; you can also use any “STRING”.
The first operation lookupSingleCustomer
requires the API client to send an ID in the request message to be able to return the corresponding customer record. Its response message format lists three atomic parameters (customerId
, name
, address
).
The second operation lookupCustomerDirectory
expects at least one customer id (+
) so that multiple records can be returned in one response (*
), which implements the Request Bundle pattern in MAP. This is indicated with the <<Request_Bundle>>
stereotype. These pattern stereotypes merely serve as markers; tools such as code generators can use them to fine-tune their output.
The data contract of the lookupSingleCustomer
operation is fully specified, whereas part of the message elements in the response of lookupCustomerDirectory
are still incomplete (for instance, "zipCode":D
).3
For more explanations of the message structures, see data contracts (schemas).
Security and Error Reporting
Response messages can indicate which type of error information might replace/accompany it, and operations can define a security policy:
endpoint type HelloWorldPlusEndpoint
exposes
operation sayHello in REQUEST_REPLY conversation
expecting payload D<string>
delivering payload SampleDTO
// message-level status report:
reporting error "400": D<int> // bad request (HTTP error code)
// operation-level security policy:
protected by policy "HTTPBasicAuthentication":MD
In this example, the error report is a simple numeric code (400
); elaborate error reports can be modeled as well, as any MDSL data type can be used.
The security policy
also is modelled as an MDSL data contract; it can be used to define the various security assertions and protocol headers that exist (for instance, basic authentication in HTTP, as explained in the OpenAPI specification). Important note: This MDSL feature also still is under design and construction (view it as an incomplete technology preview); future versions of the MDSL documentation pages will provide more examples.
Note: These two MDSL features and tool support for them still are under development; future versions of the MDSL documentation pages will provide more examples.
Technology Mappings
See this page for information on how MDSL maps to OpenAPI and REST, WSDL/SOAP, and gRPC.
Site Navigation
- Language specification:
- Service endpoint contract types (this page) and data contracts (schemas)
- Bindings and instance-level concepts
- Quick reference, tutorial and tools
- Back to MDSL homepage
Copyright: Olaf Zimmermann, 2018-2022. All rights reserved. See license information.
-
This domain model is published in Section 3 of the EuroPLoP 2019 paper on Patterns for API Evolution from the MAP team. ↩
-
The notion of API roles and responsibilities as well as the term Information Holder have their roots in Responsibility-Driven Design (RDD). ↩
-
If an operation does not expect or deliver any payload, this can be expressed with the help of the empty/null type
D<void>
. This type should only be used for this purpose. ↩