Comlink Map
Version 2023.01.16
Introduction
Comlink Map is a format for describing one concrete implementation of a Comlink Profile. It essentially maps the application (business) semantics into provider’s interface implementation.
1Map Document
Defines a document that maps a profile into a particular provider’s API. At minimum, the map document consists of the profile and provider identifiers and a profile use‐case map.
Optionally, map document may specify a variant. Variant allows for mutliple maps for the same MapProfileIdentifier and ProviderIdentifier.
Example № 1profile = "conversation/send-message"
provider = "some-telco-api"
map SendMessage {
...
}
map RetrieveMessageStatus {
...
}
Example № 2profile = "conversation/send-message"
provider = "some-telco-api"
variant = "my-bugfix"
map SendMessage {
...
}
map RetrieveMessageStatus {
...
}
2Usecase Map
Context Variables
Map context variables :
- input - User input as stated in the profile
Example № 3map RetrieveMessageStatus {
http GET "/chat-api/v2/messages/{input.messageId}/history" {
response 200 "application/json" {
map result {
deliveryStatus = body.history[0].state
}
}
}
}
2.1Map Result
Example № 4map GetWeather {
map result {
airTemperature = 42 # Sets the value returned to user
}
}
2.2Map Error
Example № 5map GetWeather {
map error {
title = "Location not found"
}
}
3Operation
Context Variables
Operation context variables :
- args - arguments as passed in the parent’s OperationCall
Example № 6operation CountArray {
return {
answer = "This is the count " + args.array.length
}
}
3.1Operation Return
Example № 7operation Foo {
return if (args.condition) {
message = "I have a condition!"
}
return {
message = "Hello World!"
}
}
3.2Operation Fail
Example № 8operation Foo {
fail if (args.condition) {
errorMessage = "I have failed!"
}
}
4Set Variables
Example № 9set {
variable = 42
}
Example № 10set if (true) {
variable = 42
}
Example № 11set {
variable.key = 42
}
Example № 12set {
variable = call ConvertToCelsius(tempF = 100)
}
5Operation Call
Condition and iteration
When both Condition and Iteration are specified, the condition is evaluated for every element of the iteration.
Context Variables
OperationCallSlot context variables:
outcome.data
- data as returned by the calleeoutcome.error
- error as returned by the callee
Example № 13operation Bar {
set {
variable = 42
}
call FooWithArgs(text = `My string ${variable}`, some = variable + 2) {
return if (!outcome.error) {
finalAnswer = "The final answer is " + outcome.data.answer
}
fail if (outcome.error) {
finalAnswer = "There was an error " + outcome.error.message
}
}
}
Example № 14map RetrieveCustomers {
// Local variables
set {
filterId = null
}
// Step 1
call FindFilter(filterName = "my-superface-map-filter") if(input.since) {
// conditional block for setting the variables
set if (!outcome.error) {
filterId = outcome.data.filterId
}
}
// Step 2
call CreateFilter(filterId = filterId) if(input.since && !filterId) {
set if (!outcome.error) {
filterId = outcome.data.filterId
}
}
// Step 3
call RetrieveOrganizations(filterId = filterId) {
map result if (!outcome.error && outcome.data) {
customers = outcome.data.customers
}
}
// Step 4
call Cleanup() if(filterId) {
// ...
}
}
Example № 15operation Baz {
array = [1, 2, 3, 4]
count = 0
data = []
call foreach(x of array) Foo(argument = x) if (x % 2) {
count = count + 1
data = data.concat(outcome.data)
}
}
Example № 16operation Baz {
array = [1, 2, 3, 4]
data = call foreach(x of array) Foo(argument = x) if (x % 2)
count = data.length
}
5.1Operation Call Shorthand
Used as RHS instead of ScriptExpression to invoke an Operation in‐place. In the case of success the operation outcome’s data is unbundled and returned by the call. See OperationCall context variable outcome
.
Example № 17set {
someVariable = call Foo()
}
Iteration and operation call shorthand
When an iteration is specified ther result of the OperationCallShorthand is always an array.
Example № 18operationOutcome = call SomeOperation()
users = call foreach(user of operationOutcome.users) Foo(user = user) if (operationOutcome)
// Intepretation:
// `Foo` is called for every `user` of `operationOutcome.users` if the `operationOutcome` is truthy
superusers = call foreach(user of operationOutcome.users) Bar(user = user) if (user.super)
// Intepretation:
// `Bar` is called for an `user` of `operationOutcome.users` if the `user.super` is truthy
6Outcome
Evaluation of a use‐case map or operation outcome. The outcome definition depends on its context. When specified in the Map context the outcome is defined as SetMapOutcome. When specified in the Operation context the outcome is defined as SetOperationOutcome.
6.1Map Outcome
Outcome in the Map context.
6.2Operation Outcome
Outcome in the Operation context.
7Network Operation
8HTTP Call
GET | HEAD | POST | PUT | DELETE | CONNECT | OPTIONS | TRACE | PATCH |
Example № 19map SendMessage {
http POST "/chat-api/v2/messages" {
request "application/json" {
body {
to = input.to
channels = ['sms']
sms.from = input.from
sms.contentType = 'text'
sms.text = input.text
}
}
response 200 "application/json" {
map result {
messageId = body.messageId
}
}
}
}
Example of HTTP call to a service other than the defaultService
.
Example № 20http GET service2 "/users" {
...
}
8.1HTTP Transaction
8.2HTTP Security
Example № 21GET "/users" {
security "api_key_scheme_id"
response {
...
}
}
If no other HTTPSecurity is provided, the default is none
. Explicitly signify public endpoints as none
as so.
Example № 22GET "/public-endpoint" {
security none
response {
...
}
}
8.3HTTP Request
Example № 23http GET "/greeting" {
request {
query {
myName = "John"
}
}
}
Example № 24http POST "/users" {
request "application/json" {
query {
parameter = "Hello World!"
}
headers {
"my-header" = 42
}
body {
key = 1
}
}
}
Example № 25http POST "/users" {
request "application/json" {
body = [1, 2, 3]
}
}
8.4HTTP Response
Context Variables
HTTPResponseSlot context variables :
- statusCode - HTTP response status code parsed as number
- headers - HTTP response headers in the form of object
- body - HTTP response body parsed as JSON
Example № 26http GET "/" {
response 200 "application/json" {
map result {
outputKey = body.someKey
}
}
}
Example № 27http POST "/users" {
response 201 "application/json" {
return {
id = body.userId
}
}
}
Handling HTTP errors:
Example № 28http POST "/users" {
response 201 "application/json" {
...
}
response 400 "application/json" {
map error {
title = "Wrong attributes"
details = body.message
}
}
}
Handling business errors, status code is left out and the handler processes everything:
Example № 29http POST "/users" {
response "application/json" {
map result if (body.ok) {
...
}
map error if (!body.ok) {
...
}
}
}
When ContentType is not relevant but ContentLanguage is needed, use the *
wildchar in place of the ContentType as follows:
Example № 30http GET "/" {
response "*" "en-US" {
map result {
rawOutput = body
}
}
}
9Conditions
Conditional statement evalutess its ScriptExpression for truthiness.
Example № 31if ( true )
Example № 32if ( 1 + 1 )
Example № 33if ( variable % 2 )
Example № 34if ( variable.length == 42 )
10Iterations
When the given ScriptExpression evaluates to an array (or any other ECMA Script iterable), this statement iterates over its elements assigning the respective element value to its context VariableName variable.
Example № 35foreach (x of [1, 2, 3])
Example № 36foreach (element of variable.nestedArray)
11Script
This is a subset of the Javascript programming language designed to be familiar to a great number of programmers while reducing the possible attack surface of the runtime environment.
This specification is based on and references ECMA 262 and heavily inspired by Jessie.
11.1Operators
+ | - | ! | ~ |
+ | - | * | ** | / | % | && | || | << | >> | >>> | & | | | ^ | < | > | <= | >= | === | !== |
= | += | -= | *= | /= |
++ -- == != %= <<= >>= >>>= &= |= ^=
11.2Literals
11.2.1Primitive
The allowed Javascript literal productions are:
Example № 371.234e-4
Example № 38"hello world"
Example № 39`Foo: ${foo}, bar: ${bar}`
11.2.2Array
Example № 40[...[1, 2], 3, 4]
11.2.3Object
Example № 41{ ...a, b: 1, c: 2 + 3 }
yield
, await
, CoverInitializedName, ComputedPropertyName and MethodDefinition.11.3Identifiers
Javascript identifier production
Javascript reserved word production
break | case | const | continue | default | do | else | false |
for | if | null | return | switch | true | while |
11.4Expressions
Expressions are central to the script. Expressions appear on the right‐hand side of VariableStatement, in Conditions and in operation call Argument list.
Since the only way to obtain a lexical context in which statements can be declared is to create an ScriptArrowFunction, it is often more convenient to use functional patterns to transform data:
Example № 42Object.entries(foo).filter(
([_key, value]) => value > 0
).map(
([key, _value]) => key
)
Example № 431 + 2**input.exponent
Example № 44{ ...a, b: 1, c: 2 + 3, d: [...[1, 2], 3, 4] }
Example № 45(() => {
const result = "only do this in very complex cases"
return result
})()
this
, FunctionExpression, ClassExpression, GeneratorExpression, AsyncFunctionExpression, AsyncGeneratorExpression and RegularExpressionLiteral.11.4.1Unary
Example № 46-7
11.4.2Binary
Example № 47"foo" + "bar"
Example № 48foo.bar += 7 * 8
11.4.3Ternary
Example № 49foo === 1 ? "hello" : "goodbye"
11.4.4Call
Example № 50foo.bar(1, 2 + 3, ["hello", "world"])
11.5Binding patterns
Binding patterns are used when destructuring values in variable declarations and function parameter declarations (i.e. in ScriptArrowFunction).
Javascript binding pattern production: BindingPattern without yield
, await
, Elision and ComputedPropertyName.
Example № 51[a, b = 2, ...c]
Example № 52{ a, b = 2, c: x = 3, ...d }
11.6Arrow function
Arrow functions are the only way to declare callable items in the script. They can be passed to built‐in methods like Array.map
or in the most complex cases used as immediately‐invoked function expressions (e.g. (() => 1)()
).
Example № 53([a, b, c = 1]) => { return a + b ** c; }
yield
, await
and where FunctionBody is replaced by ScriptStatementlistopt.11.7Statements
Statements are usually not relevant in the script, as expressions should be preferred instead.
The allowed Javascript statement productions have the following caveats recursively:
- Each production without
yield
,await
and Declaration - IterationStatement without
for/in
and without async variants - AssignmentExpression production replaced by ScriptExpression
- Statement production replaced by ScriptStatement
The allowed Javascript statement productions are:
- LexicalDeclaration (
let
,const
) - BlockStatement
- ExpressionStatement
- IfStatement
- BreakableStatement (
for
,for/of
,while
,do/while
,switch
) - ContinueStatement, BreakStatement, ReturnStatement where appropriate
- LabelledStatement
Example № 54return 1;
Example № 55{
let x = 1;
for (const y of [1, 2, 3]) {
x += y;
}
if (x == 7) {
return null;
}
}
12Language
12.1Source text
12.1.1Comments
Example № 56// This is a comment
12.1.2Line Terminators
12.2Common Definitions
12.2.1Identifier
12.2.2Profile Identifier
Identifier of a profile regardless its version.
Example № 57character-information
Example № 58starwars/character-information
12.2.3Full Profile Identifier
Fully disambiguated identifier of a profile including its exact version.
Example № 59character-information@2.0.0
Example № 60starwars/character-information@1.1.0
12.2.4Map Profile Identifier
Profile identifier used in maps does not include the patch number.
Example № 61starwars/character-information@1.1
12.2.5Provider Identifier
12.2.6Service Identifier
Service identifier form provider’s definition. Generally used for specifying a service base (host) URL.
12.2.7URL Value
12.2.8Security Scheme Identifier
References the security scheme found within a provider definition.
12.2.9String Value
" | \ | / | n | r | t |
12.2.10Integer Value
AAppendix: Keywords
§Index
- Argument
- ArgumentList
- ArgumentListContinued
- Comment
- CommentChar
- Condition
- ContentLanguage
- ContentType
- DocumentNameIdentifier
- EscapedCharacter
- FullProfileIdentifier
- HTTPBody
- HTTPBodyValueDefinition
- HTTPCall
- HTTPHeaders
- HTTPMethod
- HTTPRequest
- HTTPRequestBodyAssignment
- HTTPRequestSlot
- HTTPResponse
- HTTPResponseSlot
- HTTPSecurity
- HTTPStatusCode
- HTTPTransaction
- Identifier
- IntegerValue
- Iteration
- KeyName
- LHS
- LineTerminator
- MajorVersion
- Map
- MapDocument
- MapError
- MapProfileIdentifier
- MapResult
- MapSlot
- MinorVersion
- NetworkCall
- Operation
- OperationArguments
- OperationCall
- OperationCallShorthand
- OperationCallSlot
- OperationFail
- OperationName
- OperationReturn
- OperationSlot
- PatchVersion
- Profile
- ProfileIdentifier
- ProfileName
- ProfileScope
- Provider
- ProviderIdentifier
- RHS
- ScriptArrayLiteral
- ScriptArrayLiteralElement
- ScriptArrowFunction
- ScriptAssignmentExpression
- ScriptAssignmentOperator
- ScriptBinaryExpression
- ScriptBinaryOperator
- ScriptBindingPattern
- ScriptCallExpression
- ScriptExpression
- ScriptIdentifier
- ScriptKeyword
- ScriptLiteral
- ScriptObjectLiteral
- ScriptObjectLiteralAssignment
- ScriptPrimitiveLiteral
- ScriptReservedWord
- ScriptStatement
- ScriptTernaryExpression
- ScriptUnaryExpression
- ScriptUnaryOperator
- SecuritySchemeIdentifier
- SemanticVersion
- ServiceIdentifier
- SetMapErrorVariables
- SetMapOutcome
- SetMapResultVariables
- SetOperationFailVariables
- SetOperationOutcome
- SetOperationReturnVariables
- SetOutcome
- SetVariables
- SourceCharacter
- StringCharacter
- StringValue
- URLPath
- URLPathLiteral
- URLPathSegment
- URLPathVariable
- URLQuery
- URLTemplate
- URLValue
- UsecaseName
- VariableKeyPath
- VariableName
- VariableStatement
- VariableStatements
- Variant