View on GitHub

Microservice DSL (MDSL)

A Domain-Specific Language (DSL) to specify (micro-)service contracts, their data representations and API endpoints.

Service Endpoint Contracts in MDSL

Use Cases for MDSL Specifications

Concepts

The contract syntax (grammar) of MDSL is inspired by the API domain model from Microservice API Patterns (MAP).1 An API description features one or more endpoints, which expose operations that expect and deliver messages. These messages consist of headers and payloads, whose content is modelled with MDSL data transfer representations:

serviceSpecification: 
	'API' 'description' name=ID
	('usage' 'context' visibility=visibility 
	    'for' direction+=directionList)?
	types+=dataContract*
	contracts+=endpointContract+
	providers+=provider*
	clients+=client*
	gateways+=gateway*
	('IPA')?;

endpointContract:
	'endpoint' 'type' name=ID 
	('version' svi=semanticVersioningIdentifier)? 
	('serves' 'as' primaryRole=ResourceRole 
	    ('and' otherRoles+=ResourceRole)* 'role'?)? 
	('identified' 'by' pathParameters=elementStructure)? 
	('exposes' ops+=operation+)?;

operation:
	'operation' name=ID
	('version' svi=semanticVersioningIdentifier)?
	('with' 'responsibility' respos=operationResponsibility)?
	('in'  mep=messageExchangePattern 'conversation')?  
	'expecting' requestMessage=dataTransferRepresentation
	('delivering' responseMessage=dataTransferRepresentation
		('reporting' reportData=statusReport)? // optional
	)?;

dataTransferRepresentation:
	('headers' headers=elementStructure)? 
	'payload' payload=elementStructure
	('structured' 'as' ts=typeSystem)?;

The notation used above is the grammar language of Xtext (which close to that of antlr4). The full MSDL grammar can be found here (note: still a private repo).

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 SampleCustomerManagementAPIsupports 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 specificaiton 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 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:
	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. Important note: This MDSL feature is still under design and construction and therefore incomplete (tech. preview); future versions of the MDSL documentation pages will provide more examples.

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 is still under design and construction and therefore incomplete (tech. preview); future versions of the MDSL documentation pages will provide more examples.

Technology Mappings

RESTful HTTP (a.k.a. HTTP resource APIs)

Endpoints correspond to resources (with the mapping not being straightforward due to concepts such as URI templates and path parameters in HTTP). Operations correspond to HTTP verbs or methods (with additional constraints being imposed by the architectural style and nest practices for REST).

Web Services Description Language (WSDL)

MDSL endpoints map to port types in WSDL; operations (not surprisingly) to operations. API providers are pendants to ports in WSDL, API clients are service consumers.

Jolie

The service contract grammar can easily be mapped to the glossary of Jolie terms. For instance, endpoint types in MDSL correspond to interfaces in Jolie:

Jolie MDSL/MAP Comments
Operation Operation n/a
Interface Endpoint type n/a
tbd API (multiple endpoint types) n/a
Port (inbound) API provider n/a
Port (outbound) API client n/a
(Micro-)Service (Micro-)Service exposes one or more APIs with one or more operations
Conversation Conversation to be checked
Service definition (service implementation) n/a
Service network tbd n/a
Cell and related concepts not in scope n/a

Other integration technologies

MSDL service contracts can also be mapped to gRPC, GraphQL, and Avro in a straightforward manner. Stay tuned!

Data contracts (schemas) and optional runtime language concepts.

Quick reference.

Back to MDSL homepage.

Copyright: Olaf Zimmermann, 2018-2020. All rights reserved. See license information.

  1. This domain model is published in Section 3 of the EuroPLoP 2019 paper on Patterns for API Evolution from the MAP team

  2. The notion of API roles and responsibilities as well as the term Information Holder have their roots in Responsibility-Driven Design (RDD)

  3. 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.