Service interfaces
As described in the concepts chapter, Automatiko exposes workflows as services. These services can be directly used by consumers meaning they act as entry points of the API. Depending on the workflow design there might be various ways how to interact with these services:
-
REsT interface
-
GraphQL interface
-
Message based interface (limited to trigger)
REsT interface
REsT interface is the default and always present service interface. That means each public workflow definition will have dedicated endpoint created for it and named based on workflow definition id.
So when there is a workflow definition that processes orders with following
-
workflow definition id -
orders
-
workflow definition name -
Process incoming orders
-
version -
1.0
Then the REsT service interface will be created with following path /v1_0/orders
It will have number of additional endpoints (under the main path /v1_0/orders
) created to expose additional
capabilities of the service based on workflow definition. To name some
-
user tasks - each user task will have three endpoints to
-
get task inputs
-
complete task
-
abort task
-
-
signals - each signal event will have dedicated endpoint
-
subprocesses - each subprocess will have dedicated endpoints based on sub workflow definition
-
workflow definition image and workflow instance image
Versioned endpoints
ReST endpoints can be versioned based on the version attribute of the workflow definition. In case versions are in
use routing to latest version can be enabled. To make use of the routing following property needs to be set:
quarkus.automatiko.service-route-to-latest=true
inside the application.properties
file or via variables (env etc)
This will allow to use enpoints without the version prefix and by that target the latest one or the one given workflow instance belongs to. See version support in this section
GraphQL interface
In addition to REsT interface users can enhance their service with GraphQL interface. That is to allow more advanced operation to be performed that take advantage of under-fetching and over-fetching principles promoted by GraphQL.
It follows the same principle as REsT interfaces, each public workflow definition will have dedicated GraphQL operations created, including
-
user tasks
-
signal events
-
subprocesses
To enable GraphQL interface add following dependency to your project
<dependency>
<groupId>io.automatiko.addons</groupId>
<artifactId>automatiko-graphql-addon</artifactId>
</dependency>
Once that is added, service will be equipped with following capabilities of GraphQL that are based on workflow definition:
-
mutations - each operation that manipulates workflow instance will have dedicated mutation (e.g. start new instance, abort, etc)
-
queries - each operation that allows to retrieve workflow instance information will have dedicated query (e.g. list instances, get instance details, etc)
-
subscription - each workflow definition will have set of subscriptions available to get notifications when:
-
new instance is created
-
instance is completed
-
instance is aborted
-
instance fails (ends with error status)
-
instance is updated
-
In addition to above subscriptions there is also a generic userTasks
subscriptions that allows to get access to
user tasks managed by this service.
All subscriptions are security context aware meaning notifications are sent based on access rights of the caller who created subscription |
Subscriptions are based on websocket protocol so to create subscription from client side following code can be used
let ws = new WebSocket("ws://localhost:8080/graphql");
ws.onopen = function() {
ws.send('{ "query" : "subscription {userTasks(user:\\\"john\\\", groups:[]) {id, taskName, state, formLink}}"}');
};
This will subscribe to userTasks
as user john
so only user tasks that john
is allowed to work on will be delivered.
Errors from workflow definitions
Defining errors as part of workflow definition is a common practice. In some situations errors are the exit state of a given path of the workflow, meaning it will lead to completion of that instance. See more about error end events in this section.
An important aspect of the error end events is that service interface operations will be equipped with error information only when there is direct path to that error without any wait states in between.
Looking at the example workflow definition above there are three error end events:
-
Payment required (error code 402)
-
Length Required (error code 411)
-
Too Early (error code 425)
and here is how the end points of the service will be described with error responses
-
Payment Required
will be defined on update message operation as this is a a wait state (signal) -
Length Required
will be defined on the start instance end point as there are no wait states that lead to the error -
Too Early
will be defined on the user task end point as user task is also a wait state
Use of gateways will not be taken into account as from definition perspective it’s not possible to distinguish if given error will be encountered or not but it certainly can be and that’s why it is defined on the service interface operation level. |
Errors in ReST service interface
These errors (expressed as error end events
) are represented as additional responses of the ReST operation.
Such responses will follow normal definition and will include.
-
response code - based on error code thus it must be a valid HTTP response code (three digits)
-
schema of the response - based on error data type
With that information consumers of the ReST service interface have all the information required to properly interact with the service.
Errors in GraphQL service interface
GraphQL does not use response code as ReST do but instead all information is provided via response payload.
In case of an error, GraphQL response will have both errors
and data
provided
{
"errors": [
{
"message": "Process instance with id 098f6bcd-4621-3373-8ade-4e832627b4f6 was aborted with defined error code 411",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"create_errors"
],
"extensions": {
"classification": "DataFetchingException"
}
}
],
"data": {
"create_errors": {
"id": "test",
"name": "john",
"errorInfo": {
"details": "here is an error"
}
}
}
}
The main difference for GraphQL service interface is that the error information must be set for the workflow instance output model. The reason for that is GraphQL has only one message type defined for the output of the mutation and by that can only return single type of information. It is called partial results in GraphQL which is not complete but of the same type. |
Message based interface
Last but not least, service can also be equipped with message based interface such as
-
Apache Kafka
-
MQTT
-
Apache Camel components
The main difference for this interface (compared to REsT and GraphQL) is that it is tailored for just one
type of workflow constructs - message events
Message based interface is both inbound and outbound so it can consume and produce messages depending on the type of message event used within workflow definition (catching or throwing respectively).
To enable it one (or more) of the messaging providers must be added to your project. The easiest way is to use Automatiko archetypes to bootstrap project with defined dependencies. See Getting started guide for details.