Connectors#
A service task can call a connector instead of a service. A connector is a REST API, described by an OpenAPI document, that an administrator adds to the server with its authorization key. The model names the connector and one of its operations, and gives the operation's inputs and the parts of the answer to keep.
- No code: calling an API needs no method in the application's services.
- No credentials in models: the server holds the API's address and key; a model only names
<connector>/<operation>. Models can be exported, shared and imported without leaking a key. - Governed: the administrator chooses which operations designers may use, and which groups may use them.
Services stay: a service task calls either a service (application code, as in Service Task) or a connector, never both.
New in 3.5: see What's new in 3.5.
In the model#
The task names <connector>/<operationId> in camunda:connector, with the connector's own inputs and outputs:
<bpmn:serviceTask id="GetRepo" name="Get the repository">
<bpmn:extensionElements>
<camunda:connector>
<camunda:connectorId>github/repos/get</camunda:connectorId>
<camunda:inputOutput>
<camunda:inputParameter name="owner">${data.owner}</camunda:inputParameter>
<camunda:inputParameter name="repo">${data.repo}</camunda:inputParameter>
<camunda:outputParameter name="description">${output.description}</camunda:outputParameter>
<camunda:outputParameter name="starsCount">${output.stargazers_count}</camunda:outputParameter>
</camunda:inputOutput>
</camunda:connector>
</bpmn:extensionElements>
</bpmn:serviceTask>
connectorIdis the administrator's id for the connector (github), a/, and the operation'soperationIdin the OpenAPI document (repos/get).- Inputs are named as the operation's parameters (path, query and header parameters), each a value or an
expression. A JSON request body is given whole as
body, or field by field asbody.<field>. - Outputs:
${output}is the answer's body (JSON, else text);${output.<field>}one of its fields. Each output parameter keeps it in the instance data under its name (data.starsCount). - Service tasks and send tasks can call connectors.
Camunda 7's generic http-connector (a raw URL and method) is not supported: verify reports a connectorId
that is not <connector>/<operation>.
In the model editor#
In the Service group of a service or send task, Calls is Service or Connector. Choosing Connector opens the connector wizard, a window over the editor in three steps:
- Operation: every operation you may use, grouped by connector. Type to search: the connector, the operation's id, method, path and summary are searched, and every word must match. Enter picks the operation when only one is found.
- Inputs: a row for each of the operation's inputs, with its description, where it is sent (path, query,
header, body) and its type. Required inputs are marked
*and filled in from the data field of the same name (${data.owner}); from data fills one in again, and an input with a list of values offers them. An empty input is not sent. - Outputs: every part of the answer the document describes (and the whole answer), each with a check box and the data name it is kept under: the field's own name at first. All ticks every one.
Nothing changes in the model until Done, which writes the connector, its inputs and its outputs as one step (one Undo takes it back). Cancel, ✕ or Escape leaves the task as it was.
The Service group then shows what the task calls: the operation with its method and path, the inputs, the outputs, the HTTP errors the operation answers (a boundary error event catches them, below) and what is wrong (no operation chosen, a connector the server does not have, a required input with no value). Edit connector… opens the wizard again, at its inputs, with the task's values.
Switching Calls back to Service removes the connector; choosing a connector removes the service name.
Adding a connector (administrators)#
Administration → Connectors (/dashboard/admin/connectors) lists the server's connectors and a catalog of
public APIs to add from. To add one:
- From the catalog: filter the list and add an API. The catalog is
catalog/connectors/api-catalog.json;
CONNECTOR_CATALOG_URL(a web address or a file) names another. - Another API: an id (the name models use; it cannot change later), and the OpenAPI document as a URL or pasted. OpenAPI 3.0 and 3.1, JSON or YAML. Swagger 2.0 is not supported yet.
The server keeps a copy of the document: a document that changes elsewhere changes nothing until the connector
is refreshed. The base URL defaults to the document's first servers entry.
A connector's page sets:
| Section | |
|---|---|
| Settings | Name, description, base URL, the groups that may design with it (empty: every designer), timeout, retries, enabled. |
| Authorization key | The scheme from the document's securitySchemes, or one given by hand: bearer token, API key (its header, query parameter or cookie name), or basic (user:password). The key is write-only: the page shows its type, its last 4 characters and when it was set, never the key. |
| Operations | Which of the API's operations designers may use. A large API is narrowed to the few that matter. |
| Test the connection | Calls an operation (by default a GET that needs no input) with the inputs given, and shows the answer. |
| OpenAPI document | Refresh it from its URL, or give a new one; the operations added and removed are listed. |
| Delete | Lists the models that use the connector first. |
Keys are encrypted (AES-256-GCM) with CONNECTORS_KEY from .env, which is never stored in the database.
Without CONNECTORS_KEY a connector cannot be given a key, and the page says so. A backup holds the encrypted
key only: restoring it needs the same CONNECTORS_KEY.
From the console#
With administration off (DISABLE_ADMIN=true), or from a script, the console (npm run cli) has the same
operations:
| Command | |
|---|---|
co |
list the connectors |
coa |
add one (the OpenAPI document as a URL or a file) |
cok |
set its key |
coe |
enable or disable it |
cot |
test it |
cor |
refresh its document |
cod |
delete it |
coc |
call one of its operations with inputs |
From the command line, the command and its answers: npm run cli -- cod asana deletes the connector asana
(and quits), npm run cli -- co lists them.
Who may use a connector#
- In the editor, the wizard lists only the connectors that are enabled and allowed to the designer's groups, and only their enabled operations.
- At run time, the connector and the operation must exist and be enabled. Groups limit who may design with a connector, not who may run a model that uses it.
When the process runs#
When a token reaches a connector task, the engine:
- evaluates the inputs, as input parameters are evaluated for a service;
- builds the request: path parameters into the path (encoded), query and header parameters where the document
places them,
bodyor thebody.<field>inputs as JSON, and the authorization. The URL is always the connector's base URL and the operation's path: no input can change the host; - calls it, with a timeout, and retries
GET,HEAD,PUT,DELETEandOPTIONS(neverPOSTorPATCH) on a network error,429or5xx, waiting longer each time; - on a 2xx answer, sets
${output}and keeps the outputs in the data.
Another status (4xx, 5xx, or a 3xx: redirects are not followed) is a BPMN error with the code
HTTP_<status>, and the output is { status, error: <the body> }. A boundary error event with that error code
catches it:
<bpmn:error id="NotFound" name="Not found" errorCode="HTTP_404" />
...
<bpmn:boundaryEvent id="Missing" attachedToRef="GetRepo">
<bpmn:errorEventDefinition errorRef="NotFound" />
</bpmn:boundaryEvent>
Without one, the instance ends, as it does for a service's BPMN error. The run's decisions say which status raised which error.
No answer (the network, the timeout), or a connector or operation that is missing or disabled, is an
exception, as for a service that throws: the task's status is error with the reason, and Retry on the
instance's page calls it again (Throwing Exceptions). With Exceptions raise
a BPMN error checked on the task, it is a BPMN error instead: a boundary error event with no error catches it,
or one whose errorCode is the exception's code (ECONNREFUSED, ETIMEDOUT).
In demo mode (DEMO_MODE=true), connectors are not called: the task ends with no output, and the run's
decisions say so.
Checking models#
verifyModel and the editor's Problems tab check connector tasks:
| Code | Severity | |
|---|---|---|
connector-not-named |
error | no connector named, or not <connector>/<operation> |
connector-and-service |
error | the task names a service as well |
connector-unknown |
error | the server has no such connector |
connector-unreadable |
error | the connector's document cannot be read |
connector-operation-unknown |
error | the connector has no such operation |
connector-input-missing |
error | a required input, or a required request body, is not given |
connector-disabled |
warning | the connector is disabled: the task fails until it is enabled |
connector-operation-disabled |
warning | the operation is disabled |
connector-input-unknown |
warning | an input the operation does not have (it is not sent) |
The checks that need the connectors run with a server (the editor, api.model.verifyModel), not from the
command line. A model imported from elsewhere that names a connector this server does not have gets
connector-unknown: importing never adds a connector.
Settings#
| Setting | |
|---|---|
CONNECTORS_KEY (.env) |
The key that encrypts the connectors' keys. Required to give a connector a key. |
CONNECTORS_ALLOW_HOSTS (.env) |
A comma list of the hosts a connector may call (api.github.com,*.example.com). Unset: any. |
CONNECTOR_CATALOG_URL (.env) |
The catalog the Connectors page offers (a web address or a file). |
connectors.timeout (configuration) |
A call's timeout in ms, unless the connector sets its own. Default 30000. |
connectors.retries |
Retries of an idempotent call, unless the connector sets its own. Default 2. |
connectors.retryDelay |
The first wait before a retry in ms, doubled each time. Default 200. |
connectors.maxResponseBytes |
The largest answer read. Default 5 MB. |
Connectors are kept in the wf_connectors collection of the server's storage (MongoDB, SQLite or memory), and are
in the administration backup.
Example#
testSampleApp's model GitHub repository calls github/repos/get for an owner and a repo, keeps the
repository's description and starsCount, and ends at Not found on a 404. Add the connector from the console
(coa, id github, document connectors/openapi/github.json), then start the model with
owner bpmnServer repo bpmn-server.