Creating a Data Object Model With a REST Service Model

In this guide, we’ll look at creating a data object model, where the data for the data object data comes from a REST API.

The steps we’ll go through are

  1. (Optional) Create a mock REST API

  2. Create the data object model

  3. Create the service model based on the data object model

  4. Create an example case model and forms to show the usage of the data object

Creating an example REST API (optional)

This part can be skipped if you’re not interested in executing the example models in the next parts.

In the steps that follow, we’ll use a fictional Customer REST API.

This REST API should

  • Return a customer JSON object on a GET request

  • Take in a customer JSON object as body for a POST, returning the created Customer JSON.

  • Take in a customer JSON object as body for a PUT request, returning the updated Customer JSON.

  • Delete the customer when a DELETE request is issued.

The JSON representation of the customer data looks as follows:

    "id": "some_unique_id",
    "name": "The name",
    "active": true,
    "country": "A country",
    "yearlyFee": 12345

If you are a developer and want to have fine-grained control over the REST API, the following simple Spring Boot application can be used to set up this mock REST API.

This REST API implementation is by no means a production-ready setup: there is no persistency, logging is done with System.out, there is no security, etc. The only purpose is to have something to try out the different models.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

public class DemoApplication {

	public static void main(String[] args) {, args);


The Customer Pojo:

public class Customer {

    private String id;
    private String name;
    private boolean active;
    private String country;
    private long yearlyFee;

    // Getters and setters

And the actual REST controller:

import java.util.*;
import org.springframework.web.bind.annotation.*;

public class CustomerController {

    private Map<String, Customer> customers = new HashMap<>();

