Writing an Integration in YAML with Trigger Payloads, Inputs, and Outputs

Overview

In this quickstart, we examine a sample integration written in YAML to showcase the ability to import integrations defined as code.

In addition to examining writing integrations as code, this quickstart covers:

  • Invoking an integration with a webhook that contains a payload body
  • Referencing the trigger payload, both as an input variable for a component and in a code component
  • Knitting inputs and outputs throughout an integration to create more maintainable code

Prior to reviewing this quickstart, we recommend you check out our article on Defining Integrations as Code.

"Incomplete TODO Items" Integration Source Code

If you would like to import this integration yourself, or reference it in your own editor, download incomplete-todo-items.yaml. You can then run:

prism integrations:import --path path/to/incomplete-todo-items.yaml

What the "Incomplete TODO Items" Integration Does

This integration is triggered with an ID for a fictitious user, and writes out a list of incomplete "TODO" items for that user to a file in AWS S3. The integration is comprised of six steps (seven if you include the trigger):

  1. The integration is triggered by a POST to a webhook URL. The POST includes a payload body that specifies a userId for the user we're concerned about.

    curl 'https://hooks.prismatic.io/trigger/INTEGRATION_ID' \
    --data '{"userId":5}' \
    --header "Content-Type: application/json" \
    --request POST
  2. Next, an HTTP GET step pulls https://jsonplaceholder.typicode.com/todos, which contains a list of about 200 TODO items of the form:

    [
    {
    "userId": 5,
    "id": 201,
    "title": "clean the car",
    "completed": false
    },
    ...
    ]
  3. After that a code component takes the userId that was passed in and generates a URL to pull from https://jsonplaceholder.typicode.com/users/userId:

  4. Next another HTTP GET component pulls down the URL that was generated and gets results that look like this:

    {
    "id": 5,
    "name": "Chelsey Dietrich",
    "username": "Kamren",
    ...
    }

    The user's name and username will be referenced as inputs for upcoming steps.

  5. The next step is a code component action. The code filters the TODO items from step #1 to only include incomplete tasks for the userId that was passed in, formatted as a set of strings like this:

    Chelsey Dietrich needs to clean the car.
    Chelsey Dietrich needs to pay the bills.
    ...
  6. Next, a code component generates an S3 object name to use, and an S3 component action writes those TODO strings to a file in S3.

  7. Finally, we use the AWS S3 component to post our TODO list to an S3 bucket.

Now that we have a sense of what the integration does, let's dive into the code.

Referencing Configuration Variables

Configuration variables are defined under the requiredConfigVars header.

requiredConfigVars:
awsRegion: us-east-1
s3BucketName: my-s3-bucket-name

Those configuration variables can be referenced as inputs of steps:

- name: Save TODO list to S3
description: Save the user's incomplete tasks a file in S3
action:
key: putObject
componentKey: aws-s3
inputs:
awsRegion:
type: configVar
value: awsRegion
bucket:
type: configVar
value: s3BucketName
fileContents:
type: reference
value: listItemsForUser.results
objectKey:
type: reference
value: generateS3ObjectName.results # Save to {BUCKET}/todoitems/{USERNAME}.txt

Trigger Output as Step Input

The trigger received userId as part of its webhook payload body. This ID was used to generate a url of the form https://jsonplaceholder.typicode.com/users/5 in the first code component:

- name: Generate User URL
description: Generate the URL where the user info is stored
action:
key: runCode
componentKey: code
inputs:
code:
type: value
value: |
module.exports = async (context, { todosTrigger }) => {
const userId = todosTrigger.results.body.data.userId;
return {
data: `https://jsonplaceholder.typicode.com/users/${userId}`;
}
};

Step Output in a Code Step

The userId output is also referenced in the third step, the code component, to filter TODO items only applicable to the specific user:

module.exports = async (
context,
{
todosTrigger,
getAllTodoItems: { results: items },
getUserInfo: {
results: { name },
},
}
) => {
const userId = todosTrigger.results.body.data.userId;
};
note

The getAlltodoItems output is a JSON list that we reassigned to a variable named items using JavaScript destructuring.

userId, items, and the user's name are then all used in the code component to filter TODO items, and generate sentences of the form "Chelsey Dietrich needs to clean the car."

const incompleteTasks = items
.filter((item) => item.userId == userId)
.filter((item) => !item.completed)
.map(({ title }) => `${name} needs to ${title}.`)
.join("\r\n");

Defining Output in a Code Step

The code component for the List items for user step generates output values that can be referenced. The return value of the code component's function reads:

return { data: incompleteTasks };

Subsequent steps can then reference listItemsForUser.results to access that list.

Step Output as Step Input

The last step utilizes the userUsername output from the getUserInfo step to declare where to save a file in S3, and the incompleteTasks output from the listItemsForUser code component to declare the content of the file to be saved.

- name: Save TODO list to S3
description: Save the user's incomplete tasks a file in S3
action:
key: putObject
componentKey: aws-s3
inputs:
awsRegion:
type: configVar
value: awsRegion
bucket:
type: configVar
value: s3BucketName
fileContents:
type: reference
value: listItemsForUser.results
objectKey:
type: reference
value: generateS3ObjectName.results # Save to {BUCKET}/todoitems/{USERNAME}.txt

Summary

Congratulations! Through this quickstart you built an integration in code, invoked the integration with a header that had a body payload, and knitted together trigger and step outputs and inputs. Next we recommend you try modifying the sample YAML file, or build a simple integration yourself from scratch!