This document describes in details the exchange format (or language) used by the Unitag Engine API.
Table of Contents generated with DocToc
- Introduction
- The
Operationobject - The
Inputobject - The
Stepobject - The
Testobject - The
Actionsobject - The
Resolverobject - Access URL
- The expression language
- Miscellaneous
The Unitag Engine API allows to easily create and manage data-driven scenarios, called operations. These scenarios are expressed using structured JSON documents, whose format is detailed below.
As a lightweight and efficient serialization format, JSON is a perfect solution for describing complex structured documents like operations. Yet it does not suit well for describing common expressions such as interpreting variables or computing values.
To fill this gap, the Unitag Engine is able to parse and evaluate a markup syntax within JSON strings, for instance: <((env.connection.ip))>. This allows to embed a special expression language, which is largely inspired by JavaScript expressions, but with several useful specificities (see the expression language for more details). In the bellow documentation, the fields descriptions are often accompanied by a "Markup" column, which indicates whether a given field is allowed to embed some markup.
An Operation is a standalone document describing an HTTP application. It is expressed as a JSON object, which allows to specify:
- how the application can be reached
- which routes are exposed
- which input data are needed
- how input data are processed
- which output data are produced
- which external actions are triggered
The root object looks like the following:
Operation = {
"url": Resolver | [Resolver],
"state": String,
"label": String,
"needs": String | [String],
"input": Input | [Input],
"entryPoints": {Step},
"index": Step
}| Field | Description | Markup |
|---|---|---|
url |
Describes how this operation can be reached. Can be a single value or an array (but always returned as an array). In its simplest form, this field can contain a single string, which is sufficient to make the operation reachable through an URL of the following form: http://e.unitag.io/r/{YOUR PATH HERE}. See the Resolver object for more details. |
No |
state |
Describes the publication state of this operation. Possible values are NOT_PUBLISHED, PUBLISHED, UNPUBLISHED and BLOCKED. The PUBLISHED and UNPUBLISHED states can be written, the others are read-only. |
No |
label |
Defines an arbitrary name for this operation (generated by default). | No |
needs |
Defines the environment values needed by this operation. TODO: more details needed here. | No |
inputs |
Defines which data is needed globally for this operation. Can be a single value or an array. See the Input object for more details. | No |
entryPoints |
Defines the set of routes implemented by this operation. Each entry point is a key-value pair: the key defines an URL path, while the value defines the associated processing as a hierarchy of steps. See the Step object for more details. | No |
index |
Stands as a shortcut for entryPoints.index. This is because the index step has a special meaning: it is the default step, which is accessed when no entry point is specified in the URL. |
No |
The publication state controls whether an operation is publicly available or not. This state can have the following values:
| State | Description |
|---|---|
NOT_PUBLISHED |
The operation has never been published (default). |
PUBLISHED |
The operation is currently published. This is the only state where it can be accessed from the URL(s) defined by its resolver(s). |
UNPUBLISHED |
The operation has already been published, but is not published anymore. |
BLOCKED |
The operation was published, but has been blocked for some reason by an administrator. |
The following minimal example, which creates a simple redirection to Google, can be considered as a starting point:
{
"url": "{YOUR PATH HERE}",
"state": "PUBLISHED",
"index": "http://www.google.com"
}Additionnal examples are available in the API documentation.
An input object allows to define a set of data to be injected in the evaluation context. It definition looks like the following:
Input = {Connector} + {
"$then": Input | [Input]
}
Connector = DataConnector | CsvConnector | FileConnector |
VisitsConnector | LastVisitConnector | ParamsConnector |
ActionLogResultConnector | ActionLogCountConnectorSo, an input object is basically a map of connectors, where the key defines the name of the resulting value (accessible through <((io.name))> after evaluation), and the value defines how to produce the resulting value.
The value can be either:
- a typed connector, which is expressed as an object containing a single
$-prefixed key. The key denotes the connector's type, and its associated value defines the connector's parameters. - a raw value, which is any value that does not match the format of typed connectors. It is directly used as the resulting value.
The special $then field allows to define another set of connectors, which is evaluated only once all the other connectors are loaded. This can be used to load intermediate results, and then compute complex values based on them. See the evaluation order for more details.
The data connector is the simplest connector: it allows to inject some arbitrary data into the evaluation context. Such a connector looks like the following:
DataConnector = Boolean | Number | String | Object | Array | {
"$data": Boolean | Number | String | Object | Array
}As stated above, any raw value is implicitly interpreted as a data connector. But, although rarely useful, a data connector can also be expressed as a typed connector (using the $data key).
The CSV connector allows to retrieve a remote CSV file and to inject its parsed content into the evaluation context. Such a connector looks like the following:
CsvConnector = {
"$csv": String | {
"url": String | Url
}
}When specified as a single String, the connector definition is directly interpreted as the url field.
| Field | Description | Markup |
|---|---|---|
url |
Defines the URL of the remote CSV file. It can be any valid URL string, or a parsed URL object. TODO: more details here. | Yes, but only the string format is accepted |
The file connector allows to load a file and to inject its content into the evaluation context. Such a connector looks like the following:
FileConnector = {
"$file": String | RemoteFile | UploadedFile
}
RemoteFile = {
"url": String | Object,
"encoding": String
}
UploadedFile = {
"filename": String,
"encoding": String
}When specified as a single String, the connector definition is directly interpreted as the url field of a RemoteFile.
| Field | Description | Markup |
|---|---|---|
url |
Defines the URL of a remote file. It can be any valid URL string, or a parsed URL object. TODO: more details here. | Yes, but only the string format is accepted |
filename |
Defines the name of an uploaded file, which can be obtained from the <((params.file))> object. |
Yes |
encoding |
Optionally specifies the encoding of the loaded file: utf8, base64, hex or ascii. Default is base64. |
Yes |
The visits connector allows to retrieve the number of times a given step or this operation has been accessed.
VisitsConnector = {
"$visits": String | {
"step": String,
"from": Date,
"to": Date,
"duration": Number,
"unit": String
}
}When specified as a single String, the connector definition is directly interpreted as the step field.
| Field | Description | Markup |
|---|---|---|
step |
Defines the step to consider. By default, consider all accesses to this operation. | Yes |
from |
Defines the lower bound of the time period taken into account. Unlimited by default. | Yes, but only a numeric timestamp is accepted |
to |
Defines the upper bound of the time period taken into account. Unlimited by default. | Yes, but only a numeric timestamp is accepted |
duration |
Defines the length of the time period taken into account. Default is unlimited if no unit is specified, 1 otherwise. |
Yes |
unit |
Defines the unit of the duration field. Can be millisecond, second, minute, hour or day. Default is millisecond. |
Yes |
There are several ways for specifying the time period:
- When both
fromandtoare specified, they define the exact bounds of the time period. - When either
fromortois specified, the time period is defined by that bound, and an eventual duration. - When neither
fromnortonor a duration is specified, the time period is unlimited. - When only a duration is specified, a time period of this duration is automatically selected around the current time. This period is always a slice of the upper time unit. For example, if the duration is 10 minutes, each hour is splitted into 6 slices of 10 minutes. Then, the selected time period is the slice that contain the current time. If the upper unit is not dividable by the requested duration, an incomplete slice is produced. For example, a duration of 25 minutes splits each hour into 2 slices of 25 minutes and a slice of 10 minutes.
The last visit connector allows to retrieve the date (and time) of the last access to a given step or to this operation.
LastVisitConnector = {
"$lastVisit": String | {
"step": String,
"from": Date,
"to": Date
}
}When specified as a single String, the connector definition is directly interpreted as the step field.
| Field | Description | Markup |
|---|---|---|
step |
Defines the step to consider. By default, consider all accesses to this operation. | Yes |
from |
Defines the lower bound of the time period taken into account. Unlimited by default. | Yes, but only a numeric timestamp is accepted |
to |
Defines the upper bound of the time period taken into account. Unlimited by default. | Yes, but only a numeric timestamp is accepted |
The parameters connector allows to retrieve all input parameters supplied upon access to a given step.
ParamsConnector = {
"$params": String | {
"step": String,
"from": Date,
"to": Date,
"output": String | [String] | {String},
"sort": Number,
"skip": Number,
"limit": Number
}
}When specified as a single String, the connector definition is directly interpreted as the step field.
| Field | Description | Markup |
|---|---|---|
step |
Defines the step to consider. "index" by default. |
Yes |
from |
Defines the lower bound of the time period taken into account. Unlimited by default. | Yes, but only a numeric timestamp is accepted |
to |
Defines the upper bound of the time period taken into account. Unlimited by default. | Yes, but only a numeric timestamp is accepted |
output |
Defines how the results are generated from the HTTP parameters. See below for details on how to specify this field. Default is "params". |
Yes |
sort |
Defines the sorting order of results. Can be either -1 (newest first), 1 (oldest first) or 0 (unordered). Unordered by default. |
Yes |
skip |
Defines a number of results to be skipped. Especially useful in combination with sort and limit for pagination. No result is skipped by default. |
Yes |
limit |
Defines the maximal number of results to be returned. All results are returned by default. | Yes |
For each access, the following data is available:
{
"creationTime": Date,
"params": {
"url": {},
"body": {},
"cookie": {},
"files": {}
}
}| Field | Description |
|---|---|
creationTime |
The date (and time) of the access. |
params |
The HTTP parameters. Reflects what was injectable through <((io.params))> at runtime. |
The connector produces an array in which each item has been built from the input parameters supplied upon an access. The output field allows to define how to build these items. It consists in one or more strings that reference fields of the above object using the dot-notation. The structure of the output field (single value, array or map) is then replicated for each resulting item, with all references replaced by the targeted values.
For example, let's consider the following output field:
{
"date": "creationTime",
"form": "params.body"
}Assuming that the connector was configured on a step that accepts an HTTP form, we could obtain this kind of result:
[
{
"date": Date("Thu, 01 Jan 1970 00:00:00 GMT"),
"form": {
"firstname": "Chuck",
"lastname": "Norris"
}
},
{
"date": Date:("Sun, 25 Aug 1991 20:57:08 GMT"),
"form": {
"firstname": "Linus",
"lastname": "Torvalds"
}
}
]The action log result connector allows to retrieve the results produced by the given action(s). Note that only results of actions with the log flag can be retrieved.
ActionLogResultConnector = {
"$actionLogResult": String | {
"actionName": String,
"actionType": String,
"step": String,
"from": Date,
"to": Date,
"sort": Number,
"skip": Number,
"limit": Number
}
}When specified as a single String, the connector definition is directly interpreted as the actionName field.
| Field | Description | Markup |
|---|---|---|
actionName |
Defines the name of the action(s) to consider. By default, consider actions with any name. | Yes |
actionType |
Defines the type of the action(s) to consider. By default, consider actions with any type. | Yes |
step |
Defines the step to consider. By default, consider all accesses to this operation. | Yes |
from |
Defines the lower bound of the time period taken into account. Unlimited by default. | Yes, but only a numeric timestamp is accepted |
to |
Defines the upper bound of the time period taken into account. Unlimited by default. | Yes, but only a numeric timestamp is accepted |
sort |
Defines the sorting order of results. Can be either -1 (newest first), 1 (oldest first) or 0 (unordered). Unordered by default. |
Yes |
skip |
Defines a number of results to be skipped. Especially useful in combination with sort and limit for pagination. No result is skipped by default. |
Yes |
limit |
Defines the maximal number of results to be returned. All results are returned by default. | Yes |
The action log count connector allows to retrieve the number of times the given action(s) has been triggered. Note that only actions with the log flag can be counted.
ActionLogCountConnector = {
"$actionLogCount": String | {
"actionName": String,
"actionType": String,
"step": String,
"from": Date,
"to": Date
}
}When specified as a single String, the connector definition is directly interpreted as the actionName field.
| Field | Description | Markup |
|---|---|---|
actionName |
Defines the name of the action(s) to consider. By default, consider actions with any name. | Yes |
actionType |
Defines the type of the action(s) to consider. By default, consider actions with any type. | Yes |
step |
Defines the step to consider. By default, consider all accesses to this operation. | Yes |
from |
Defines the lower bound of the time period taken into account. Unlimited by default. | Yes, but only a numeric timestamp is accepted |
to |
Defines the upper bound of the time period taken into account. Unlimited by default. | Yes, but only a numeric timestamp is accepted |
The connectors defined in the same input object are implicitly evaluated in parallel. Thus, a connector cannot use a value produced by one of its siblings.
However, there are two ways for controlling the evaluation order of connectors:
- An input object can define a special
$thenkey. It allows to define another input object (or an array) which is processed only once all the connectors of the current object have been evaluated. The resulting values of these connectors can be injected in the$thenfield using the markup syntax. - When an array of input objects is specified, its items are evaluated in parallel. When coupled with
$then, this allows to define several independent evaluation chains.
As shown in the following example, these techniques can cohabit in order to define complex and/or deep dependency graphs. However, most use cases will involve implicit parallel definitions, which are easy to express and evaluated efficiently.
Caution: this example addresses complex situations. Beginners may skip this part at first.
To illustrate the previous section, let's consider the following input object (for the sake of simplicity, connector definitions have voluntary been replaced by empty objects {}):
[
{
"a": {},
"b": {},
"$then": [
{
"c": {}
},
{
"d": {},
"e": {},
"$then": {
"f": {}
}
}
]
},
{
"g": {}
}
]This declaration can mentally be represented as follows:
+---+
,----| c |
+---+ / +---+
| a | /
,----| |----:
/ | b | \ +---+
/ +---+ \ | d | +---+
----: `----| |----| f |
\ | e | +---+
\ +---+ +---+
`----| g |
+---+
Now, more verbosely, here is what would happen at evaluation time:
- Two evaluation chains start in parallel (two items in the top-level array).
- The first chain follows the following steps:
- Connectors
aandbare evaluated in parallel. - When
aandbhave completed, two new evaluation chains start in parallel (two items in the$thenfield):
- The first chain simply evaluates the
cconnector. - The second chain follows the following steps:
- Connectors
dandeare evaluated in parallel. - When
dandehave completed, thefconnector is evaluated.
- Connectors
- Connectors
- The second chain simply evaluates the
gconnector.
- All connectors have properly been evaluated, and the resulting values can now been accessed using the markup syntax (
<((io.a))>...<((io.g))>).
This example just aims at providing an overview of ordering capabilities. It is voluntarily complex and does not reflect a particular use case (see below for a more realistic example). However, it illustrates well how evaluation chains can be powerful. For instance, if evaluating the g connector is particularly expensive, it will not block nor affect in any way the other evaluation chain. Both will progress concurrently, and will be waited transparently for processing the following tasks.
TODO
A step is fundamentally a piece of logic. There are two kinds of step:
- A transitional step allow to take decisions by conditionally redirecting to another step.
- A terminal steps allows to generate an HTTP response, thus ending a chain of transitional steps.
Steps can be seen as statements in a standard programming language: transitional steps mimic control flow structures, while terminal steps mimic regular instructions (with potential side-effects).
Step = RedirectStep | VcardStep | ResponseStep | UmeStep |
SwitchStep | IfStep | GotoStep | TryStepA step generally looks like the following:
BaseStep = {
"label": String,
"input": Input | [Input],
"trigger": Actions | [Actions]
}| Field | Description | Markup |
|---|---|---|
label |
Defines a name for this step. It is mandatory when the step needs to be referenced (connectors, goto steps and analytics). |
No |
input |
Defines which data is needed locally for this step and its potential descendants. Can be a single value or an array. See the Input object for more details. | No |
trigger |
Defines the action(s) to be triggered when accessing this step. Can be a single value or an array. See the Actions for more details. | No |
A redirection step is a terminal step that allows to send an HTTP redirection.
RedirectStep = String | BaseStep + {
"redirect": String | Url
}When the whole step definition is given as a single string, it is implicitly interpreted as the redirect field of a RedirectStep.
| Field | Description | Markup |
|---|---|---|
redirect |
Defines the destination of the HTTP redirection. It can be any valid URL string, or a parsed URL object. TODO: more details here. | Yes, but only the string format is accepted |
A vCard step is a terminal step that allows to send a vCard file.
VcardStep = BaseStep + {
"vcard": Vcard
}| Field | Description | Markup |
|---|---|---|
vcard |
Defines the vCard content. See the vCard object for more details. | Yes |
A response step is a terminal step that allows to send an arbitrary textual or JSON response.
ResponseStep = BaseStep + {
"response": Boolean | Number | String | Array | {
"status": Number,
"body": Boolean | Number | String | Object
}
}| Field | Description | Markup |
|---|---|---|
response |
Defines the HTTP response. If a primitive type or an array is given, it is implicitly interpreted as the body field. |
Yes, but interpreted as the body field |
response.status |
Defines the HTTP status code. Defaults to 200 (OK). | No |
response.body |
Defines the response data. A string is sent as a textual response (text/plain) while any other data type is sent as JSON (application/json). |
Yes |
An U.me step is a terminal step that allows to render an HTML page.
UmeStep = BaseStep + {
"ume": Ume,
"mode": String
}| Field | Description | Markup |
|---|---|---|
ume |
Defines the structure of the rendered page. See the U.me documentation for more details. Note that a single-page U.me is expected. | Yes |
mode |
Defines the rendering mode, which defaults to components. The classic mode may be used for backward compatibility. |
No |
A switch/cases/default step is a transitional step that allows to test a given value against multiple conditions in order to select the following step.
SwitchStep = BaseStep + {
"switch": Boolean | Number | String | Object,
"cases": {Step} | [Option],
"default": Step
}| Field | Description | Markup |
|---|---|---|
switch |
Defines the value to be tested. | Yes |
cases |
Defines the tests to be performed, along with their respective destination steps. In its canonical form, this field is expressed as an array of options. The first encountered matching option (if any) triggers the evaluation of its destination step (see the Option object for more details). In addition, a simpler alternative allows to express this field as a key-value map: if a key is equal to the tested value, then its associated step is directly evaluated. | No |
default |
Defines the default step, which is evaluated if no match is found in the cases field. |
No |
A if/then/else step is a transitional step that allows to perform a boolean test in order to select the following step. In fact, it is a simplified form of the switch/cases/default step.
IfStep = BaseStep + {
"if": Boolean,
"then": Step,
"else": Step
}| Field | Description | Markup |
|---|---|---|
if |
Defines the tested boolean. This value is likely to be obtained from a markup expression. | Yes |
then |
Defines the step that is evaluated if the tested value is true. |
No |
else |
Defines the step that is evaluated if the tested value is not true (this includes non-boolean values). |
No |
A goto step is a transitional step that allows to unconditionnaly evaluate a specific step.
GotoStep = BaseStep + {
"goto": String | Step
}| Field | Description | Markup |
|---|---|---|
goto |
Defines the step to be evaluated. When expressed as a string, it allows to jump to the step that defines this specific label. This should be avoided, and reserved for situations where it is absolutely necessary. |
No |
A try/catch/then step is a transitional step that allows to...
TryStep = BaseStep + {
"try": Test | [Test],
"catch": Step,
"then": Step
}Test = {
"enabled": Boolean,
"label": String,
"input": Input | [Input],
"trigger": Actions | [Actions],
"value": Boolean | Number | String | Object,
"assert": Boolean | Number | String | Assertion | [Assertion],
"catch": Step
}An Actions object allows to define a set of actions that are triggered upon step evaluation.
Actions = {
"enabled": Boolean,
"logged": Boolean,
"waited": Boolean,
"data": DataAction | [DataAction],
"email": EmailAction | [EmailAction],
"sms": SmsAction | [SmsAction],
"cookie": CookieAction | [CookieAction],
"upload": UploadAction | [UploadAction]
}| Field | Description | Markup |
|---|---|---|
enabled |
Defines whether these actions are enabled. Can be overridden on a per action basis, and defaults to true. |
Yes |
logged |
Defines whether these actions are expected to be logged in the database. Can be overridden on a per action basis. The default value depends on the action type. Some action types may also force this flag to a fixed value. | Yes |
waited |
Defines whether these actions are expected to be waited before evaluating the rest of the step. Can be overridden on a per action basis. The default value depends on the action type. Some action types may also force this flag to a fixed value. | Yes |
data |
Defines the data action(s), if any. | No |
email |
Defines the email action(s), if any. | No |
sms |
Defines the SMS action(s), if any. | No |
cookie |
Defines the cookie action(s), if any. | No |
upload |
Defines the upload action(s), if any. | No |
An action generally looks like the following:
BaseAction = {
"enabled": Boolean,
"logged": Boolean,
"waited": Boolean,
"output": String
}| Field | Description | Markup |
|---|---|---|
enabled |
Defines whether this action is enabled. Defaults to the common enabled flag (from the Actions object). |
Yes |
logged |
Defines whether this action is expected to be logged in the database. Defaults to the common logged flag (from the Actions object). Some action types may also force this flag to a fixed value. |
Yes |
waited |
Defines whether this action is expected to be waited before evaluating the rest of the step. Defaults to the common waited flag (from the Actions object). Some action types may also force this flag to a fixed value. |
Yes |
output |
Defines the output name of this action. This makes the action result accessible like this: <((out.{OUTPUT_NAME}))>. It may also be useful for selecting actions by their name in the action log connectors (using the actionName field). |
No |
A data action allows to record some arbitrary data. No external action is actually performed. However, along with the output field, this can be useful in the following situations:
- Thanks to the
outputfield, it is possible to assign – and even reassign – an arbitrary value to a custom variable within the<((out))>object. - By enabling the
loggedflag, it is possible to permanently store some arbitrary data, in order to process them later using the action log connectors.
| Flag | Behavior |
|---|---|
logged |
Defaults to false |
waited |
Defaults to true |
DataAction = BaseAction + {
"value": Boolean | Number | String | Object
}| Field | Description | Markup |
|---|---|---|
value |
Defines the arbitrary value produced by this action. | Yes |
An email action allows to send a custom email.
| Flag | Behavior |
|---|---|
logged |
Forced to true |
waited |
Defaults to false |
EmailAction = BaseAction + {
"from": String | [String] | Object | [Object],
"to": String | [String] | Object | [Object],
"cc": String | [String] | Object | [Object],
"bcc": String | [String] | Object | [Object],
"subject": Boolean | Number | String | Object,
"body": Boolean | Number | String | Object,
"attachment": Attachment | [Attachment]
}Attachment = {
"text": TextAttachement | [TextAttachement],
"vcard": Vcard | [Vcard],
"upload": File | [File]
}TextAttachement = String | {
"filename": String,
"content": String
}An SMS action allows to send a custom text message.
| Flag | Behavior |
|---|---|
logged |
Forced to true |
waited |
Defaults to false |
SmsAction = BaseAction + {
"destination": String,
"text": Boolean | Number | String | Object
}An cookie action allows to set a custom HTTP cookie.
| Flag | Behavior |
|---|---|
logged |
Defaults to false |
waited |
Forced to true |
CookieAction = BaseAction + {
"key": Boolean | Number | String,
"value": Boolean | Number | String | Object,
"age": Number
}An upload action allows to permanently store a file.
| Flag | Behavior |
|---|---|
logged |
Defaults to true |
waited |
Defaults to false |
UploadAction = BaseAction + {
"file": String | File,
"alterations": [Alteration]
}
File = {
"path": String,
"filename": String,
"contentType": String
}
Alteration = /TODO/A Resolver allows to specify how the operation can be reached. Each resolver basically defines an URL from which the underlying operation is made accessible. Additionally, it is possible to create a typed resolver, which allows to associate one ore more communication media to the access URL.
Resolver = String | RawResolver | QrcodeResolver | ImageResolverA Resolver generally looks like the following:
RawResolver = {
"host": String,
"name": String,
"label": String
}When a resolver is specified as single String, it is interpreted as the name of a RawResolver.
| Field | Description | Markup |
|---|---|---|
host |
Defines the host on which the resolver is created (optional). Public hosts are available by default, but custom domains can be added upon request. | No |
name |
Defines the name of this resolver, which is used as the URL path. | No |
label |
Specifies an arbitrary label for this resolver (optional). | No |
A resolver can be used as a QR code channel. This means that one or more QR code(s) can be associated to the resolver in order to help the diffusion of the underlying operation. A QR code resolver looks like the following:
QrcodeResolver = RawResolver + {
"type": "qrcode",
"design": QrcodeDesign | [QrcodeDesign]
}| Field | Description | Markup |
|---|---|---|
type |
Defines the type of channel (QR code here). | No |
design |
Describes the design(s) of the generated QR code(s). TODO: more details needed here. | No |
A resolver can be used as an image recognition channel. This means that one or more interactive image(s) can be associated to the resolver in order to make them recognizable by Unitag QR Code Scanner. When such an image is scanned by this application, the user is redirected to the underlying operation. An image resolver looks like the following:
ImageResolver = RawResolver + {
"type": "image",
"image": Number | [Number]
}| Field | Description | Markup |
|---|---|---|
type |
Defines the type of channel (image recognition here). | No |
image |
Describes the uploaded image(s) that should be associated to this resolver. TODO: more details needed here. | No |
By default, the following domain names can be used in the host field of a resolver:
| Domain name | Path prefix | Description |
|---|---|---|
e.unitag.io |
/r |
This is the default domain name, which is used when no host is specified. |
opn.to |
/r |
This is a freely usable white-label domain. |
Once create and published, an operation can be reached from the web through an URL of the following form:
+--> Targets an operation <-+
| |
http://:resolverHost[/:pathPrefix]/:resolverPath/:entryPoint
| |
+--> Fixed by the host +--> Targets an entry point
The entryPoint is optional, and defaults to index. The other URL components are defined by the resolver(s).
Predicate = {
"eq": Boolean | Number | String | Object,
"ne": Boolean | Number | String | Object,
"lt": Boolean | Number | String | Object,
"gt": Boolean | Number | String | Object,
"lte": Boolean | Number | String | Object,
"gte": Boolean | Number | String | Object
// Other tests
}Vcard = /TODO/