How to implement Activiti REST API with Spring Boot Example

In this tutorial, we’re gonna look at an example that uses Activiti REST API with Spring Boot.

Related Articles:
Introduction to Activiti – a Java BPM Engine
How to start Activiti + Spring JPA with Spring Boot

I. Activiti REST API Overview

Activiti Engine includes a REST API that can be used by:
– deploying the activiti-rest.war file to a servlet container,
– or including the servlet and it’s mapping in the application and add all activiti-rest dependencies to the classpath.

By default the Activiti Engine will connect to an in-memory H2 database, so with Spring Boot, we just need to add dependency as below to make it run:

<dependency>
	<groupId>com.h2database</groupId>
	<artifactId>h2</artifactId>
</dependency>

<dependency>
	<groupId>org.activiti</groupId>
	<artifactId>activiti-spring-boot-starter-basic</artifactId>
	<version>5.22.0</version>
</dependency>

<dependency>
	<groupId>org.activiti</groupId>
	<artifactId>spring-boot-starter-rest-api</artifactId>
	<version>5.17.0</version>
</dependency>

Activiti REST API supports:

  • Deployment: get/create/delete Deployments, get resources inside a Deployment.
  • Process Definition: get one or list of Process Definitions, get resource content or BPMN model of a Process Definition, activate/suspend, get/add/delete candidate starters.
  • Model: get/update/create/delete Models, get/set editor source for a Model.
  • Process Instance: get/delete/activate/suspend Process Instances, add/remove Users, get/create/update Variables.
  • Execution: get Executions, execute an action or get active activities, query, get/create/update Variables.
  • Task: get/update/delete Tasks, query for Tasks, get/create/update Variables, get/create/delete identity links, get Events, get/create/delete Attachments.
  • History: get/delete/query for Historic Process Instances, Task Instances, Activities Instances, Variables Intances.
  • User & Group: get/create/update/delete information.
  • Database Table, Engine, Runtime, Job

For more details, please visit: Activiti User Guide – REST API

In the example, we will test some of them to see how it works.

II. Practice

1. Technology

– Java 1.8
– Maven 3.3.9
– Spring Tool Suite – Version 3.8.4.RELEASE
– Spring Boot: 1.5.3.RELEASE

2. Step by step

2.1 Create Spring Boot project

Using Spring Tool Suite/Eclipse to create Project and add Dependencies to pom.xml file:

<dependency>
	<groupId>com.h2database</groupId>
	<artifactId>h2</artifactId>
</dependency>

<dependency>
	<groupId>org.activiti</groupId>
	<artifactId>activiti-spring-boot-starter-basic</artifactId>
	<version>5.22.0</version>
</dependency>

<dependency>
	<groupId>org.activiti</groupId>
	<artifactId>spring-boot-starter-rest-api</artifactId>
	<version>5.17.0</version>
</dependency>

2.2 Define Process

Under src/main/resources, create processes folder and add simple-process.bpmn20.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
	xmlns:activiti="http://activiti.org/bpmn" targetNamespace="Examples">

	<process id="simpleProcess" name="Simple Process">
		<startEvent id="theStart" />
		<sequenceFlow sourceRef="theStart" targetRef="theTask" />

		<userTask id="theTask" name="Task" activiti:assignee="${person}">
			<documentation>
				Do the task.
			</documentation>
		</userTask>

		<sequenceFlow sourceRef="theTask" targetRef="theEnd" />
		<endEvent id="theEnd" />
	</process>

</definitions>

We use ${person} expression and activiti:assignee attribute for assigning task.

2.3 Initialize User

By default, all Activiti REST resources require a valid User to be authenticated. So we should create an admin User. Open Application class, add Bean for initializing User:


package com.javasampleapproach.restactiviti;

import org.activiti.engine.IdentityService;
import org.activiti.engine.identity.User;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class SpringRestActivitiApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringRestActivitiApplication.class, args);
	}

	@Bean
	InitializingBean usersAndGroupsInitializer(final IdentityService identityService) {

		return new InitializingBean() {
			public void afterPropertiesSet() throws Exception {

				User admin = identityService.newUser("admin");
				admin.setPassword("admin");
				identityService.saveUser(admin);

			}
		};
	}
}

Basic HTTP access authentication is used, so we always include a authorized username & password in the request url.

More about Activiti Services at: Introduction to Activiti – a Java BPM Engine

2.4 Run & Check Result

– Config maven build:
clean install
– Run project with mode Spring Boot App
– Check results:

List of Deployments:
curl -u admin:admin http://localhost:8080/repository/deployments


{
   "data": [
      {
         "id": "1",
         "name": "SpringAutoDeployment",
         "deploymentTime": "2017-05-15T20:08:26.859+07:00",
         "category": null,
         "url": "http://localhost:8080/repository/deployments/1",
         "tenantId": ""
      }
   ],
   "total": 1,
   "start": 0,
   "sort": "id",
   "order": "asc",
   "size": 1
}

