I'm working on a proof-of-concept that needs to provide runtime support for the execution of business processes.

Right now, I'm happy to use the Flowable Modeler to model business processes and to create User tasks and process instances, however, I'd also like to use Flowable's REST API to interact with process instances and User tasks.

Flowable Modeler

The easiest way to get started with Flowable is to use the flowable/all-in-one Docker image:

docker run --name flowable -p 8080:8080 flowable/all-in-one

or

docker start --interactive flowable

Navigate to http://localhost:8080/flowable-modeler and sign in using the default user id: admin and password: test

sign-in

You will then be redirected to the Processes tab in the Flowable Modeler's dashboard:

flowable-modeler-dashboard-1

To begin modelling a business process (using BPMN) click the Create Process button:

create-business-process-1

Enter a Model name, a Model key and a Description then click the Create new model button:

bpmn-editor

The 'process design interface' (Flowable's BPMN editor) includes a side menu with a palette of BPMN 2.0 elements and a properties panel at the bottom of the page. Each new process begins with a Start event (the small circle).

You can drag and drop elements from the side menu, or you can use the 'quick menu' of a selected element. Click on the Start event element and its quick menu will appear.

We’re going to add a User task, so click the icon representing a user:

add-user-task

This will add a box linked by an arrow to the Start event. Double-click on the box to give the task the name 'Fill in a Leave Application Form' and then click outside the box to save the change:

fill-in-form

Click on the box again to display its quick menu and select the Stop event icon (the circle with a thick border):

quick-menu

Our business process model now consists of a Start event, a User task and an End event:

end-event

Assignments

In order for Flowable to successfully execute our business process it needs to know which users can complete the User task. Select the 'Fill in a Leave Application Form' User task and then click its Assignments property:

assignments

You can assign the task to an individual or a group:

allow-process-initiator

Check the 'Allow process initiator to complete task' box and then click the Save button.

Form Reference

To associate a form with a User task, select the 'Fill in a Leave Application Form' User task and then click its Form reference property:

form-reference

We don't have any forms just yet:

new-form

Click the New form button:

create-a-form

Enter a Form name, a Form key and a Description then click the Create form button:

form-builder

The Form designer includes a side menu with a palette of form components that you can drag and drop onto the design canvas:

leave-application-form

App Definitions

Now that we have modelled our business process we need to make it available for people to use. Navigate to the Apps tab in the Flowable Modeler's dashboard and click the Create App button:

new-app-definition

Enter an App definition name, an App definition key and a Description then click the Create new app definition button:

app-definition-details

I changed the Icon, used the Edit included models button to add the 'Leave Application Process' to the 'HR App' and then clicked the Save icon:

apps-tab-hr-app

Click the 'HR App' card:

hr-app-publish

Note: You can export the App definition as a zip file or as a deployable bar file.

Click the Publish button:

Screen-Shot-2018-12-24-at-08.21.35

Click the Publish app definition button.

Now we'll use Flowable's REST API to check and see if our app definition has been deployed:

curl -i 'http://admin:test@localhost:8080/flowable-task/process-api/repository/deployments'

You should see output like:

{
    "data": [
        {
            "id": "c56b72eb-06f8-11e9-a85e-0242ac110002",
            "name": "hr-app.zip",
            "deploymentTime": "2018-12-23T21:21:54.532Z",
            "category": null,
            "parentDeploymentId": "c55ec8b6-06f8-11e9-a85e-0242ac110002",
            "url": "http://localhost:8080/flowable-task/process-api/repository/deployments/c56b72eb-06f8-11e9-a85e-0242ac110002",
            "tenantId": ""
        }
    ],
    "total": 1,
    "start": 0,
    "sort": "id",
    "order": "asc",
    "size": 1
}

Let's check and see if our process definition has been deployed too:

curl -i 'http://admin:test@localhost:8080/flowable-task/process-api/repository/process-definitions'

You should see output like:

{
    "data": [
        {
            "id": "leave-application-process:1:c5ae6f5e-06f8-11e9-a85e-0242ac110002",
            "url": "http://localhost:8080/flowable-task/process-api/repository/process-definitions/leave-application-process:1:c5ae6f5e-06f8-11e9-a85e-0242ac110002",
            "key": "leave-application-process",
            "version": 1,
            "name": "Leave Application Process",
            "description": "An employee wants to take some time off.",
            "tenantId": "",
            "deploymentId": "c56b72eb-06f8-11e9-a85e-0242ac110002",
            "deploymentUrl": "http://localhost:8080/flowable-task/process-api/repository/deployments/c56b72eb-06f8-11e9-a85e-0242ac110002",
            "resource": "http://localhost:8080/flowable-task/process-api/repository/deployments/c56b72eb-06f8-11e9-a85e-0242ac110002/resources/leave-application-process.bpmn",
            "diagramResource": "http://localhost:8080/flowable-task/process-api/repository/deployments/c56b72eb-06f8-11e9-a85e-0242ac110002/resources/leave-application-process.leave-application-process.png",
            "category": "http://www.flowable.org/processdef",
            "graphicalNotationDefined": true,
            "suspended": false,
            "startFormDefined": false
        }
    ],
    "total": 1,
    "start": 0,
    "sort": "name",
    "order": "asc",
    "size": 1
}

Flowable Task

Navigate to http://localhost:8080/flowable-task

flowable-task-hr-app

Click the 'HR App' card and navigate to the Processes tab:

flowable-task-processes-tab

Click the Start a process button:

flowable-task-leave-application-process

Then click the Start process button:

flowable-task-lap-2

Now we'll use Flowable's REST API to obtain information about our process instances:

curl -i 'http://admin:test@localhost:8080/flowable-task/process-api/runtime/process-instances'

You should see output like:

{
    "data": [
        {
            "id": "02d460bb-070e-11e9-a85e-0242ac110002",
            "url": "http://localhost:8080/flowable-task/process-api/runtime/process-instances/02d460bb-070e-11e9-a85e-0242ac110002",
            "name": "Leave Application Process - December 24th 2018",
            "businessKey": null,
            "suspended": false,
            "ended": false,
            "processDefinitionId": "leave-application-process:1:c5ae6f5e-06f8-11e9-a85e-0242ac110002",
            "processDefinitionUrl": "http://localhost:8080/flowable-task/process-api/repository/process-definitions/leave-application-process:1:c5ae6f5e-06f8-11e9-a85e-0242ac110002",
            "activityId": null,
            "startedBy": "admin",
            "started": "2018-12-23T23:53:56.992Z",
            "variables": [],
            "callbackId": null,
            "callbackType": null,
            "tenantId": "",
            "completed": false
        }
    ],
    "total": 1,
    "start": 0,
    "sort": "id",
    "order": "asc",
    "size": 1
}

Let's check and see if we have any tasks to complete:

curl -i 'http://admin:test@localhost:8080/flowable-task/process-api/runtime/tasks'

You should see output like:

{
    "data": [
        {
            "id": "1fae489a-070f-11e9-a85e-0242ac110002",
            "url": "http://localhost:8080/flowable-task/process-api/runtime/tasks/1fae489a-070f-11e9-a85e-0242ac110002",
            "owner": null,
            "assignee": "admin",
            "delegationState": null,
            "name": "Fill in a Leave Application Form",
            "description": null,
            "createTime": "2018-12-24T00:01:54.893Z",
            "dueDate": null,
            "priority": 50,
            "suspended": false,
            "taskDefinitionKey": "sid-3BA1F4D1-500F-4766-89BF-519166929F2D",
            "scopeDefinitionId": null,
            "scopeId": null,
            "scopeType": null,
            "tenantId": "",
            "category": null,
            "formKey": "leave-application-form",
            "parentTaskId": null,
            "parentTaskUrl": null,
            "executionId": "1fadfa77-070f-11e9-a85e-0242ac110002",
            "executionUrl": "http://localhost:8080/flowable-task/process-api/runtime/executions/1fadfa77-070f-11e9-a85e-0242ac110002",
            "processInstanceId": "1fadfa74-070f-11e9-a85e-0242ac110002",
            "processInstanceUrl": "http://localhost:8080/flowable-task/process-api/runtime/process-instances/1fadfa74-070f-11e9-a85e-0242ac110002",
            "processDefinitionId": "leave-application-process:1:c5ae6f5e-06f8-11e9-a85e-0242ac110002",
            "processDefinitionUrl": "http://localhost:8080/flowable-task/process-api/repository/process-definitions/leave-application-process:1:c5ae6f5e-06f8-11e9-a85e-0242ac110002",
            "variables": []
        }
    ],
    "total": 1,
    "start": 0,
    "sort": "id",
    "order": "asc",
    "size": 1
}

formKey contains the name of the form ('leave-application-form') associated with the User task.

We can check the form repository for the 'Leave Application Form':

curl -i 'http://admin:test@localhost:8080/flowable-task/form-api/form-repository/form-definitions'

You should see output like:

{
    "data": [
        {
            "id": "c5bdb1a1-06f8-11e9-a85e-0242ac110002",
            "url": "http://localhost:8080/flowable-task/form-api/form-repository/form-definitions/c5bdb1a1-06f8-11e9-a85e-0242ac110002",
            "category": null,
            "name": "Leave Application Form",
            "key": "leave-application-form",
            "description": null,
            "version": 1,
            "resourceName": "form-leave-application-form.form",
            "deploymentId": "c5b0b94f-06f8-11e9-a85e-0242ac110002",
            "tenantId": ""
        }
    ],
    "total": 1,
    "start": 0,
    "sort": "name",
    "order": "asc",
    "size": 1
}

We can use the id to obtain a JSON representation of the form model:

curl -i 'http://admin:test@localhost:8080/flowable-task/form-api/form-repository/form-definitions/c5bdb1a1-06f8-11e9-a85e-0242ac110002/model'

You should see output like:

{
    "id": "c5bdb1a1-06f8-11e9-a85e-0242ac110002",
    "name": "Leave Application Form",
    "key": "leave-application-form",
    "version": 1,
    "url": "http://localhost:8080/flowable-task/form-api/form/model",
    "fields": [
        {
            "fieldType": "FormField",
            "id": "givenName",
            "name": "Given Name",
            "type": "text",
            "value": null,
            "required": true,
            "readOnly": false,
            "overrideId": true,
            "placeholder": "",
            "layout": null
        },
        {
            "fieldType": "FormField",
            "id": "familyName",
            "name": "Family Name",
            "type": "text",
            "value": null,
            "required": true,
            "readOnly": false,
            "overrideId": true,
            "placeholder": null,
            "layout": null
        },
        {
            "fieldType": "FormField",
            "id": "employeeNumber",
            "name": "Employee Number",
            "type": "integer",
            "value": null,
            "required": true,
            "readOnly": false,
            "overrideId": true,
            "placeholder": null,
            "layout": null
        },
        {
            "fieldType": "FormField",
            "id": "fromDate",
            "name": "From Date",
            "type": "date",
            "value": null,
            "required": true,
            "readOnly": false,
            "overrideId": true,
            "placeholder": null,
            "layout": null
        },
        {
            "fieldType": "FormField",
            "id": "toDate",
            "name": "To Date",
            "type": "date",
            "value": null,
            "required": true,
            "readOnly": false,
            "overrideId": true,
            "placeholder": null,
            "layout": null
        }
    ],
    "outcomes": []
}

Now navigate to the Tasks tab to see how Flowable's Form engine renders our Leave Application form:

flowable-task-lap-3

We can fill in the form:

flowable-task-lap-4

Or use Flowable's REST API to update the form's variables and to complete the User task:

curl -H "Content-Type: application/json" 
     -X POST http://admin:test@localhost:8080/flowable-task/process-api/runtime/tasks/1fae489a-070f-11e9-a85e-0242ac110002
     -d "@data-1.json"

data-1.json:

{
  "action" : "complete",
  "variables" : [
    {
        "id": "givenName",
        "name": "Given Name",
        "type": "string",
        "value": "Rob"
    },
    {
        "id": "familyName",
        "name": "Family Name",
        "type": "string",
        "value": "Ferguson"
    },
    {
        "id": "employeeNumber",
        "name": "Employee Number",
        "type": "integer",
        "value": 123456
    },
    {
        "id": "fromDate",
        "name": "From Date",
        "type": "date",
        "value": "2018-12-21T00:00:00+00:00"
    },
    {
        "id": "toDate",
        "name": "To Date",
        "type": "date",
        "value": "2019-01-07T00:00:00+00:00"
    }
  ]
}

You should see output like:

Status: 200 OK

Despite returning OK the call doesn't appear to save the User task's variables:

blank-form

So I raised the following Flowable issue:

I also tried, POST /form/form-data

curl -H "Content-Type: application/json" 
     -X POST http://admin:test@localhost:8080/flowable-task/process-api/form/form-data 
     -d "@data-2.json"

data-2.json:

{
  "taskId" : "1fae489a-070f-11e9-a85e-0242ac110002",
  "properties" : [
    {
      "id": "givenName",
      "name": "Given Name",
      "type": "string",
      "value": "Rob"
    },
    {
      "id": "familyName",
      "name": "Family Name",
      "type": "string",
      "value": "Ferguson"
    },
    {
      "id": "employeeNumber",
      "name": "Employee Number",
      "type": "integer",
      "value": 123456
    },
    {
      "id": "fromDate",
      "name": "From Date",
      "type": "date",
      "value": "2018-12-21T00:00:00+00:00"
    },
    {
      "id": "toDate",
      "name": "To Date",
      "type": "date",
      "value": "2019-01-07T00:00:00+00:00"
    }
  ]
}

You should see output like:

Status: 204 No Content

I'm not sure why its returning 204 No Content so I raised the following Flowable issue:

However it does appear to save the User task's variables (and complete the User task):

form-data

Flowable Issues

I raised the following Flowable issues:

What's Next

In the next post, we'll use Angular, Angular Material and Flowable's REST API to create a bespoke Task List component:

task-list

Source Code:
References: