Skip to content

Tutorial

This document is a guided walkthrough of using the Flexli Engine API to create a Connector and a Workflow that uses the actions defined in that connector. We will create a basic Slack incoming webhook connector and a workflow that sends a message to a channel.

Creating the Connector

Every connector starts off with a type, name, and description. The type is a string of letters without spaces that acts as a descriptive identifier for the connector. Note that this is not a unique identifier. The name and description can be long-form and are intended for users of your connectors.

The schema_version is required and must be set to 1.

As Flexli Engine adopts new features that are not backwards compatible they will be exposed through a new schema version that you will need to migrate to."

Connector Description
{
  "type": "SlackWebhook",
  "name": "Slack Incoming Webhook",
  "description": "A basic connector for sending messages to Slack Incoming Webhook URLs.",
  "schema_version": 1
}

Configuration

The config contains the host and base path that are used for all Actions that will be defined.

The host must be a fully qualified domain name without a scheme or path. HTTPS is enforced by the engine for all outbound connections. The base_path will be prepended to the path of every action defined in this connector. This base path value may be the API version (e.g. v1) or the API's path off the service host (e.g. api).

The base_path is an optional value. Many of the properties described in this walkthrough are. Refer to then API docs for a complete reference on required and optional properties.

The default_headers will also apply to every action, cutting down on the need to write repetitive definitions, but they may also be overridden in the action. A header of the same key name in an action will take precedence over the default.

This Slack webhook connector will be reusable across multiple webhooks. The common base path for all webhooks is services, and our requests must be JSON content.

Connector Configuration
{
  "config": {
    "host": "hooks.slack.com",
    "base_path": "services",
    "default_headers": {
      "Accept": "application/json",
      "Content-Type": "application/json"
    }
  }
}

What if?

What if you did not want this connector to be reusable, and instead only wanted it to be for a single channel? In that case the full path of the webhook could be hardcoded into the connector's configuration.

Engine users still use the connector when authoring, but if they only have permissions to reading the connector's actions and events they would not have access to the configuration data. These single-purpose connectors can be used to simplify the workflow authoring experience in your account."

Slack's webhook integration is unauthenticated and credentials are not needed as a part of the connector. For APIs that require authentication you will need to add a credentials object conforming to one of the supported types. See Authoring Connectors: Credentials for more details.

Adding an Action

A Slack webhook only allows for posting messages. This will be the only action included in our connector.

Actions are a description of an API operation. They are very similar in nature to OpenAPI's schema but without the hierarchical structure.

Like the connector, the action must have a type value that workflow authors will use to identify which actions they are using. For posting a message to a Slack channel only the method, path, and body properties need to be set for the action (remember, the default_headers are already setting the content type to JSON).

The Slack documentation shows the minimum requirement for a message is a JSON object with a single text key. This action is constructing that object as a part of the body so workflow authors only have to pass a string of text when they use it.

The path and inner text properties are both dynamically populated by inputs which are defined in the parameters. You can see they are using Expressions to make these references.

The parameters object uses JSON schema to create the workflow author's interface to this action. The webhook must be a string limited to 44 characters, and the text must also be a string with a limit of 2000 characters (conforming to Slack's API).

The schema defines the user interface when using connector actions. Users know exactly what data is required, what is optional, what types are allowed, and what their limitations are. The Workflows API enforces action schemas and will return detailed error messages to users.

A well-defined action schema results in a better user experience.

{
  "actions": [
    {
      "type": "PostMessage",
      "method": "post",
      "path": "::webhook",
      "body": {
        "text": "::text"
      },
      "parameters": {
        "properties": {
          "webhook": {
            "title": "Webhook Path",
            "type": "string",
            "maxLength": 44
          },
          "text": {
            "title": "Message Text",
            "maxLength": 2000,
            "type": "string"
          }
        },
        "required": [
          "webhook",
          "text"
        ]
      }
    }
  ]
}

When this action is used in a workflow, the values that the author sets for webhook and text will be passed into the path and body. Workflow authors do not see any of the implementation details beyond parameters. Connector actions can be as simple or complex as is required for the operation they expose.

Create the Connector

The JSON definition of this connector will be passed to the Create a Connector API. A success response will include the unique ID of the connector that will be used in workflows.

Connector Created Response
{
  "id": "01HP21BX1MCA5T8EDBGBZ3JTSR",
  "href": "/v1/connectors/01HP21BX1MCA5T8EDBGBZ3JTSR"
}

A connector definition should be reusable within the same account as many times as needed. While multiple instances will share the same type they will all have different IDs.

View the complete Slack Incoming Webhook Connector
{
  "type": "SlackWebhook",
  "name": "Slack Incoming Webhook",
  "description": "A basic connector for sending messages to Slack Incoming Webhook URLs.",
  "schema_version": 1,
  "config": {
    "host": "hooks.slack.com",
    "base_path": "services",
    "default_headers": {
      "Accept": "application/json",
      "Content-Type": "application/json"
    }
  },
  "actions": [
    {
      "type": "PostMessage",
      "method": "post",
      "path": "::webhook",
      "body": {
        "text": "::text"
      },
      "parameters": {
        "properties": {
          "webhook": {
            "title": "Webhook Path",
            "type": "string",
            "maxLength": 44
          },
          "text": {
            "title": "Message Text",
            "maxLength": 2000,
            "type": "string"
          }
        },
        "required": [
          "webhook",
          "text"
        ]
      }
    }
  ]
}

Creating the Workflow

Now that we have a connector we can use its actions within a workflow.

Workflows can be described with their name and an optional description similar to connectors. These values can be long-form and are intended for operators.

The schema_version is required and must be set to 1.

As Flexli Engine adopts new features that are not backwards compatible they will be exposed through a new schema version that you will need to migrate to."

{
  "name": "Hello Slack",
  "description": "A \"hello world\" example workflow.",
  "schema_version": 1
}

Using an Action

Workflows must contain at least 1 action (but con contain up to 100). Each action is defined as an object within the actions array.

The connector_id will be the ID value of the connector this action references. Then the type states which action in that connector will be used.

Note that the connector's type value is not used here. It will be inferred on creation when the Workflows API validates the definition.

The order is a numeric value that determines the sequence that actions in the workflow are executed. This value can be any integer, and while the values across all your actions must be unique they do not need to be contiguous. You could have three actions defined and their orders are 10, 20, and 30 respectively.

{
  "actions": [
    {
      "connector_id": "<ConnectorId>",
      "type": "PostMessage",
      "order": 1,
      "parameters": {
        "webhook": "T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX",
        "text": "Hello from Flexli!"
      }
    }
  ]
}

The pqrameters are determined entirely by the schema of the connector action's definition. Remember in our example Slack connector the PostMessage action requires two parameters: a webhook string limited to 44 characters, and a text string limited to 2000 characters. If the parameters here do not pass validation by the Workflows API it will be rejected.

View the complete Hello Slack Workflow
{
  "name": "Hello Slack",
  "description": "A \"hello world\" example workflow.",
  "schema_version": 1,
  "actions": [
    {
      "connector_id": "<ConnectorId>",
      "type": "PostMessage",
      "order": 1,
      "parameters": {
        "webhook": "T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX",
        "text": "Hello from Flexli!"
      }
    }
  ]
}

Create the Workflow

The JSON definition of this connector will be passed to the Create a Workflow API. A success response will include the unique ID of the workflow that can be used to run it with the Run API (and other methods as well!).

Workflow Created Response
{
  "id": "01HP22FG2C15KF3EKB92VH8WFQ",
  "href": "/v1/workflows/01HP22FG2C15KF3EKB92VH8WFQ"
}