List resources in a deployment:
curl -u admin:admin http://localhost:8080/repository/deployments/1/resources


[
   {
      "id": "E:\\STS\\WorkPlace\\SpringRestActiviti\\target\\classes\\processes\\simple-process.bpmn20.xml",
      "url": "http://localhost:8080/repository/deployments/1/resources/E:\\STS\\WorkPlace\\SpringRestActiviti\\target\\classes\\processes\\simple-process.bpmn20.xml",
      "contentUrl": "http://localhost:8080/repository/deployments/1/resourcedata/E:\\STS\\WorkPlace\\SpringRestActiviti\\target\\classes\\processes\\simple-process.bpmn20.xml",
      "mediaType": "text/xml",
      "type": "processDefinition"
   }
]

List of process definitions:
curl -u admin:admin http://localhost:8080/repository/process-definitions


{
   "data": [
      {
         "id": "simpleProcess:1:3",
         "url": "http://localhost:8080/repository/process-definitions/simpleProcess:1:3",
         "key": "simpleProcess",
         "version": 1,
         "name": "Simple Process",
         "description": null,
         "tenantId": "",
         "deploymentId": "1",
         "deploymentUrl": "http://localhost:8080/repository/deployments/1",
         "resource": "http://localhost:8080/repository/deployments/1/resources/E:\\STS\\WorkPlace\\SpringRestActiviti\\target\\classes\\processes\\simple-process.bpmn20.xml",
         "diagramResource": null,
         "category": "Examples",
         "graphicalNotationDefined": false,
         "suspended": false,
         "startFormDefined": false
      }
   ],
   "total": 1,
   "start": 0,
   "sort": "name",
   "order": "asc",
   "size": 1
}

Get BPMN model (by processId):
curl -u admin:admin http://localhost:8080/repository/process-definitions/simpleProcess:1:3/model


{
   "definitionsAttributes": {},
   "processes": [
      {
         "id": "simpleProcess",
         "xmlRowNumber": 5,
         "xmlColumnNumber": 52,
         "extensionElements": {},
         "attributes": {},
         "name": "Simple Process",
         "executable": true,
         "documentation": null,
         "ioSpecification": null,
         "executionListeners": [],
         "lanes": [],
         "dataObjects": [],
         "candidateStarterUsers": [],
         "candidateStarterGroups": [],
         "eventListeners": [],
         "flowElements": [
            {
               "id": "theStart",
               "xmlRowNumber": 6,
               "xmlColumnNumber": 31,
               ...
               "outgoingFlows": [
                  {
                     "id": null,
                     "xmlRowNumber": 7,
                     "xmlColumnNumber": 60,
                     ...
                     "sourceRef": "theStart",
                     "targetRef": "theTask",
                  }
               ],
               "eventDefinitions": [],
               "initiator": null,
               "formKey": null,
               "formProperties": []
            },
            {
               "id": null,
               "xmlRowNumber": 7,
               "xmlColumnNumber": 60,
               ...
               "sourceRef": "theStart",
               "targetRef": "theTask",
            },
            {
               "id": "theTask",
               "xmlRowNumber": 9,
               "xmlColumnNumber": 68,
               ...
               "name": "Task",
               "documentation": "Do the task.",
               "incomingFlows": [
                  {
                     "id": null,
                     "xmlRowNumber": 7,
                     "xmlColumnNumber": 60,
                     ...
                     "sourceRef": "theStart",
                     "targetRef": "theTask",
                  }
               ],
               "outgoingFlows": [
                  {
                     "id": null,
                     "xmlRowNumber": 15,
                     "xmlColumnNumber": 58,
                     ...
                     "sourceRef": "theTask",
                     "targetRef": "theEnd",
                  }
               ],
               ...
               "assignee": "${person}",
            },
            {
               "id": null,
               "xmlRowNumber": 15,
               "xmlColumnNumber": 58,
               ...
               "sourceRef": "theTask",
               "targetRef": "theEnd",
            },
            {
               "id": "theEnd",
               "xmlRowNumber": 16,
               "xmlColumnNumber": 27,
               ...
               "incomingFlows": [
                  {
                     "id": null,
                     "xmlRowNumber": 15,
                     "xmlColumnNumber": 58,
                     ...
                     "sourceRef": "theTask",
                     "targetRef": "theEnd",
                  }
               ],
               "outgoingFlows": [],
               "eventDefinitions": []
            }
         ],
         "artifacts": []
      }
   ],
   ...
   "resources": [],
   "targetNamespace": "Examples",
   "mainProcess": {
      ...
      ],
      "artifacts": []
   },
   "itemDefinitions": {},
   "namespaces": {
      "activiti": "http://activiti.org/bpmn"
   }
}

