Example of completing a User Task with REST API

Hi,

I have a User Task and I assign it to a user. In the runtime, after the assignment, the task is in waiting state until it’s completed, right?
I don’t want the user to complete the task by clicking “Complete” in the Tasklist application but I want to complete it with a REST call when I receive an external trigger.

Can anyone point me a very simple example to call some code to complete a User Task with REST API?

Thanks!

Shouldn’t be a problem you just need to use the Complete rest call there is an example in the docs.

1 Like

Thanks @Niall, I’ve seen that documentation but I’m looking for a github example what to write in my code, how to trigger the POST method from an Execution/Task Listener, etc.

Hi,

Whatever your code (in which language do you work ?), you have to send a post request to your rest API.

for me (4gl), it’s look like that :

LET taskId = arg_val(1); 
LET url = "http://localhost:8080/camunda/api/engine/engine/default/task/", taskId, "/submit-form";
LET req = com.HttpRequest.Create(URL);
CALL req.setMethod("POST");
CALL req.setHeader("Content-Type", "application/json")
CALL req.setHeader("Accept", "application/json")
CALL req.doTextRequest(data); #send the request to submit the task
TRY
    LET res = req.getResponse()
    IF res.getStatusCode() != 200 or res.getStatusCode() != 204 THEN #StatusCode have to be 204
        DISPLAY  "HTTP Error ("||res.getStatusCode()||") ",res.getStatusDescription()
        RETURN "error"
    END IF
CATCH 
    DISPLAY "request don't work"
END TRY

my variable “data” is a JSON like explain in the docs.

Hope I’ve help.
Romain.

Thanks @ethaqnix for the suggestion.
I use Java and normally I see lines of code using annotations like

     @POST
     @Path("/post")
     @Consumes("application/json")

but I’m not very familiar with.
What are the configurations I need in order to make such code work?
So, I’m looking for a simple example with a Java code to make the POST call that is described in the documentation.

Thanks!

Hi,

as you mentioned before you are in a Task/Execution Listener?
So, why do you want to you use the REST API to complete the Task?
You could easily use the taskService.

If this is not the case, here an example to call the post request from JAVA. But don’t forget, you have to know the task id.

 String url = "http://localhost:8080/engine-rest/task/c44b7c61-5026-11e7-9d74-064bed1e2b33/complete";
    	  URL obj = new URL(url);
    	  HttpURLConnection con = (HttpURLConnection) obj.openConnection();
	 
	        // Setting basic post request
	  con.setRequestMethod("POST");
	  con.setRequestProperty("Content-Type","application/json");
 
//if you want to add some variables
	  String postJsonData = "{\"variables\":\r\n    {\"aVariable\": {\"value\": \"aStringValue\"},\r\n    \"anotherVariable\": {\"value\": 42},\r\n    \"aThirdVariable\": {\"value\": true}}\r\n}";
	  
	  // Send post request
	  con.setDoOutput(true);
	  DataOutputStream wr = new DataOutputStream(con.getOutputStream());
	  wr.writeBytes(postJsonData);
	  wr.flush();
	  wr.close();
	 
	  int responseCode = con.getResponseCode();
	  System.out.println("nSending 'POST' request to URL : " + url);
	  System.out.println("Post Data : " + postJsonData);
	  System.out.println("Response Code : " + responseCode);

regards,
Dominik

Hi @dominikh,

No I’m not in an Execution/Task Listener.
Actully, what I want to achieve is while the User Task is in waiting state (meaning it’s being worked on), I get an external trigger and I want with the REST call to complete the task.

I will have a look in your code, thanks!

Best,
Kostas

Hi @kontrag ,

If you don’t want to pass any variables you can set postJsonData to an empty String.
Is this the normal behavior of your Process? Or is the external trigger some kind of special case?

regards,
Dominik

There’s a chance that some variables need to be passed for the rest of the control flow, but in most cases it’s just the action of completion of the task (I can handle the variables from the external trigger somehow).

Hi,

as a suggestion, you could model this external trigger as completing the task, or you could model it as an interrupting event.

Given the brief description, I would tend to model it as an interrupting event. If this were the case, you may want to consider a different API call.

regards

Rob

@Webcyberrob that was exactly what I was thinking about.
Maybe @kontrag can provide the process model that we can understand the use case.
regards

The process model is not that complex, at least the main idea.
There’s a task to be executed by an external system. When the external system completes the task, it sends a message to my application and the flow can move on.
Initially, I thought something like the following:

