Connector Template Guide

Goals

This guide will walk you through building a new connector Action / Event that will leverage the provided template below.

  • Using an existing connector’s Custom API Action (CAPIA) in conjunction with the provided template, that the developer will be able to replace placeholder variables in the template to quickly build a net-new action or event with low friction.
  • User should be able to copy-paste the given template as a new action/event, replace placeholder variables, and add minor data transformation logic to the post-processing function.
  • Produce action/events with low time to development (TTD).

Prerequisite

  • This assumes that the connector already has a fully functioning Custom API Action, with supporting functions complete and ready to develop against.

Instructions

Legend

  1. Add Action button (New Action)
  2. Action Parameters/Options
    • This is the ‘Options’ tab that is rendered in designer.
  3. Action Input Fields
  4. Action Output Fields
  5. Action module - Call Custom API Action
  6. Action module - post-processing function
  7. Functions section
    • This is where the helper functions exist. This function library is accessible by any action.
  8. Add Function button (New Function)
  9. Post-processing function
    • Example of a working post-process function.
    • Called by 6. - the action module that calls the post-processing function.
  10. Object Construct module/brick
    • Required. Must always be the last brick/module in the post processing function.
    • This is where most of the user-implemented logic will go. Must go before the final object.construct.
  11. Add new step button
    • Add a new brick/module to the post process function.

Forge Sidebar 1 Forge Sidebar 2

Walkthrough

Notes:

  • It is recommended that you approach building this connector by leveraging the separate template components, and add them incrementally to your new action. For example, first paste the entire Parameters template into the action’s params section by replacing all of the existing placeholder text for params in Forge.
  • Placeholder variable names: All template placeholder variables and values are indicated using the <VARIABLE NAME> structure.
    • Template placeholder variables indicated by <> characters, with capitalized naming conventions.
    • You will be required to replace all placeholder names with your own names.
    • Ensure that all like-named placeholder values are consistent throughout all of your connector code. For example, <INPUT FIELD HEADER NAME> exists in multiple sections. It will be required that the name is consistent across all occurrences.
  • The following steps will reference the above images and the legend.