Start Process:
curl -u admin:admin -H "Content-Type: application/json" -d '{"processDefinitionKey":"simpleProcess", "variables": [ {"name":"person", "value":"John"}]}' http://localhost:8080/runtime/process-instances

We have also sent Variables Information {“person”:”John”}. This request returns a Process Instance:


{
   "id": "4",
   "url": "http://localhost:8080/runtime/process-instances/4",
   "businessKey": null,
   "suspended": false,
   "ended": false,
   "processDefinitionId": "simpleProcess:1:3",
   "processDefinitionUrl": "http://localhost:8080/repository/process-definitions/simpleProcess:1:3",
   "activityId": "theTask",
   "variables": [],
   "tenantId": "",
   "completed": false
}

List of variables by Process Instance ID
curl -u admin:admin http://localhost:8080/runtime/process-instances/4/variables


[
   {
      "name": "person",
      "type": "string",
      "value": "John",
      "scope": "local"
   }
]

List of tasks:
curl -u admin:admin http://localhost:8080/runtime/tasks


{
   "data": [
      {
         "id": "9",
         "url": "http://localhost:8080/runtime/tasks/9",
         "owner": null,
         "assignee": "John",
         "delegationState": null,
         "name": "Task",
         "description": "Do the task.",
         "createTime": "2017-05-15T20:28:22.667+07:00",
         "dueDate": null,
         "priority": 50,
         "suspended": false,
         "taskDefinitionKey": "theTask",
         "tenantId": "",
         "category": null,
         "formKey": null,
         "parentTaskId": null,
         "parentTaskUrl": null,
         "executionId": "4",
         "executionUrl": "http://localhost:8080/runtime/executions/4",
         "processInstanceId": "4",
         "processInstanceUrl": "http://localhost:8080/runtime/process-instances/4",
         "processDefinitionId": "simpleProcess:1:3",
         "processDefinitionUrl": "http://localhost:8080/repository/process-definitions/simpleProcess:1:3",
         "variables": []
      }
   ],
   "total": 1,
   "start": 0,
   "sort": "id",
   "order": "asc",
   "size": 1
}

Add Variables to Task (by Id):
curl -u admin:admin -H "Content-Type: application/json" -d '[{"name" : "newTaskVariable", "scope" : "local", "type" : "string", "value" : "This is variable Value"}]' http://localhost:8080/runtime/tasks/9/variables


[
   {
      "name": "newTaskVariable",
      "type": "string",
      "value": "This is variable Value",
      "scope": "local"
   }
]

Identity Links (by Id):
curl -u admin:admin http://localhost:8080/runtime/tasks/9/identitylinks


[
   {
      "url": "http://localhost:8080/runtime/tasks/9/identitylinks/users/John/assignee",
      "user": "John",
      "group": null,
      "type": "assignee"
   }
]

Complete Task (by Id):
curl -u admin:admin -H "Content-Type: application/json" -d '{"action" : "complete"}' http://localhost:8080/runtime/tasks/9

Historic process instance:
curl -u admin:admin http://localhost:8080/history/historic-process-instances/4


{
   "id": "4",
   "url": "http://localhost:8080/history/historic-process-instances/4",
   "businessKey": null,
   "processDefinitionId": "simpleProcess:1:3",
   "processDefinitionUrl": "http://localhost:8080/repository/process-definitions/simpleProcess:1:3",
   "startTime": "2017-05-15T20:40:34.504+07:00",
   "endTime": "2017-05-15T20:44:51.036+07:00",
   "durationInMillis": 256532,
   "startUserId": "admin",
   "startActivityId": "theStart",
   "endActivityId": "theEnd",
   "deleteReason": null,
   "superProcessInstanceId": null,
   "variables": [],
   "tenantId": ""
}

III. Source code

SpringRestActiviti



By grokonez | May 15, 2017.

Last updated on April 29, 2021.



Related Posts


7 thoughts on “How to implement Activiti REST API with Spring Boot Example”

  1. Hi,
    I downloaded your code source. And it doesn’t work until I removed activiti rest – api. and by removing activit-rest-api we will not have acces to Rest api. can you suggest any solution?

    1. Hi WAJDI,

      Make sure that you didn’t deploy the activiti-rest.war file to a servlet container before.
      Then just follow step by step to make project run (all activiti-rest dependencies will be added to the classpath automatically).
      I have checked the source code again and it works well.

      If you cannot make thing done, notice us again and show your problem more clearly.

      Best Regard,

  2. I downloaded the code and tried to post using the below command.

    curl -u admin:admin -H “Content-Type: application/json” -d ‘{“processDefinitionKey”:”simpleProcess”, “variables”: [ {“name”:”person”, “value”:”John”}]}’ http://localhost:8080/runtime/process-instances

    I am getting below error
    ,
    {“message”:”Bad request”,”exception”:”Either processDefinitionId, processDefinitionKey or message is required.”}

Got Something To Say:

Your email address will not be published. Required fields are marked *

*