When your project implements the Compact Architecture it natively integrates the Data-Index subsystem. One of the useful frameworks offered by this Service is GraphQL, which provides endpoints that can be consumed by client applications to run Process Instances, User Tasks, Jobs, and Process Definitions and also get other information about running process instances. GraphQL offers a very rich set of conditions to create a query according to your business needs.
The GraphQL functionalities can be consumed in two ways:
-
Using the GraphQL UI tool in Quarkus dev mode:
This tool is useful to experiment and create your own queries to run against your application. You can use it in the development phase by setting
quarkus.kogito.data-index.graphql.ui.always-include=true, and opening the GraphQL UI viahttp://localhost:8080/q/graphql-ui -
Using the
/graphqlentry point to make requests to GraphQL, which the Compact Architecture natively exposes.
The /graphql entry point is described in the following table.
| Type | POST |
|---|---|
Description |
It runs a provided GraphQL query against your application |
Inputs |
A GraphQL query |
Output |
A JSON that holds the result of your GraphQL query |
Example |
curl -X POST http://localhost:8080/graphql -H 'accept: application/json' -H 'Content-Type: application/json' -d '{ "query": "/* YOUR GRAPHQL QUERY */" }'
|
GraphQL query capabilities
GraphQL queries can be done on the different workflow types
Process Instances
ProcessInstances represents an instance of a running Workflow in the runtime environment. The state of a ProcessInstances can be tracked (e.g., active, completed, suspended, or aborted). A process instance may execute various tasks, handle events, interact with external services, and more, depending on the Process Definition.
Here is a sample query on ProcessInstances showing the different fields you can query:
{
ProcessInstances {
id
processId
version
processName
parentProcessInstanceId
rootProcessInstanceId
rootProcessId
roles
state
endpoint
serviceUrl
nodes {
id
name
type
enter
exit
definitionId
nodeId
slaDueDate
errorMessage
retrigger
}
milestones {
id
name
status
}
variables
start
end
parentProcessInstance {
id
}
childProcessInstances {
id
}
error {
nodeInstanceId
nodeDefinitionId
message
}
addons
lastUpdate
businessKey
nodeDefinitions {
id
metadata {
UniqueId
state
branch
action
}
name
type
uniqueId
}
diagram
source
definition {
id
}
identity
createdBy
updatedBy
slaDueDate
timers {
timerId
processId
processInstanceId
nodeInstanceId
description
}
}
}
User Tasks
UserTaskInstances are used to track the tasks that are part of a broader workflow, and the Kogito framework provides mechanisms to manage and interact with these tasks through different lifecycle stages. Using APIs, you can easily manage UserTaskInstances in business processes, including assigning tasks, tracking task states, and interacting with process variables.
Here is a sample query on UserTaskInstances showing the different fields you can query:
{
UserTaskInstances {
id
description
name
priority
processInstanceId
processId
rootProcessInstanceId
rootProcessId
state
actualOwner
adminGroups
adminUsers
completed
started
excludedUsers
potentialGroups
potentialUsers
inputs
outputs
referenceName
lastUpdate
endpoint
comments {
id
content
updatedBy
updatedAt
}
attachments {
id
name
content
updatedBy
updatedAt
}
externalReferenceId
slaDueDate
}
}
Jobs
Jobs are used to represent asynchronous or scheduled tasks that run in the background. They are primarily used for executing long-running processes, timers, and other scheduled tasks within a business process or workflow. Jobs are typically used to handle tasks like sending reminders, triggering specific actions after a delay, or performing periodic checks within a process.
Here is a sample query on Jobs showing the different fields you can query:
{
Jobs {
id
processId
processInstanceId
nodeInstanceId
rootProcessInstanceId
rootProcessId
status
expirationTime
priority
callbackEndpoint
repeatInterval
repeatLimit
scheduledId
retries
lastUpdate
executionCounter
endpoint
}
}
Process Definitions
A ProcessDefinitions represents the definition of a business process or workflow. It encapsulates the structure, rules, and logic that define how a process behaves. The ProcessDefinitions object is the model for a particular BPMN (Business Process Model and Notation) or other workflow-based process and includes all the details required to execute and manage that process within the runtime environment.
Here is a sample query on ProcessDefinitions showing the different fields you can query:
{
ProcessDefinitions {
id
name
version
nodes {
id
metadata {
UniqueId
state
branch
action
}
name
type
uniqueId
}
source
addons
roles
type
endpoint
serviceUrl
description
annotations
metadata
}
}
Filtering
Filtering typically refers to the ability to query and retrieve values based on specific criteria. Filtering can be extremely useful in scenarios where you want to track, manage, or analyse processes, tasks, or jobs by applying certain conditions or constraints (e.g., filter by status, user, date range, variables, etc.).
There are multiple mechanisms to filter ProcessInstances, UserTasksInstances, Jobs, and ProcessDefinitions.
For example here is an example of a query that will show all UserTaskInstances:
{
UserTaskInstances {
id
name
state
processInstanceId
actualOwner
lastUpdate
}
}
Which returns a list such as the following:
{
"data": {
"UserTaskInstances": [
{
"id": "c2caa8f3-fe14-4779-9745-bc2c62861d01",
"name": "HRInterview",
"state": "Error",
"processInstanceId": "8ca68693-1c38-4f96-ab36-1f20a164dfd2",
"actualOwner": "jdoe",
"lastUpdate": "2025-03-28T12:02:14.171Z"
},
{
"id": "f41664f4-ae79-4eaf-ad86-bdc1c1a06676",
"name": "HRInterview",
"state": "Error",
"processInstanceId": "cd9be754-96d0-4d4f-868b-d377bdab3962",
"actualOwner": "jdoe",
"lastUpdate": "2025-03-28T12:02:14.172Z"
},
{
"id": "b9df90d0-2f54-4a05-aefd-8878274258e7",
"name": "HRInterview",
"state": "Completed",
"processInstanceId": "69e8a419-1a5e-4b1d-bbe8-5ba49718e8dd",
"actualOwner": "jdoe",
"lastUpdate": "2025-03-28T11:59:37.294Z"
},
...
]
}
}
To apply filtering conditions in GraphQL queries, use the where and mention the specific conditions. For example, to filter the UserTaskInstances and show only those instances where state is ”Reserved” or "Ready" and name is prefixed by 'HR', the following query can be used:
{
UserTaskInstances (where: {
and: [
{state: {in: ["Reserved", "Ready"]}},
{name: {like: "HR*"}}
]
}) {
id
name
state
processInstanceId
actualOwner
lastUpdate
}
}
And something like the following will be returned showing UserTaskInstances that match the criteria :
{
"data": {
"UserTaskInstances": [
{
"id": "2fc77c0e-7afd-40da-8978-4bcac4dfa56d",
"name": "HRInterview",
"state": "Reserved",
"processInstanceId": "42e919fb-b014-4927-aa3c-c19a3930efd5",
"actualOwner": "jdoe",
"lastUpdate": "2025-03-28T12:07:47.068Z"
},
{
"id": "8d547a46-05a0-4999-8793-a672532106ff",
"name": "HRInterview",
"state": "Reserved",
"processInstanceId": "3299d15f-1ae5-4631-8efe-d9ba955fb9b3",
"actualOwner": "jdoe",
"lastUpdate": "2025-03-28T12:07:50.373Z"
},
{
"id": "4e8acdcb-0f40-4da3-bd92-e897437580fe",
"name": "HRInterview",
"state": "Reserved",
"processInstanceId": "2e1113f2-9f67-4ac7-91c4-0f8495d8e410",
"actualOwner": "jdoe",
"lastUpdate": "2025-03-28T12:12:56.138Z"
},
...
]
}
}
In GraphQL, filters are often handled through arguments passed to queries, and the conditions like logical operators (AND, OR, NOT) , between, contains, containsAll, containsAny, equalTo, greaterThan, greaterThanEqual, lessThan, lessThanEqual, isNull can be used to handle the complex query conditions.
Depending on the attribute type, the following operators can be used:
| Attribute type | Operators |
|---|---|
String array argument |
|
String argument |
|
ID argument |
|
Boolean argument: |
|
Numeric argument: |
|
Date argument: |
|
Sorting
In GraphQL, sorting is often implemented by arguments in the query. The specific sorting mechanism and the way it is used depends on how the GraphQL schema is designed, but many GraphQL API endpoints allow sorting by providing arguments that specify the field(s) to sort by and the sort order (ascending - ASC or descending - DESC). To sort the value based on a particular field in either ascending or descending order, you can use the ORDER BY clause in your Graphql query.
The following shows an example of a query to return UserTaskInstances filtered in the previous query, and sorted in the descending order of the lastUpdate string.
{
UserTaskInstances (where: {
and: [
{state: {in: ["Reserved", "Ready"]}},
{name: {like: "HR*"}}
]},
orderBy: {lastUpdate: DESC}
) {
id
name
state
processInstanceId
actualOwner
lastUpdate
}
}
And something like the following will be returned showing UserTaskInstances that match the criteria, shown in descending order or LastUpdate:
{
"data": {
"UserTaskInstances": [
{
"id": "14d92bfa-1273-4400-b81b-a049c3fcf4a9",
"name": "HRInterview",
"state": "Ready",
"processInstanceId": "d3007173-6c89-4bbc-9438-89d75055e223",
"actualOwner": null,
"lastUpdate": "2025-03-28T12:13:30.659Z"
},
{
"id": "cfa97303-50f2-4f37-b3f0-c79585665819",
"name": "HRInterview",
"state": "Ready",
"processInstanceId": "3368aff0-2b72-49ea-8bf5-c27a93152a9b",
"actualOwner": null,
"lastUpdate": "2025-03-28T12:13:16.514Z"
},
{
"id": "78341329-8759-4493-aeec-e008927f828c",
"name": "HRInterview",
"state": "Ready",
"processInstanceId": "3a7b2acd-408f-427a-9b4b-b322cb668969",
"actualOwner": null,
"lastUpdate": "2025-03-28T12:13:07.899Z"
},
...
]
}
}
Pagination
GraphQL pagination is used to break down large datasets into smaller, manageable chunks to improve performance and the user experience. Unlike traditional APIs where pagination might be handled with parameters like page and limit, GraphQL commonly uses offset-based pagination.
To add pagination to your query, you can use the parameters:
limit-
to specify how many results to return
offset-
where to start returning the results(the starting point).
The following shows an example of a query to return the first 5 UserTaskInstances from the top of the list (offset 0) generated by the prevous query.
{
UserTaskInstances (where: {
and: [
{state: {in: ["Reserved", "Ready"]}},
{name: {like: "HR*"}}
]},
orderBy: {lastUpdate: DESC},
pagination: {
limit: 5,
offset: 0
}
) {
id
name
state
processInstanceId
actualOwner
lastUpdate
}
}
Where the following 5 instances will be returned:
{
"data": {
"UserTaskInstances": [
{
"id": "14d92bfa-1273-4400-b81b-a049c3fcf4a9",
"name": "HRInterview",
"state": "Ready",
"processInstanceId": "d3007173-6c89-4bbc-9438-89d75055e223",
"actualOwner": null,
"lastUpdate": "2025-03-28T12:13:30.659Z"
},
{
"id": "cfa97303-50f2-4f37-b3f0-c79585665819",
"name": "HRInterview",
"state": "Ready",
"processInstanceId": "3368aff0-2b72-49ea-8bf5-c27a93152a9b",
"actualOwner": null,
"lastUpdate": "2025-03-28T12:13:16.514Z"
},
{
"id": "78341329-8759-4493-aeec-e008927f828c",
"name": "HRInterview",
"state": "Ready",
"processInstanceId": "3a7b2acd-408f-427a-9b4b-b322cb668969",
"actualOwner": null,
"lastUpdate": "2025-03-28T12:13:07.899Z"
},
{
"id": "ed89c127-0cdf-4b25-927f-7c936ccad984",
"name": "HRInterview",
"state": "Reserved",
"processInstanceId": "b31168a1-f083-43de-aad3-29b93e5112c8",
"actualOwner": "jdoe",
"lastUpdate": "2025-03-28T12:12:58.452Z"
},
{
"id": "3b17a8f9-5fc8-404b-a15d-5757b98d8476",
"name": "HRInterview",
"state": "Reserved",
"processInstanceId": "61465c5e-6d3c-4054-8d6f-a9183b0c5ee6",
"actualOwner": "jdoe",
"lastUpdate": "2025-03-28T12:12:57.621Z"
}
]
}
The following shows an example of a query to return the first 5 UserTaskInstances from the top of the list (offset 0) generated by the prevous query.
{
UserTaskInstances (where: {
and: [
{state: {in: ["Reserved", "Ready"]}},
{name: {like: "HR*"}}
]},
orderBy: {lastUpdate: DESC},
pagination: {
limit: 5,
offset: 5
}
) {
id
name
state
processInstanceId
actualOwner
lastUpdate
}
}
Where the following 4 instances will be returned starting from the 6th item in the list:
{
"data": {
"UserTaskInstances": [
{
"id": "81014d64-e81a-483a-a9d4-797e0d5cb596",
"name": "HRInterview",
"state": "Reserved",
"processInstanceId": "4691e5d2-04d7-4764-8ce2-9b0ae6d150ef",
"actualOwner": "jdoe",
"lastUpdate": "2025-03-28T12:12:56.841Z"
},
{
"id": "4e8acdcb-0f40-4da3-bd92-e897437580fe",
"name": "HRInterview",
"state": "Reserved",
"processInstanceId": "2e1113f2-9f67-4ac7-91c4-0f8495d8e410",
"actualOwner": "jdoe",
"lastUpdate": "2025-03-28T12:12:56.138Z"
},
{
"id": "8d547a46-05a0-4999-8793-a672532106ff",
"name": "HRInterview",
"state": "Reserved",
"processInstanceId": "3299d15f-1ae5-4631-8efe-d9ba955fb9b3",
"actualOwner": "jdoe",
"lastUpdate": "2025-03-28T12:07:50.373Z"
},
{
"id": "2fc77c0e-7afd-40da-8978-4bcac4dfa56d",
"name": "HRInterview",
"state": "Reserved",
"processInstanceId": "42e919fb-b014-4927-aa3c-c19a3930efd5",
"actualOwner": "jdoe",
"lastUpdate": "2025-03-28T12:07:47.068Z"
}
]
}
}
Mutation Capabilities
In GraphQL, mutations are used to modify data on the server, such as creating, updating, or deleting records. Mutations are an essential part of GraphQL because they allow you to make changes to the underlying data while also returning a result or confirmation about the operation.
In GraphQL, the syntax for a mutation is similar to that of a query. However, it is wrapped inside the mutation keyword. Mutations usually require input parameters, and they are passed as arguments. The arguments can be simple values (strings, integers, etc.) or complex objects. Like queries, you can use variables with mutations to make the request more flexible. This allows you to pass dynamic values instead of hardcoding them into the mutation.
The following sections describe the main GraphQL mutation capabilities in BAMOE.
Process Instance Abort
The ProcessInstanceAbort functionality allows you to abort a process instance, effectively stopping the execution of the process before it completes normally. This can be useful in situations where a process instance should be canceled due to a failure, manual intervention, or other business needs.
The following shows a sample GraphQL mutation for aborting a process instance by specifying the id of the instance as a query parameter:
mutation {
ProcessInstanceAbort(
id : String
)
}
Process Instance Retry
The ProcessInstanceRetry functionality enables you to retry a failed instance or instance that is in Error state. This is useful when a process instance encounters a failure (e.g., due to an error, task failure, or external dependency issues) and you want to attempt it again. It triggers the completed method of the process instance to allow execution to continue.
The following shows an example ProcessInstanceRetry mutation, specifying the id of the instance as a parameter:
mutation {
ProcessInstanceRetry(
id : String
)
}
Process Instance Skip
The ProcessInstanceSkip functionality enables you to skip a running process instance or a specific process instance state. Skip is similar to retry in the sense that it only applies to process instances in ERROR state. But instead of retrying the failed node instance, it just triggers the completed method of the process instance to allow execution to continue.
The following shows an example ProcessInstanceSkip mutation, specifying the id of the instance as a query parameter:
mutation {
ProcessInstanceSkip(
id : String
)
}
Process Instance Variables Update
The ProcessInstanceUpdateVariables functionality enables you to update the variables associated with a process instance. This mutation is useful for modifying the data associated with a process instance. You can update variables at any point in the process, such as when a decision needs to be made based on new input or when external factors influence the process flow.
The following shows an example ProcessInstanceUpdateVariables mutation, specifying the id of the instance and the values to be updated as a query parameter in JSON:
mutation {
ProcessInstanceUpdateVariables(
id : String,
variables : JSON String
)
}
The following snippet shows an example for the variables parameter in JSON format:
variables : "{\"booleanVar\" : true, \"stringVar\" : \"hello\"}"
Process Instance Reschedule SLA Timer
The ProcessInstanceRescheduleSlaTimer mutation enables you to reschedule the SLA due date of a processInstance.
The following shows an example ProcessInstanceRescheduleSlaTimer mutation which reschedules the SLA due date of the process instance identified by id passed as a parameter. The new due date is defined in the expirationTime parameter.
mutation {
ProcessInstanceRescheduleSlaTimer(
id : String,
expirationTime : String
)
}
Node Instance Trigger
The NodeInstanceTrigger mutation enables you to trigger a node in a process instance. A node is a unit of work in a process definition, such as a task, action, or decision point. Triggering a node causes a new node instance to be created, and might involve moving the process instance to the next state or node, effectively advancing the process.
The following shows an example NodeInstanceTrigger mutation. The nodeId is included in the nodeInstances of a process instance passed in the id parameter.
mutation {
NodeInstanceTrigger(
id : String,
nodeId : String
)
}
Node Instance Retrigger
The NodeInstanceReTrigger mutation enables you to retrigger an existing node instance in a process instance. Retriggering a node instance involves moving the process instance to the next state or node, effectively advancing the process. The arguments need to be passed are the processInstanceId and the nodeInstanceId that needs to be triggered.
The following shows an example NodeInstanceRetrigger mutation which retriggers a node instance corresponding to nodeInstanceId related to the process instance identified by id passed as a parameters.
mutation {
NodeInstanceTrigger(
id : String,
nodeInstanceID : String
)
}
Node Instance Cancel
The NodeInstanceCancel mutation enables you to cancel a node instance within a processInstance. When a node is canceled, it stops the execution of that particular node and its associated activities within the process instance. This mutation is useful when you want to prevent further actions or states from being processed, either due to changes in business requirements, process errors, or exceptions.
The following shows an example NodeInstanceCancel mutation which cancels the node instance corresponding to nodeInstanceId related to the process instance identified by id passed as a parameters.
mutation {
NodeInstanceCancel(
id : String,
nodeInstanceID : String
)
}
Node Instance Reschedule SLA Timer
The NodeInstanceRescheduleSlaTimer mutation enables you to reschedule the SLA due date of a node instance within a processInstance.
The following shows an example NodeInstanceRescheduleSlaTimer mutation which reschedules the SLA due date of a node instance corresponding to nodeInstanceId related to the process instance identified by id passed as a parameters. The new due date is defined in the expirationTime parameter.
mutation {
NodeInstanceRescheduleSlaTimer(
processInstanceId : String,
nodeInstanceId : String,
expirationTime : String
)
}
Job Cancel
The JobCancel functionality enables you to cancel a job that is either scheduled, in progress, or waiting in the job queue. This can be useful when you need to stop a job from executing or if it is no longer needed due to changes in the business process or external conditions.
The following shows an example JobCancel mutation which cancels the Job instance corresponding to the id passed as a argument.
mutation {
JobCancel(
id : String
)
}
Job Reschedule
The JobReschedule functionality enables you to reschedule a job. This can be useful when the job was originally scheduled to run at a certain time, but due to external factors or changes in business requirements, the job needs to be executed at a later time.
You can this mutation to reschedule a specific job by providing its id and also by specifying the data parameter, including fields such as expirationTime in JSON format.
mutation {
JobReschedule(
id : String,
data : String
)
}
The following snippet shows an example for the data parameter in JSON format:
data: "{\"expirationTime\" : \"2025-12-31T20:00:00.000Z\"}"