Then I thought the idea of using a User Task, which is in a waiting state and when I receive the message from the external system, I want to complete the Task with the API.

Hi @kontrag

to correlate the message would be a much better approach in my point of view.
You could do the correlation with the businesskey and the messageName.

 String url = "http://localhost:8080/engine-rest/message";
 URL obj = new URL(url);
 HttpURLConnection con = (HttpURLConnection) obj.openConnection();
 
	        // Setting basic post request
 con.setRequestMethod("POST");
 con.setRequestProperty("Content-Type","application/json");
 
	//Set the correlation stuff
 JSONObject camundajson = new JSONObject();
 camundajson.put("messageName", "YourMessageName");
 camundajson.put("businessKey", "YourBusinessKey");
	 // Send post request
 con.setDoOutput(true);
 DataOutputStream wr = new DataOutputStream(con.getOutputStream());
 wr.writeBytes(camundajson.toString());
 wr.flush();
 wr.close();
 
 int responseCode = con.getResponseCode();
 System.out.println("nSending 'POST' request to URL : " + url);
 System.out.println("Post Data : " + postJsonData);
 System.out.println("Response Code : " + responseCode);

Another idea is to use the external task pattern.

1 Like

I’ve achieved the message correlation with

MessageCorrelationBuilder correlationBuilder = runtimeService.createMessageCorrelation(catch_event_message);
correlationBuilder.processInstanceId(process_instance_id);
correlationBuilder.correlateAllWithResult();

The point is that what if the task is not completed? What if it needs to be re-assigned to another user?
Then in the catching message I should check many options.
So I started to think of a solution with the User Task where the task is still in waiting state and I can keep receiving many messages.
Still, not sure which one is better solution for me at the moment but since I achieved the first one with the Service Task - Message correlation, I want now to try the User Task - REST API completion.

I also considered the External Task pattern but I don’t want the external users to be responsible and go fetch the tasks themselves. I want my application to have control and assign the tasks immediately.

Hi @kontrag

Let’s go some steps back.
Is your external System some kind of Tasklist?
If this is the case you could just create a UserTask and add an TaskListener. With this Listener you can inform the external system when the task is created.

To complete the Task you can call the post request I mentioned before.

Hi @dominikh,

With external system, I mean an external application that will further do some actions. From Camunda, I want actually to trigger the movement of a robot. When the movement is complete, the robot will inform me back with a message that the task is complete.
Your idea is what I’m trying to achieve at the moment. With a Task Listener (or maybe Execution Listener??) I will send information to the robot to perform a movement. The User Task will be in waiting state until the robot informs me back and at that point I will call the Complete method of the API to move on.

Thanks!

Hi,

given your description, I would model this as a service task followed by a receive task, something like;

Initiate Movement -> Receive Movement Complete

Hence the Initiate movement service task generates some sort of signal, message or API call to instruct the machine to move. The process then transitions to a wait sate on the receive task. When the movement is complete, the Robot initiates a message back to the engine indicating the movement is complete.

regards

Rob

Thanks @Webcyberrob,
So you are in favor of the first approach I explained above (with the bpmn example I gave).
Can you argue about such a design choice?
This what I’m currently struggling to decide on.

Thanks!

Hi,

Rationale for this design over a user task;
I tend to reserve user tasks for a human interaction. In particular, the human is often a knowledge worker and thus the ‘wait state’ associated with the user task is often the ‘think time’. In addition, a user task often has a user interface associated with it.

In your case, the process is orchestrating an asynchronous remote procedure call to initiate an activity in an external system and wait for a signal indicating the activity is complete. You could model this as a single service task and use the asynchronous Camunda service task, however this is advanced Camunda usage and I would only recommend it use for advanced Camunda users. A simpler approach with the same behaviour is a service task to initiate and a receive task to wait for the response. Note I am advocating using a receive task rather than a receive message event as per your model. Rationale for this choice is you can add interrupting boundary events on the receive task. It can be done with a receive message event, but then you get into an event driven gate…

On the other hand, if you had many robots and each robot just grabbed the next ‘task’ to do, then an external service task may be even more approriate…

regards

Rob

2 Likes

Hi @Webcyberrob,

I see your points and I fully agree!
I was thinking though that the User tasks can help me in the cases where the robot task is paused, or needs to be re-assigned to another user. With the Service-Receive Task, once you send the task, then your process sits on the waiting state while the actual work being done is before that state. Think of the cockpit, where the token will be in the Receive Task and not in the Service Task.

In any case, many things to argue and thanks for the discussions!

Best,
Kostas