Steps

  1. Create a brand new action in Forge for the desired connector.
    • Click the ‘+’ button next to Actions (1).
    • Give your action the desired Display Name.
    • Enter a description for this action. This will be visible in designer.
  2. Copy the Parameters template, and then click on the params section (2). Replace the boiler plate code with the template.
    • Replace all placeholder values with your own desired value.
  3. Copy the Input template, and then click on the input section (3). Replace the boiler plate code with the template.
    • Replace all placeholder values with your own desired value.
    • These will render your fields on the card in designer.
    • Ensure to use the API value for the name field. The displayname field can be anything you like.
  4. Copy the Output template, and then click on the output section (4). Replace the boiler plate code with the template.
    • Replace all placeholder values with your own desired value.
    • These will render your fields on the card in designer.
    • Ensure to use the API value for the name field. The displayname field can be anything you like.
  5. Copy the Core Module - Call Custom API Action template, and then click the ‘+Add new step’ button, just under ‘Core’ (7).
    • A pop-up window will appear. In the search bar, type ‘call’. Select the ‘Call FLO’ module from the Control section.
      • We will replace this module’s placeholder text, so you can choose any item from the list of modules if desired.
    • Paste the Call Custom API Action template and replace all of the existing placeholder text.
    • Replace placeholder variable names
      • This will require some knowledge of the service’s API. Consult the API docs for the service to determine how to structure your request.
      • <RELATIVE URL> - Replace with the relative URL of the API endpoint that you will be working with. Refer to the Custom API Action help docs for info about the required relative URL structure for that API.
      • <INPUT FIELD HEADER NAME> - This will be the same value that you entered for the Input template.
      • <REQUEST METHOD TYPE> - This will be one of GET, POST, PUT, PATCH, and DELETE.
    • This will become (5) in the first image above.
  6. Copy the Core Module - Post Process function template, and then click the ‘+Add new step’ button again (7).
    • Choose the Call FLO module again.
    • Paste the Post Process template and replace the existing placeholder text.
    • Replace <POST PROCESS FUNCTION NAME> with your desired name for the Post Process helper function. For example, this could be readRecordPostProcess or similar if you are creating an action to read a record.
      • You will not be able to save if you have not created a Function with this name yet.
    • This will become (6) in the first image above.
  7. Copy the Post Process function template.
    • Click the Function (8) tab, and then click the ‘+’ to the right of the Function tab (9) to create a new Function.
    • A modal window will pop up to prompt you to name the function. Enter the name that you gave it in the previous step for <POST PROCESS FUNCTION NAME>.
    • Paste the copied Post Process function template to replace the placeholder text.
      • Ensure that you do not overwrite your name or displayname for the function.
    • Replace placeholder variable names
      • <OUTPUT FIELD HEADER NAME> - this will be the same value that you used in your output template.
      • Replace the output field placeholders.
      • Ensure that the existing object.construct that is pre-populated in this template remains as the last module/brick in this function. This is required so that the action will return your output field values correctly.
    • All logic that will be added to this function will necessarily need to be added before the existing object.construct with the output fields. IMPORTANT
    • The final step is adding additional logic to transform the data that is coming from the response body and pass it to the defined output fields in the post process function. In some cases, you will not need to do any additional logic to map the fields if they are top level keys in the response. Another common case is map or filter over the response.
      • To add a new step above the object.construct step, hover over the object.construct module in the function on the left, and click on the three dot button that appears. Then click ‘Add step above` button.
      • Choose the required module/brick that is right for your use case. Many of the modules that you will find are similar to the Designer functions, so they should be familiar.
  8. Refer to an example of an action built using this template below.

Deployment

  1. Click the ‘Save’ button at the top left of the Forge toolbar.
    • Saving a connector will save a draft. This will be overwritten with subsequent saves, and the draft does not have any version control. Be careful when saving.
    • Wait for the ‘Connector successfully saved’ toast to appear, then you have saved successfully.
  2. Click the ‘Submit’ button at the top of the Forge toolbar.
    • Increment the version by 1. For example, if the connector is currently version 1.2.7, then increment the version to 1.2.8. Connector versioning uses basic semantic versioning rules.
    • Wait for the ‘Connector version submitted’ toast, then you have submitted successfully.
  3. Click on the ‘Control Panel’ tab at the top of Forge.
  4. Deploy your connector version that you have just submitted.
    • Production Forge - Deploy using the ‘Testing Version’. Choose the (Test) connector in designer.
    • Beta Forge - Deploy using the ‘Production Version’. Choose the standard connector (not Test) in beta Designer.
  5. Your updated connector should be available in designer.
    • If you do not see your connector or action, please wait up to 20 minutes and check again. It may take some time to see them appear in designer once they have been deployed.

Template and Examples

Template

Parameters

[
  {
    "<PARAMETER KEY NAME 1>": {
      "type": "string",
      "optional": true,
      "displayname": "<PARAMETER DISPLAYNAME 1>"
    }
  },
  {
    "<PARAMETER KEY NAME 2>": {
      "type": "option",
      "displayname": "<PARAMETER DISPLAYNAME 2>",
      "choices": [
        "<CHOICE VALUE 1>",
        "<CHOICE VALUE 2>",
        "<CHOICE VALUE 3>"
      ]
    }
  }
]

Inputs

{
  "extensible": false,
  "attributes": [
    {
      "name": "<INPUT FIELD HEADER NAME>",
      "attributes": [
        {
          "name": "<FIELD NAME 1>",
          "type": "string",
          "displayname": "<FIELD DISPLAYNAME 1>"
        },
        {
          "name": "<FIELD NAME 2>",
          "type": "object",
          "displayname": "<FIELD DISPLAYNAME 2>"
        },
        {
          "name": "<FIELD NAME 3>",
          "type": "object",
          "collection": true,
          "displayname": "<FIELD DISPLAYNAME 3>"
        },
        {
          "name": "<FIELD NAME 4>",
          "type": "number",
          "displayname": "<FIELD DISPLAYNAME 4>"
        },
        {
          "name": "<FIELD NAME 5>",
          "type": "boolean",
          "displayname": "<FIELD DISPLAYNAME 5>"
        }
      ]
    }
  ]
}

Outputs

{
  "extensible": false,
  "attributes": [
    {
      "name": "<OUTPUT FIELD HEADER NAME>",
      "attributes": [
        {
          "name": "<FIELD NAME 1>",
          "type": "string",
          "displayname": "<FIELD DISPLAYNAME 1>"
        },
        {
          "name": "<FIELD NAME 2>",
          "type": "object",
          "displayname": "<FIELD DISPLAYNAME 2>"
        },
        {
          "name": "<FIELD NAME 3>",
          "type": "object",
          "collection": true,
          "displayname": "<FIELD DISPLAYNAME 3>"
        },
        {
          "name": "<FIELD NAME 4>",
          "type": "number",
          "displayname": "<FIELD DISPLAYNAME 4>"
        },
        {
          "name": "<FIELD NAME 5>",
          "type": "boolean",
          "displayname": "<FIELD DISPLAYNAME 5>"
        }
      ]
    }
  ]
}

Core

Core Modules

  • Call Custom API Action

    {
    "brick": "control.spawn",
    "id": "callCustomAPIAction",
    "item": "",
    "inputs": {
    "flo": {
      "_type": "flo",
      "_array": false,
      "_value": "customAPIAction"
    },
    "input": {
      "Request": {
        "Relative URL": "<RELATIVE URL>",
        "Body": "{{input.<INPUT FIELD HEADER NAME>}}"
      }
    },
    "parameters": {
      "requestType": "<REQUEST METHOD TYPE>"
    }
    },
    "outputs": {
    "output": {
      "_type": "object",
      "_array": false
    }
    }
    }
  • Post Process

    {
    "brick": "control.spawn",
    "id": "callPostProcess",
    "item": "",
    "inputs": {
    "flo": {
      "_type": "flo",
      "_array": false,
      "_value": "<POST PROCESS FUNCTION NAME>"
    },
    "input": "{{callCustomAPIAction.output}}"
    },
    "outputs": {
    "output": {
      "_type": "object",
      "_array": false
    }
    }
    }

Metadata Function(s)

  • Post Process fucntion

    {
    "name": "<POST PROCESS FUNCTION NAME>",
    "description": "Post processing function for CAPIA output data transformation",
    "kind": "metadata",
    "zebricks": [
    {
      "brick": "object.construct",
      "id": "output",
      "inputs": {
        "<OUTPUT FIELD HEADER NAME>": {
          "<FIELD NAME 1>": "{{input.Response.Body.<FIELD NAME 1>}}",
          "<FIELD NAME 2>": "{{input.Response.Body.<FIELD NAME 2>}}",
          "<FIELD NAME 3>": "{{input.Response.Body.<FIELD NAME 3>}}",
          "<FIELD NAME 4>": "{{input.Response.Body.<FIELD NAME 4>}}",
          "<FIELD NAME 5>": "{{input.Response.Body.<FIELD NAME 5>}}"
        }
      },
      "outputs": {
        "output": {
          "_type": "object",
          "_array": false
        }
      }
    }
    ],
    "displayname": "<POST PROCESS FUNCTION NAME>"
    }

    Examples

    Example Action Modules

  • Parameters

    [
    {
    "requestType": {
      "type": "option",
      "displayname": "Request Type",
      "choices": [
        "GET",
        "POST",
        "PUT",
        "PATCH",
        "DELETE"
      ]
    }
    }
    ]

    Example rendering of parameters in designer:

params

  • Inputs

    {
    "extensible": false,
    "attributes": [
    {
      "name": "Fields",
      "attributes": [
        {
          "name": "name",
          "type": "string",
          "displayname": "Name"
        },
        {
          "name": "description",
          "type": "string",
          "displayname": "Description"
        },
        {
          "name": "campaignCode",
          "type": "string",
          "displayname": "Campaign Code"
        },
        {
          "name": "color",
          "type": "string",
          "displayname": "Color"
        },
        {
          "name": "favorite",
          "type": "boolean",
          "displayname": "Favorite"
        }
      ]
    }
    ]
    }
  • Outputs

    {
    "extensible": false,
    "attributes": [
    {
      "name": "New Record",
      "attributes": [
        {
          "name": "id",
          "type": "string",
          "displayname": "ID"
        },
        {
          "name": "name",
          "type": "string",
          "displayname": "Name"
        },
        {
          "name": "description",
          "type": "string",
          "displayname": "Description"
        },
        {
          "name": "campaignCode",
          "type": "string",
          "displayname": "Campaign Code"
        },
        {
          "name": "color",
          "type": "string",
          "displayname": "Color"
        },
        {
          "name": "favorite",
          "type": "boolean",
          "displayname": "Favorite"
        },
        {
          "name": "createdDate",
          "type": "string",
          "displayname": "Created Date"
        },
        {
          "name": "modifiedDate",
          "type": "string",
          "displayname": "Modified Date"
        }
      ]
    }
    ]
    }

    Example Input & Output fields in designer using the above I/O schemas:

io

  • #### Core json { "brick": "control.spawn", "id": "createCampaign", "item": "", "inputs": { "flo": { "_type": "flo", "_array": false, "_value": "customAPIAction" }, "input": { "Request": { "Relative URL": "/hub/v1/campaigns", "Body": "{{input.Fields}}" } }, "parameters": { "requestType": "POST" } }, "outputs": { "output": { "_type": "object", "_array": false } } }
{
  "brick": "control.spawn",
  "id": "postProcess",
  "item": "",
  "inputs": {
    "flo": {
      "_type": "flo",
      "_array": false,
      "_value": "createCampaignPostProcess"
    },
    "input": "{{createCampaign.output}}"
  },
  "outputs": {
    "output": {
      "_type": "object",
      "_array": false
    }
  }
}
  • #### Post-Process Function json { "name": "createCampaignPostProcess", "description": "Post processing function for create campaign", "kind": "metadata", "zebricks": [ { "brick": "object.construct", "id": "output", "inputs": { "New Record": { "id": "{{input.Response.Body.id}}", "name": "{{input.Response.Body.name}}", "description": "{{input.Response.Body.description}}", "campaignCode": "{{input.Response.Body.campaignCode}}", "color": "{{input.Response.Body.color}}", "favorite": "{{input.Response.Body.favorite}}", "createdDate": "{{input.Response.Body.createdDate}}", "modifiedDate": "{{input.Response.Body.modifiedDate}}" } }, "outputs": { "output": { "_type": "object", "_array": false } } } ], "displayname": "createCampaignPostProcess" }

Example Action (combined components)

Note: Metadata functions are called from the action, and are not explicitly a function of the action itself.

{
  "name": "createCampaign",
  "displayname": "Create Campaign",
  "description": "Create a Campaign in Salesforce Marketing Campaign.",
  "kind": "action",
  "params": [],
  "input": {
    "extensible": false,
    "attributes": [
      {
        "name": "Fields",
        "attributes": [
          {
            "name": "name",
            "type": "string",
            "displayname": "Name"
          },
          {
            "name": "description",
            "type": "string",
            "displayname": "Description"
          },
          {
            "name": "campaignCode",
            "type": "string",
            "displayname": "Campaign Code"
          },
          {
            "name": "color",
            "type": "string",
            "displayname": "Color"
          },
          {
            "name": "favorite",
            "type": "boolean",
            "displayname": "Favorite"
          }
        ]
      }
    ]
  },
  "output": {
    "extensible": false,
    "attributes": [
      {
        "name": "New Record",
        "attributes": [
          {
            "name": "id",
            "type": "string",
            "displayname": "ID"
          },
          {
            "name": "name",
            "type": "string",
            "displayname": "Name"
          },
          {
            "name": "description",
            "type": "string",
            "displayname": "Description"
          },
          {
            "name": "campaignCode",
            "type": "string",
            "displayname": "Campaign Code"
          },
          {
            "name": "color",
            "type": "string",
            "displayname": "Color"
          },
          {
            "name": "favorite",
            "type": "boolean",
            "displayname": "Favorite"
          },
          {
            "name": "createdDate",
            "type": "string",
            "displayname": "Created Date"
          },
          {
            "name": "modifiedDate",
            "type": "string",
            "displayname": "Modified Date"
          }
        ]
      }
    ]
  },
  "zebricks": [
    {
      "brick": "control.spawn",
      "id": "createCampaign",
      "item": "",
      "inputs": {
        "flo": {
          "_type": "flo",
          "_array": false,
          "_value": "customAPIAction"
        },
        "input": {
          "Request": {
            "Relative URL": "/hub/v1/campaigns",
            "Body": "{{input.Fields}}"
          }
        },
        "parameters": {
          "requestType": "POST"
        }
      },
      "outputs": {
        "output": {
          "_type": "object",
          "_array": false
        }
      }
    },
    {
      "brick": "control.spawn",
      "id": "postProcess",
      "item": "",
      "inputs": {
        "flo": {
          "_type": "flo",
          "_array": false,
          "_value": "createCampaignPostProcess"
        },
        "input": "{{createCampaign.output}}"
      },
      "outputs": {
        "output": {
          "_type": "object",
          "_array": false
        }
      }
    }
  ]
}