Camunda External Task Client for NodeJS

repository·master·Indexed 42 days ago

https://github.com/camunda/camunda-external-task-client-js

A NodeJS client for Camunda External Tasks that allows developers to implement BPMN Service Tasks by polling the Camunda engine. Version 3.1.1-SNAPSHOT supports task subscription, lock management, failure handling, and BPMN error triggering. It requires NodeJS >= v18 and provides a Client class for managing polling and topic subscriptions.

Tokens
12.6K
Snippets
40
Records
57
Agent score
51%

What's inside Camunda External Task Client JS

  1. Understand typed values

    master

    A typed value is a structured object used to preserve the data type and additional metadata of a variable. This is useful when you need to know if a value is a string, integer, json, XML, etc.

    Structure:

    {
      "value": "some value",
      "type": "string",
      "valueInfo": {}
    }
    • value: The actual data.
    • type: The variable type (e.g., integer, long, string, boolean, json, XML, date). Note that type names are not case sensitive when setting.
    • valueInfo: An object containing additional, value-type-dependent properties (e.g., { "transient": true }).
  2. Use Interceptors to modify requests

    master

    Interceptors are functions that allow you to intercept and modify the configuration of a request before it is sent to the engine.

    • Interceptors receive the current request configuration and must return a new (or modified) configuration.
    • If multiple interceptors are provided, they are executed in a pipeline (the output of one is the input to the next) in the order they were defined.
    • A common use case is implementing BasicAuthInterceptor for authentication.
  3. How token caching works in KeycloakAuthInterceptor

    master

    To minimize requests to the Keycloak token endpoint, the KeycloakAuthInterceptor caches the access token until it expires.

    To prevent using a token that expires exactly during an API request, the interceptor uses a cacheOffset. It subtracts this offset (defaulting to 10 seconds) from the token's actual validity time. For example, if a token is valid for 60 seconds, the interceptor will treat it as expired after 50 seconds, ensuring that the token remains valid for the duration of the subsequent API call.

  4. Quickstart: Implement a BPMN Service Task in NodeJS

    master

    To use the client, follow these steps:

    1. Ensure Camunda is running.
    2. Create a BPMN process with an External Service Task and define a topic name (e.g., creditScoreChecker).
    3. Deploy the process to the Camunda engine.
    4. Use the Client to subscribe to the topic and handle tasks using the provided taskService.

    Note: While examples use async/await, you can also use Promises.

    import { Client, logger } from "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: "http://localhost:8080/engine-rest", use: logger };
    
    // create a Client instance with custom configuration
    const client = new Client(config);
    
    // subscribe to the topic: 'creditScoreChecker'
    client.subscribe("creditScoreChecker", async function({ task, taskService }) {
      // Put your business logic
      // complete the task
      await taskService.complete(task);
    });
  5. Handle JSON and Date variables

    master

    The Variables class automatically handles serialization and deserialization for Date and JSON types.

    Date Variables

    • Setting: You can pass a JavaScript Date object directly to .set() or .setTyped(). Alternatively, you can pass a date string to .setTyped() with type: "date".
    • Getting: .get() and .getTyped().value will return a JavaScript Date object.

    JSON Variables

    • Setting: You can pass a JavaScript object directly to .set() or .setTyped(). The type will be automatically detected as json.
    • Getting: .get() and .getTyped().value will return the original JavaScript object.
    // --- Date Example ---
    variables.set("someDate", new Date());
    
    // Setting via string in setTyped
    variables.setTyped("anotherDate", { 
      type: "date", 
      value: "2016-01-25T13:33:42.165+0100", 
      valueInfo: {}
    });
    
    console.log(typeof variables.get("anotherDate")); // "object" (a Date instance)
    
    // --- JSON Example ---
    variables.set("meal", { id: 0, name: "pasta" });
    
    const meal = variables.get("meal");
    console.log(meal.name); // "pasta"
  6. Use BasicAuthInterceptor for authentication

    master

    If your Camunda Engine requires Basic Authentication, use the BasicAuthInterceptor to automatically add the necessary credentials to all outgoing requests. You create an instance of the interceptor with your credentials and pass it to the interceptors option when initializing the Client.

    const {
      Client,
      BasicAuthInterceptor
    } = require("camunda-external-task-client-js");
    
    const basicAuthentication = new BasicAuthInterceptor({
      username: "demo",
      password: "demo"
    });
    
    const client = new Client({
      baseUrl: "http://localhost:8080/engine-rest",
      interceptors: basicAuthentication
    });
  7. Run the Order Example

    master

    This example demonstrates a NodeJS implementation of an order processing workflow using the Camunda External Task Client.

    Prerequisites:

    • NodeJS version >= v18
    • A running instance of Camunda
    • The order.bpmn model file (available in assets/order.bpmn)

    Setup Steps:

    1. Deploy the order.bpmn model to your Camunda instance using the Camunda Modeler.
    2. Install dependencies using npm or yarn.
    3. Execute the example script using node index.js.

    Expected Output: Upon successful execution, the terminal should indicate subscription to the topic and task completion:

    ✓ subscribed to topic invoiceCreator
    ✓ completed task 21d19522-3e4c-11e8-b8df-186590db1cd7
    # Install dependencies
    npm install
    
    # Run the example
    node index.js
  8. Implement a Handler Function

    master

    A handler function is an asynchronous function used to process a fetched task. It receives an object containing the task and the taskService. You use the taskService to communicate the outcome of your business logic back to the Camunda engine (e.g., completing the task, handling failures, or extending locks).

    To use a handler, subscribe to a specific topic using client.subscribe(topicName, handler).

    const { Client, logger, Variables } = require("camunda-external-task-client-js");
    
    // create a Client instance with custom configuration
    const client = new Client({ baseUrl: "http://localhost:8080/engine-rest", use: logger });
    
    // create a handler function
    const handler = async function({ task, taskService }) {
      // get the process variable 'score'
      const score = Variables.get("score");
      // set a process variable 'winning'
      const processVariables = new Variables().set("winning", score > 5);
      // set a local variable 'winningDate'
      const localVariables = new Variables().set("winningDate", new Date());
    
      // complete the task
      await taskService.complete(task, processVariables, localVariables);
    };
    
    // susbscribe to the topic: 'topicName'
    client.subscribe("topicName", handler);
  9. Run the granting-loans example

    master

    This example demonstrates a NodeJS implementation of a loan granting process.

    Prerequisites:

    • NodeJS >= v18
    • A running instance of Camunda

    Steps to run:

    1. Deploy the BPMN model assets/loan-process.bpmn to your Camunda instance using the Camunda Modeler.
    2. Install dependencies using npm install or yarn.
    3. Execute the example with node index.js.

    Expected Output: Upon successful execution, you should see subscription and completion logs similar to:

    ✓ subscribed to topic creditScoreChecker
    ✓ completed task 897ce191-2dea-11e8-a9c0-66b11439c29a
    # Install dependencies
    npm install
    
    # Run the example
    node index.js
  10. Use KeycloakAuthInterceptor for OpenID Connect authentication

    master

    If your Camunda REST API is protected by Keycloak Gatekeeper, use the KeycloakAuthInterceptor to automatically add a Bearer token header to all requests. This interceptor handles the OpenID Connect flow by requesting a token from the Keycloak token endpoint using a client ID and client secret.

    To use it, instantiate KeycloakAuthInterceptor with your Keycloak configuration and pass the instance into the interceptors array of the Client constructor.

    const {
      Client,
      KeycloakAuthInterceptor
    } = require("camunda-external-task-client-js");
    
    const keycloakAuthentication = new KeycloakAuthInterceptor({
      tokenEndpoint: "https://your.keyclock.domain/realms/your-realm/protocol/openid-connect/token",
      clientId: "your-client-id",
      clientSecret: "your-client-secret"
    });
    
    const client = new Client({
      baseUrl: "http://localhost:8080/engine-rest",
      interceptors: keycloakAuthentication
    });
  11. Configure the built-in logger in the Client

    master

    The logger is a middleware that logs events during the client lifecycle. You can enable it by passing it to the use option in the Client constructor. By default, if no level is specified, the logger uses the info level.

    const { Client, logger } = require("camunda-external-task-client-js");
    
    const client = new Client({
      use: logger,
      baseUrl: "http://localhost:8080/engine-rest"
    });