Comlink Map Reference
Comlink Map is a format for describing how an API provider's services map to the use-cases in a Comlink Profile.
Map Details
profile
- the profile identifier to which the map corresponds- can be written without version:
starwars/character-information
- can be written with version omitting the patch number:
starwars/character-information@1.1
- can be written without version:
provider
- corresponds to the provider identifier found in the Provider Definitionvariant
(optional) - allows for multiple maps for the same profile and provider
profile = "conversation/send-message"
provider = "some-telco-api"
map SendMessage {
...
}
map RetrieveMessageStatus {
...
}
Use-Case Maps
Map to a use-case using the map <use-case-name>
statement. Use-cases may define and expect inputs from the user. These inputs are defined in the profile. A Use-Case Map can have multiple HTTP Calls defined within it.
HTTP Call
The HTTP Call uses http
and defines the information needed to make a call and map the inputs, result, and error to the profile use-cases.
- HTTP Method - Comlink supports all widely-support HTTP methods
- URI Template - URI template as defined by RFC6570
- HTTP Transaction - a scope that defines the HTTP Security, HTTP Request, and HTTP Responses for a given HTTP Call.
The example below shows an HTTP Call that uses the HTTP method POST
and the URI template /api/messages
.
profile = "<profile-name>@<version>"
provider = "<provider-name>"
map UseCaseName {
http POST "/api/messages" {
}
}
HTTP Security
You can define the security requirements for an HTTP transaction that align with the security schemes in a provider definition. If no security requirement is provided, the default is none
. The security requirement is enclosed within double quotes "
.
This example shows a POST
HTTP call to the provider's default service on path /api/messages
.
http GET "/public-endpoint" {
security "api_key_scheme_id"
response {
# ...
}
}
HTTP Request
The HTTP Request uses request
and is optional. It defines the request for the HTTP Transaction. It can include URL query parameters, HTTP headers, and a body. It can also include the content type and specify different services included in the provider definition.
This shows an example of an HTTP request.
profile = "<profile-name>@<version>"
provider = "<provider-name>"
map UseCaseName {
http POST "/api/messages" {
security "scheme-id"
request "application/json" {
query {
from = input.from
}
body {
to = input.to
text = input.text
}
}
}
}
The definition makes a call to /api/messages?from=...
with body of content type application/json
including object with two parameters to
and text
.
Path Parameters
You can reference variables in URI template with {variable}
syntax. This is a simple variable substitution, non-string values are converted to their JSON equivalents.
http GET "/messges/{input.id}" {
response {
# ...
}
}
Query Parameters
A query
maps query parameters to their values. Variables are accessible here, so input
may be used to map profile inputs to query parameters.
This example shows how to map an HTTP Request with a myName
query parameter to the value "John"
.
http GET "/greeting" {
request {
query {
myName = "John"
}
}
}
HTTP Headers
The headers
property maps HTTP headers to their values. Variables are accessible here, so input
may be used to map profile inputs to HTTP headers. If an HTTP header name contains a hyphen, enclose the name in double quotes.
http POST "/users" {
request "application/json" {
headers {
"my-header" = 42
}
}
}
HTTP Request Body
The body
property maps body properties to their values.
This example shows a request body mapped to an object.
http POST "/users" {
request "application/json" {
body = {
key = 1
}
}
}
Arrays may also be used.
http POST "/users" {
request "application/json" {
body = [1, 2, 3]
}
}
HTTP Response
An HTTP Response describes the responses for a transaction that map the response to the profile's result or error. An HTTP Transaction can have multiple responses based on HTTP status codes and content types. This allows for handling many different types of responses and mapping them into the use-case's result
and error
definitions.
A response has a:
- status code
- content type
- content language (optional)
- response block
Response variables
The following variables are available in a response block. These can be used to map response data to use-case results or errors. They can also be used to conditionally map to results or errors.
statusCode
(number): HTTP response status codeheaders
(object): HTTP response headersbody
(object): HTTP response body
This example shows where response variables are available.
profile = "<profile-name>@<version>"
provider = "<provider-name>"
map UseCaseName {
http POST "/api/messages" {
security "scheme-id"
request "application/json" { /* ... */ }
response 201 "application/json" {
// code in this block can reference `statusCode`, `headers` and `body`
}
}
}
Map a Use-Case Result
You can map to a use-case result using a map result
statement. You must resolve the same result
as defined in the use-case.
profile = "<profile-name>@<version>"
provider = "<provider-name>"
map UseCaseName {
http POST "/api/messages" {
security "scheme-id"
request "application/json" { /* ... */ }
response 201 "application/json" {
map result {
messageId = body.message_sid
remainingMessages = headers["X-CREDIT-LEFT"] / 0.3
}
}
}
}
The above definition maps the two expected result fields. One from the response's body and the other is from the headers, which is then transformed with a Comlink expression.
Map to a Use-Case Error
You can also map a response to a use-case error using the map error
statement. Like when mapping to a result
, you must resolve the same error
as defined in the use-case.
profile = "<profile-name>@<version>"
provider = "<provider-name>"
map UseCaseName {
http POST "/api/messages" {
security "scheme-id"
request "application/json" { /* ... */ }
response 201 "application/json" { /* ... */ }
response 429 {
map error {
title = "Sending messages too frequently"
details = (`You can send more message after ${headers['Retry-After']} seconds`)
}
}
}
}
This maps to the two expected error fields when the server responds with status 429 (Too Many Requests)
. One is hardcoded as it describes the error scenario, the other constructs a helpful message with a value from response headers using a simple Comlink expression.
note
map error
Comlink statement and can happen from anywhere inside the use-case mapping, not only from an inside of the response handler.
Multiple Response Mappings
You may map multiple responses in a single HTTP Transaction. This is how to match different status codes for a single request.
The example belows shows a single POST
with responses for multiple success and error HTTP Responses.
profile = "communication/send-email@1.1"
provider = "postmark"
map SendEmail {
http POST "/email" {
security "server_token"
request "application/json" {
body {
From = input.from
To = input.to
Subject= input.subject
TextBody = input.text
HtmlBody = input.html
}
}
response 200 "application/json" {
map result {
messageId = body.MessageID
}
}
response 422 "application/json" {
map error {
title = "Invalid inputs"
detail = body.Message
}
}
response 401 "application/json" {
map error {
title = "Unauthorized"
detail = body.Message
}
}
response 403 "application/json" {
map error {
title = "Forbidden"
detail = body.Message
}
}
response 500 "application/json" {
map error {
title = "Internal server Error"
detail = body.Message
}
}
}
}
Conditional Response Mappings
Sometimes more conditions are needed to map HTTP responses to the profile results and errors. For this, you can conditionally handle mappings.
This example shows how to map a result if body.ok
is truthy or map an error if body.ok
is falsey.
http POST "/users" {
response 201 "application/json" {
map result if(body.ok) {
...
}
map error if(!body.ok) {
...
}
}
}
Specification
There are more features of the Comlink Map. Please refer to the specifications for more information.