Q&A: JSON requests

Q&A: The One Where a JSON Request is Sent While Calling an External REST

Q: How do I send and receive a JSON request while calling an external REST from within the BPMN?

There are a couple of questions wrapped up in one that need to be addressed here. It’s important first to ask, “What result are you trying to achieve?” We typically get this question when someone is trying to post some JSON data to an external service.

While this is certainly possible from within the BPMN itself, it might not be the best way to go about it. To do this from within the BPMN, you would use the AbstractBpmnActivityBehavior class, but this has some drawbacks. The biggest one is that, should something go wrong and the task can’t be completed, you can’t create an incident during the signal() call. There’s no practical way to create an incident, which means your process will be largely unaware of any failures.

The external task implementation is more powerful as you can use externalTaskService.failure() and externalTaskService.bpmnError() in cases when something goes wrong with your service response.

Let’s start with a simple BPMN model to visualize the process of sending JSON data:

A 2-step BPMN Diagram

Using a script task

The first task is a script task that builds a JSON object for us:

var caller_id = {"Top Level": { "AValue": "A String", "BValue": 33, "NextLevel": {"FinalValue": 33.3}}}

I defined this in a script task in the BPMN model:

A script task

I exported the variable as caller_id in the definition, so now that variable is available in the process instance. 

Note: Using a script here is also one of the drawbacks of doing things this way. It is difficult to maintain processes that have internal script tasks, so be careful with relying on them when building your solution.

The next step in the process is using an external task that will send the JSON data along.

Using an external task

There are lots of examples of how to create and call external tasks (provide links) so we won’t go into how to create an external task here. Instead, we’ll look at how to send JSON data to the external task.

An external task definition

Next, we’ll see how that JSON data arrives in the external task handler:

const { Client, logger } = require("camunda-external-task-client-js");
// configuration for the Client:
//  - 'baseUrl': url to the Process Engine
//  - 'logger': utility to automatically log important events
const config = { baseUrl: "https://localhost:8080/engine-rest", use: logger };

// create a Client instance with custom configuration
const client = new Client(config);

// subscribe to the topic: 'handle_call'
client.subscribe("handle_call", async function ({ task, taskService }) {
  const caller_id = task.variables.get("caller_id");
  const outcome = handle_call_with_id(caller_id);
  // complete the task
  await taskService.complete(task);

function handle_call_with_id(caller_id) {
  console.log("Handling call with id: " + caller_id);
  // run business logic / perform REST call	
  return "call_handled";

This code example won’t call an external REST application, but some custom business logic can be added easily in the handle_call_with_id  function. 

If we run this, we will see the following output:

/usr/local/bin/node ./task-handler.js
✓ subscribed to topic handle_call
Handling call with id: undefined
✓ completed task 22b165eb-6374-11ec-952c-0242661ea8d3
Handling call with id: var caller_id = {"Top Level": { "AValue": "A String", "BValue": 33, "NextLevel": {"FinalValue": 33.3}}}
✓ completed task 478c5da4-6374-11ec-952c-0242661ea8d3

As you can see, the data sent by the process was indeed valid JSON. (Feel free to paste it into a JSON-validator to see if it’s valid.)

So there you have it! A working example of how to send JSON data from a BPMN process to an external service. If you run into any trouble, please visit our forum for help from our engineers and community members.