Skip to main content

Update 0.1 to 0.2

Intermediate

The following sections explain which adjustments must be made to migrate from Connector SDK 0.1.x to 0.2.0.

caution

Be aware that the update from 0.1 to 0.2 requires manual migration steps as described below.

Connector function​

With SDK version 0.2.0, we introduce the following structural changes:

  • Input validation and secret replacement move from writing imperative code to declaratively using annotations.
  • The Outbound aspect of APIs is more explicit. Classes have been moved to more explicit packages and have been renamed.
  • New required annotation for outbound Connectors.

Declarative validation and secrets​

Input objects previously had to implement the ConnectorInput interface to participate in validation and secret replacement initiated from the ConnectorContext using its validate and replaceSecrets methods respectively.

With version 0.2.0, we remove the imperative approach for validation and secret replacement from the SDK. Instead, you can use annotations to describe the constraints of input attributes and mark those that can contain secrets.

These are two input objects written with the SDK version 0.1.x:

import io.camunda.connector.api.ConnectorInput;
import io.camunda.connector.api.SecretStore;
import io.camunda.connector.api.Validator;

public class MyConnectorRequest implements ConnectorInput {

private String message;
private Authentication authentication;

@Override
public void validateWith(final Validator validator) {
validator.require(message, "message");
validator.require(authentication, "authentication");
validateIfNotNull(authentication, validator);
}

@Override
public void replaceSecrets(final SecretStore secretStore) {
replaceSecretsIfNotNull(authentication, secretStore);
}
}
import io.camunda.connector.api.ConnectorInput;
import io.camunda.connector.api.SecretStore;
import io.camunda.connector.api.Validator;

public class Authentication implements ConnectorInput {

private String user;
private String token;

@Override
public void validateWith(final Validator validator) {
validator.require(user, "user");
validator.require(token, "token");
if (token != null && !(token.startsWith("xobx") || token.startsWith("secrets."))) {
validator.addErrorMessage("Token must start with \"xobx\" or be a secret");
}
}

@Override
public void replaceSecrets(final SecretStore secretStore) {
token = secretStore.replaceSecret(token);
}
}

You can express the same input objects with SDK version 0.2.0 as follows:

import io.camunda.connector.api.annotation.Secret;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;

public class MyConnectorRequest {

@NotEmpty
private String message;

@NotNull
@Valid
@Secret
private Authentication authentication;
}
import io.camunda.connector.api.annotation.Secret;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Pattern;

public class Authentication {

@NotEmpty
private String user;

@NotEmpty
@Pattern("^(xobx-|secret).+")
@Secret
private String token;
}

As a result, you have to remove the ConnectorInput interface implementation and the imperative code that comes with validateWith and replaceSecrets. You can now concisely describe the constraints of attributes rather then expressing them in imperative code.

In order to use annoation-based validation out of the box, you can include the new artifact connector-validation that comes with the SDK.

<dependency>
<groupId>io.camunda.connector</groupId>
<artifactId>connector-validation</artifactId>
<version>0.2.0</version>
</dependency>

You can read more about validation and secret replacement in our SDK Guide.

Explicit Outbound aspect​

With version 0.2.0 of the SDK, we make the Outbound aspect of those components specific to oubound connectivity more visible. This separates those SDK components that are tightly coupled to Outbound from those that will be reusable for Inbound.

With this change, the names of the following classes need to be adjusted:

  • Rename io.camunda.connector.api.ConnectorContext to io.camunda.connector.api.outbound.OutboundConnectorContext
  • Rename io.camunda.connector.api.ConnectorFunction to io.camunda.connector.api.outbound.OutboundConnectorFunction
  • Rename io.camunda.connector.api.SecretProvider to io.camunda.connector.api.secret.SecretProvider
  • Rename io.camunda.connector.api.SecretStore to io.camunda.connector.api.secret.SecretStore
  • Rename io.camunda.connector.test.ConnectorContextBuilder to io.camunda.connector.test.outbound.OutboundConnectorContextBuilder

As a result, you must replace all occurrences of the old class names and imports with the new ones. This includes the SPI for the connector function itself. Therefore, rename the file META-INF/services/io.camunda.connector.api.ConnectorFunction to META-INF/services/io.camunda.connector.api.outbound.OutboundConnectorFunction.

@OutboundConnector annotation​

For best interoperability, Connectors provide default meta-data (name, type, inputVariables) via the @OutboundConnector annotation:

@OutboundConnector(
name = "PING",
inputVariables = {"caller"},
type = "io.camunda.example.PingConnector:1"
)
public class PingConnector implements OutboundConnectorFunction {
...
}

Connector runtime environment​

If using the pre-packaged runtime environment that comes with the SDK does not fit your use case, you can create a custom runtime environment.

With version 0.2.0 of the job worker runtime environment, you need to make the following changes:

  • Rename io.camunda.connector.runtime.jobworker.ConnectorJobHandler to io.camunda.connector.runtime.jobworker.api.outbound.ConnectorJobHandler
  • Rename connector related env variables from ZEEBE_ to CONNECTOR_. Zeebe configuration properties remain unchanged

As a general change in behavior the module will now pick up connectors from classpath unless it is explicitly configured via environment variables.

Also take the name changes in the SDK core into account.

Implementing your own Connector wrapper you need to provide a Connector context specific to your environment. Consider extending the io.camunda.connector.impl.outbound.AbstractConnectorContext instead of implementing the io.camunda.connector.api.ConnectorContext yourself. Most of the commonly needed functionality is already provided in there.