    public Customer getCustomer(@PathVariable String id) {
        Customer customer = customers.get(id);
        System.out.println("Retrieved customer " + customer);
        return customer;

    public Customer createCustomer(@RequestBody Customer createCustomer) {
        Customer customer = new Customer();

        customers.put(customer.getId(), customer);

        System.out.println("Created customer " + customer);

        return customer;

    public Customer updateCustomer(@PathVariable String id, @RequestBody Customer updateCustomer) {
        Customer customer = customers.get(id);

        System.out.println("Update customer " + customer);

        return customer;

    public void deleteCustomer(@PathVariable String id) {
        Customer customer = customers.remove(id);
        System.out.println("Deleted customer " + customer);


Creating the Data Object Model

In Flowable Design, go to the Others section, select Data object from the list on the left-hand side, and then click on the the Create button in the top-right corner.

In the dialog, give the data object model a name, set the key, and optionally add a meaningful description for it. Once all the information is entered then click on Create new model.

Create a Data Object

Once created, the Data Object Model editor opens, and we can start defining it.

Defining the Data Object Fields

A data object consists of one or more fields. New fields can be added by clicking the Create new field button.

The following form is shown:

New data object field

Following properties can be set:

  • Label (optional): a human-readable version of the (technical) name of the field.

  • Name (required): the (technical) name of the field. This is the name that is used for example in expressions in process or case models (e.g. ${ === '123}).

  • Type (required): the type of the field. Currently supported are String/Date/Boolean/Integer/Double/Long fields.

  • Default value (optional): a value for the field that is set in case when a value would not have been set.

  • Description (optional): a human-readable explanation of the purpose of this field.

Let’s add following fields to the data object:

  • ID: a unique identifier for the customer.

  • Name: the name of the customer

  • Active: a flag indicating whether this is an active customer or not

  • Country: the country where the customer resides.

  • Yearly fee: a monetary value indicating some yearly fee the customer pays.

This should result in something that looks like this:

Data object fields

If a description is set, an information icon is shown next to the label of that field (e.g. for the ID field here.)

The actions column of the table shows the following actions (from left to right):

  • Edit: this will allows changing the field settings.

  • Delete: this deletes the field. A confirmation will be asked before deleting.

  • Move up: moves the field one row up.

  • Move down: moves the field one row down.

Advanced Settings

At the bottom of the page there is a check box available that, when selected, displays optional advanced settings:

Advanced settings

All these fields are (technical) metadata settings:

  • Type: A custom type for the data object.

  • Sub type: A custom sub type for the data object.

  • External Id: An external id to identify the data object.

The main use case for these is to categorise or easily query and retrieve data object definitions via the API’s.

Include in App

Data object models can be added and are deployed as part of a regular app. To do that we need to go to the Apps section of Flowable Design and create an app. After the app is created in the App Editor, we need to

  • select the + button

  • select now Include an existing model into the app

  • go to the Others models tab and then select the data object model

Add data object to app

Creating the Service Model

In this part, we’ll create the service model needed to retrieve and manipulate the data for a data object model. The point about doing this, is that all of this is hidden to the business modeler. The actual details how this done are hidden in the service models and don’t leak into the models where the data object gets used.

In Flowable Design, go to the Others section, select Service from the list on the left-hand side, and then click on the the Create button in the top-right corner.

In the dialog, give the model a name, set the key, and optionally add a meaningful description for it. Once all the information is entered then click on Create new model.

REST Service Definition Creation

Flowable Design will now switch to the service model editor.

Two dropdowns are available: one to select the type and one to select the service type. he type is either standard or based on a data object model.

  • A standard service model allows defining operations and parameters in a free-form way. This is for service models that e.g. get used by the service registry task (See The Service Registry Developer Guide) in process or case models.

  • A service model based on a data object model is used to connect a data object model to an implementation of how to retrieve and manipulate the data at runtime. When this type is selected, the structure of the data model will define a set of required operations and define which parameters are available (i.e. the fields of the data object model).

Select now based on a data object model. A second dropdown appears that allows selecting the data object model. Choose from that list the Customer data object model which we’ve created above.

REST Service Definition Type Selection

With the third dropdown, the type of service is chosen. In this case, we’ll use the REST option.

When switching to this type a few things happen, as shown on the screenshot below.

  • The REST Settings section appears

  • The Data Object Configuration section appears

  • Four operations are automatically generated

REST Service Definition Data Object Model Selection

At this point a Lookup ID needs to be set. It is used to uniquely identify and retrieve data object instances at runtime. Select the ID field.

REST Settings

The REST Settings section enables configuring settings that are applied to all operations:

  • Base URL: The base url will be taken as basis for the operations: first the value here will be applied before applying the url configuration of the operation.

  • Custom headers: Allows defining custom headers, which will be applied to all operations. Operations can override headers by setting a different value for the same header name.

For example, if for some reason the REST API would accept XML instead of JSON, a custom header could be configured:

Service Definition REST Settings


After selecting a data object model from the dropdown, four operations have automatically been generated. These operations are needed by any service definitions that handles the data of a data object (this is why these operations, unlike any other operations, cannot be deleted). Of course, other operations for the same service model are still permitted.

The default generated operations are

  • Lookup : This operation will be used whenever the data object instance is needed. For example, when a form is displaying information about the data object, the data will be retrieved using this operation behind the scene.

  • Create : This operation is be used when a data object is created for the first time.

  • Update : This operation is used when the data of an existing data object instance is changed.

  • Delete : This operations allow deleting the data object instance.

REST Service Definition Operations

Let’s have a look at the concrete configuration of the four operations for our customer data object.

Lookup Operation

The responsability of the Lookup operation is to retrieve the data of a data object instance at runtime, based on a data object model.

Note that the name can be changed, but the key is not editable. This is because this opertation is a 'fixed' operation which every data object based service model needs to have.

In the example REST API, such data is retrieved by doing an HTTP GET call to /customers/id where id is the actual unique identifier of the customer.

The default generated operation has already /${lookupId} pre-configured. Given that the Base URL above was configured already, this means that we don’t need to change anything. The final URL will be http://localhost:8123/customers/${lookupId}.

The only thing left to do is setting the Method to GET.

REST Service Definition - Lookup Operation

Following configuration is also possible (but not used in this example):

  • Headers: any HTTP headers configured here will be added to the Custom Headers set globally on the service model. When a header name is added here and also exists globally, the value here will be used and it will override the global setting.

  • Output path: Calling the REST API will return a JSON response. If all data for the data object is not on the root level, it’s possible to define the general path of this data. Note that this can be further configured in the output parameters below. For example, if for some reason the REST API would return the data in the first element of a data array, it could be something like /data/0. The syntax for the path is JSON-Pointer syntax.

The Lookup operation does not have input parameters, as the only value available is the lookupId.

The Lookup REST API produces a JSON response and this JSON needs to be mapped to the structure of the data object. Unlike a standard service model, the fact we’ve got the data object structure available, helps us in defining this mapping.

As our example REST API returns all the properties on the root level, the mapping is a simple one-to-one mapping. The left-hand side shows the HTTP response side, which needs to be mapped to the data object model structure on the right-hand side:

REST Service Definition - Lookup Operation Output Mapping

Since the body of the response contains the data on the root level, the Path column is empty. However, if this wouldn’t have been the case the Path can be used to define where the value can be found (using JSON-Pointer syntax). Note that the Path is applied on top the Ouput path configured above. This avoids having to repeat the common path multiple times.

Create and Update Operation

The Create and Update operations are quite similar: they both start from a representation of the data object, typically through forms, and need to either create or change the corresponding data.

Configuring the create operation is easy: only the method needs to be set to POST. The Base URL is already okay for the Create operation.

REST Service Definition - Create Operation

The Update operation looks similar, except using PUT for the method and adding /${lookupId} to the URL (which is already done automatically by default).

The input and output parameters of both operations is exactly the same. The input mapping shows the representation of the data object (coming from a form) that needs to be mapped to the REST body of the REST call.

REST Service Definition - Create Operation Input Mapping

Since the REST API is simple here, all values go on the root of the JSON body. In a more complex scenario, the Body location column can be used. This can for example have a value like data.customer.field, which means that the value will be placed in the field property of the customer object, which is part of the data object. Note that the Body location overrides anything in the name column. Only when Body location is missing, the name value will be used.

Alternatively to mapping the JSON body with this table, a Body template resource can be placed on the classpath of the Flowable installation. If set, the table is ignored and the template resource (using Spring resource reference syntax) will be used to generate the body. This template is a Freemarker template and has all data variables available to build the body.

See The Service Registry Developer Guide for an example of these templates.

The Create and Update REST calls typically return a response. This response needs to be mapped to the data object instance in a way similar to the Lookup above:

REST Service Definition - Create Operation Output Mapping

Note that the Body location and Path settings don’t use the same syntax. The Path settings uses JSON-Pointer syntax, but the Body location uses a much simpler 'name and dots' syntax.

Delete Operation

The delete operation is the simplest of all operations. Beyond changing the Method to DELETE, nothing more is needed as the URL was already pre-configured correctly for our simple example here.

REST Service Definition - Delete Operation

A delete operation has neither input nor output parameters, as only the lookupId can be used and nothing needs to be mapped back as the data object instance gets deleted when invoked.

Example: How To Use the Data Object Model in a Case Model

Let’s use the models from above to create a simple case model. The goal is to create a CMMN case model that can be used to create and manage customer data.

The end result will be a CMMN model that looks like:

CMMN Model

Of course, this is but a minimal model highlighting specifically using a data object model (backed by a service model). A realistic customer case model would have way more steps and details than this example.

Creating the CMMN Model

In Flowable Design, click on Apps in the header bar. Create a new App and name it Customer app. Include the data object and service model we’ve created above by clicking the large + button and selecting Include an existing model into the app.

Now, click the + button again and select Create a new model for the app and Case in the next step. Give the model a name (e.g. Customer Case) and a unique key (e.g. customerCase).

Create CMMN model

Click Create new model. The view will now change to the CMMN editor.

The Start Form

When a case instance is started for this model, we want to show a form that asks for customer data.

Click on the plan model (the only thing shown on the screen right now) and click in the property panel on the Start form property. The New tab is open by default, so fill in a name for the start form and click on Create:

Case Start Form

An empty form model is now shown. Before we model the form, we have to configure it to be bound to a data object model. To do this, click on the Data model property in the property panel:

Case Start Form Data Model Configuration

A popup is now shown that allows us to fill in the data object model we want to reference. Here, we fill in the following:

  • variable name: customer

    • This is how we’ll reference the data object in the form value bindings.

  • Data object definition key: customer

    • This is the key of the data object model.

  • Mode: Create

    • When handling the form, we need to know whether this form will create the data object or only view or modify it.

Case Start Form Data Object Model Popup

This effectively creates a sort of 'scope', similar to the root or parent scope where variables can be stored on. It is also possible to bind the data object instance to a root or parent variable (e.g. using root.customer).

Let’s add some fields to the model:

Case Start Form Fields

The fields here are

  • Name, bound to and of type text.

  • Active?, bound to and of type checkbox.

  • Country, bound to and of type text.

  • Fee, bound to customer.yearlyFee and of type number.

Note that each fields is bound to customer., which is the variable configured for the data object in the popup above.

Publishing the App

Save the CMMN model and go to our app model (it is the model right at the top when going to the Apps tab). The three models (data object, service and CMMN model) are part of the app:

App view

Now click the Publish button (this will only work when you have a running Flowable Work or Engage where you can publish against).

Go to your Flowable Work or Engage installation, log in, Click the New button and select Work. Type customer in the search field. The customer case is now be selectable:

Definitions View

Select it. The start form is now shown:

Start Form

Filling in the form and clicking Submit will start a case instance and immediately end it, as the case has no tasks to do.

The Work Form

Simular to the start form, we can add a Work Form to the case model. This form can be seen from the case instance view and the goal is to display the customer information, but in a read-only mode. The actual editing will be implemented with a user task later.

Close to the Start form property, there is the Work form property. Create a new form:

Case Work Form Property

Similar to the start form, click the Data model property of the form. Give it the same customer variable and key, but change the mode to View this time:

Case Work Form Data Model Configuration

The fields look exactly the same as for the start form, except that all fields have the Enabled checkbox set to false.

The Customer Update Task

Let’s add a few things to the case model:

  1. Add a stage with name Active

  2. Add a user event listener Inactivate in this stage

  3. Add an exit sentry to this stage and link it to the event listener

  4. Add user task named Change customer details to this stage

  5. Make this task manual activated (select the manual activation checkbox in the property panel)

  6. Make this task (infinite) repeatable (select the repetition checkbox in the property panel)

  7. Add a stage with name Inactive below the other stage

  8. Add an entry sentry to the second stage. Link it to the first stage and select the Exit transition. We want to move to this stage when the first one is terminated

Select the user task again and create a new form:

Update Task Form

Similar to above, configure the data object model for this form. Set the mode to Modify.

Note: Modify actually also allows for viewing data, as will become clear in the next step.

Update Task Form Data Model

Let’s create a simple form, only adding a name and fee field. Set the Enabled checkbox of the Name field to false.

Update Task Form Fields

Let’s deploy the app: either go to the Apps tab, select the app model and click Publish or click the Quick Deploy button in the editor toolbar (the cloud icon with the triangle).

Go to Flowable Work or Engage and, like before, start a new case instance and fill in the start form. After starting the case instance, the view is now more interesting. The two stages are shown in the header and when clicking the Work form tab, the read-only form from above is displayed:

Case View

To start the (manual) user task, we need to click the Change customer details button in the header. This will start the user task, which can be found by clicking the Open tasks tab. The form to update the customer data is shown:

Update Task View

Change the fee to another value. If you’re running the example applications, you’ll see in those applications the output

Update customer Customer{id='8db19819-62df-4baa-b746-12fae1376941', name='John Doe', active=false, country='Belgium', yearlyFee=123456}

Note that the Change customer details tasks can be started an infinite number of times. In reality, you’d probably want to limit this to one. The Max instance count property on the user can be used to make sure there is only one user task open at any given time.

Using the Service Registry Task

This feature is only available from Flowable 3.5.1

Let’s finish up the CMMN model:

Cmmn Model Second Stage

  1. Add an event listener to the Inactive stage with name Remove customer data. The idea is that when the Inactivate event listener is selected, the first stage gets terminated, which brings the customer in an inactive but not yet deleted state. To actually delete the data, the Remove customer data event listener needs to be triggered.

  2. Add a service registry task Delete customer data to the same stage and link it to the event listener with an entry sentry.

  3. Add an exit sentry to the whole case (this is fully optional, as the behavior would be the same without here, but it’s visually clearer).

Above, we’ve configured the service model to be based on a data object model. However, this service model is still available as a regular service model and thus can be referenced from the service registry task.

Select the Delete customer data task and select the Delete operation from the model and operation. In the Input parameters configuration, bind the value to ${}.

Service Registry Task Configuration


  1. Deploy the app again and start a new case instance.

  2. Click the Inactivate button in the header. This brings the case instance to the Inactive stage.

  3. Click the Remove customer data button in the header.

The customer data is now deleted. When running with the example appliaction, in the logging you can now see something like

Deleted customer Customer{id='3465f3ae-e8e9-43e2-a10e-27887270e764', name='John Doe', active=false, country='Belgium', yearlyFee=123456}