Skip to main content

Tutorial

In this tutorial, we'll step through examples to highlight the capabilities of the Operate API, such as rendering a BPMN diagram.

Getting started​

  • You need authentication to access the API endpoints. Find more information here.
  • We will use the bpmn-js library to render the diagram and add overlays. Visit the documentation on embedding the pre-packaged viewer for more details.

Set up the demo project​

  1. Create a new folder using the following command:
mkdir operate-api-demo
cd operate-api-demo
  1. Initialize the project using the following command:
npm init --y
  1. Add a proxy server to bypass CORS errors. Create a server.js file inside the project folder with the following contents:
const http = require("http");
const request = require("request");

const server = http.createServer((req, res) => {
request.get(
{
// Replace http://localhost:8080 with your Operate API url if its running on different port.
url: `http://localhost:8080${req.url}`,
headers: {
// Replace COOKIE_VALUE with your OPERATE-SESSION cookie value.
Cookie: "OPERATE-SESSION=COOKIE_VALUE",
},
},
(error, response, body) => {
if (error) {
console.error(error);
res.statusCode = 500;
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Content-Type", "application/json");
res.end("Error: Could not get data from API");
} else {
res.setHeader("Content-Type", response.headers["content-type"]);
res.setHeader("Access-Control-Allow-Origin", "*");

res.end(body);
}
}
);
});

server.listen(3030, () => {
console.log("Proxy server listening on port 3030");
});
  1. Install the necessary packages using the following command:
npm install request
  1. Run the server using the following command:
node server.js

Render a BPMN diagram​

  1. Create an index.html file and include the bpmn-js script:
<!doctype html>
<html>
<head>
<script src="https://unpkg.com/bpmn-js/dist/bpmn-viewer.development.js"></script>
</head>

<body></body>
</html>
  1. Create a styles.css file to maintain the styling:
html,
body,
#canvas {
height: 100%;
padding: 0;
margin: 0;
}

.flow-node-incident {
width: 20px;
height: 20px;
display: flex;
justify-content: center;
align-items: center;
background-color: #ff3d3d;
color: White;
border-radius: 10px;
font-family: Arial;
font-size: 12px;
font-weight: bold;
transform: translateX(-50%);
}
  1. Create an api.js script file and write a function that fetches the process XML by definition:
async function fetchDiagram() {
return fetch(
// Replace {PROCESS_DEFINITION_ID} with a process definition id.
// http://localhost:3030 is the URL of the Proxy server, which should stay the same.
"http://localhost:3030/v1/process-definitions/{PROCESS_DEFINITION_ID}/xml",
{
method: "GET",
}
).then((response) => response.text());
}
  1. Fetch and render the diagram:
<!doctype html>
<html>
<head>
<!-- replace CDN url with local bpmn-js path -->
<script src="https://unpkg.com/bpmn-js/dist/bpmn-viewer.development.js"></script>
<link rel="stylesheet" href="./styles.css" />
</head>

<body>
<!-- BPMN diagram container -->
<div id="canvas"></div>
<!-- JS file that includes our API methods -->
<script src="./api.js"></script>
<script>
// BpmnJS is the BPMN viewer instance
const viewer = new BpmnJS({ container: "#canvas" });

async function renderDiagram() {
const diagram = await fetchDiagram();

try {
await viewer.importXML(diagram);

const canvas = viewer.get("canvas");

canvas.zoom("fit-viewport");
} catch (err) {
console.log("err", err);
}
}

renderDiagram();
</script>
</body>
</html>
  1. Open index.html in your browser to see the rendered diagram.

    render diagram

Show statistics on the diagram​

  1. Add a new function to the api.js file that fetches the flow node statistics for a specified process instance id:
async function fetchStatistics() {
return fetch(
// Replace {PROCESS_INSTANCE_ID} with a process instance id.
// http://localhost:3030 is the URL of the proxy server, which should stay the same.
"http://localhost:3030/v1/process-instances/{PROCESS_INSTANCE_ID}/statistics",
{
method: "GET",
}
).then((response) => response.json());
}
  1. Add an overlay that displays the number of incidents on flow nodes:
// ...
canvas.zoom("fit-viewport"); // insert following code below this line

const overlays = viewer.get("overlays");

fetchStatistics()
.then((statistics) =>
statistics.forEach(({ activityId, incidents }) => {
if (incidents > 0) {
overlays.add(activityId, "flowNodeState", {
position: {
bottom: 9,
right: 0,
},
html: `<div class="flow-node-incident">${incidents}</div>`,
});
}
})
)
.catch((err) => {
console.error("An error occured when fetching statistics: ", err);
});

// ...
  1. Open index.html in your browser to see the incident overlay displayed on the related flow node(s), if there are any.

display incidents

Highlight processed sequence flows on the diagram​

  1. Add a new function to the api.js file that fetches the processed sequence flows for a specified process instance id:
async function fetchSequenceFlows() {
return fetch(
// Replace {PROCESS_INSTANCE_ID} with a process instance id.
// http://localhost:3030 is the URL of the Proxy server, which should stay the same.
"http://localhost:3030/v1/process-instances/{PROCESS_INSTANCE_ID}/sequence-flows",
{
method: "GET",
}
).then((response) => response.json());
}
  1. Color the processed sequence flows:
// ...
const overlays = viewer.get("overlays"); // insert following code below this line

fetchSequenceFlows()
.then((sequenceFlows) => {
sequenceFlows.forEach((sequenceFlow) => {
const elementRegistry = viewer.get("elementRegistry");
const graphicsFactory = viewer.get("graphicsFactory");
const element = elementRegistry?.get(sequenceFlow);
if (element?.di !== undefined) {
element.di.set("stroke", "#4d90ff");

const gfx = elementRegistry?.getGraphics(element);
if (gfx !== undefined) {
graphicsFactory?.update("connection", element, gfx);
}
}
});
})
.catch((err) => {
console.error("An error occured when fetching sequence flows: ", err);
});

// ...
  1. Open index.html in your browser to see the processed sequence flows highlighted.

color sequence flows

Full demo​

For additional details, visit the GitHub full working demo.