Merge pull request #703 from automatisch/docs/build-integrations
Docs/build integrations
This commit is contained in:
@@ -189,6 +189,26 @@ export default defineConfig({
|
||||
text: 'App',
|
||||
link: '/build-integrations/app',
|
||||
},
|
||||
{
|
||||
text: 'Global variable',
|
||||
link: '/build-integrations/global-variable',
|
||||
},
|
||||
{
|
||||
text: 'Auth',
|
||||
link: '/build-integrations/auth',
|
||||
},
|
||||
{
|
||||
text: 'Triggers',
|
||||
link: '/build-integrations/triggers',
|
||||
},
|
||||
{
|
||||
text: 'Actions',
|
||||
link: '/build-integrations/actions',
|
||||
},
|
||||
{
|
||||
text: 'Examples',
|
||||
link: '/build-integrations/examples',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
127
packages/docs/pages/build-integrations/actions.md
Normal file
127
packages/docs/pages/build-integrations/actions.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# Actions
|
||||
|
||||
:::info
|
||||
|
||||
The build integrations section is best understood when read from beginning to end. To get the most value out of it, start from the first page and read through page by page.
|
||||
|
||||
1. [Folder structure](/build-integrations/folder-structure)
|
||||
2. [App](/build-integrations/app)
|
||||
3. [Global variable](/build-integrations/global-variable)
|
||||
4. [Auth](/build-integrations/auth)
|
||||
5. [Triggers](/build-integrations/triggers)
|
||||
6. [<mark>Actions</mark>](/build-integrations/actions)
|
||||
7. [Examples](/build-integrations/examples)
|
||||
|
||||
:::
|
||||
|
||||
## Add actions to the app.
|
||||
|
||||
Open the `thecatapi/index.ts` file and add the highlighted lines for actions.
|
||||
|
||||
```typescript{4,17}
|
||||
import defineApp from '../../helpers/define-app';
|
||||
import auth from './auth';
|
||||
import triggers from './triggers';
|
||||
import actions from './actions';
|
||||
|
||||
export default defineApp({
|
||||
name: 'The cat API',
|
||||
key: 'thecatapi',
|
||||
iconUrl: '{BASE_URL}/apps/thecatapi/assets/favicon.svg',
|
||||
authDocUrl: 'https://automatisch.io/docs/apps/thecatapi/connection',
|
||||
supportsConnections: true,
|
||||
baseUrl: 'https://thecatapi.com',
|
||||
apiBaseUrl: 'https://api.thecatapi.com',
|
||||
primaryColor: '000000',
|
||||
auth,
|
||||
triggers
|
||||
actions
|
||||
});
|
||||
```
|
||||
|
||||
## Define actions
|
||||
|
||||
Create the `actions/index.ts` file inside of the `thecatapi` folder.
|
||||
|
||||
```typescript
|
||||
import mark-cat-image-as-favorite from './mark-cat-image-as-favorite';
|
||||
|
||||
export default [markCatImageAsFavorite];
|
||||
```
|
||||
|
||||
:::tip
|
||||
If you add new actions, you need to add them to the actions/index.ts file and export all actions as an array.
|
||||
:::
|
||||
|
||||
## Add metadata
|
||||
|
||||
Create the `actions/mark-cat-image-as-favorite.ts` file inside the `thecatapi` folder.
|
||||
|
||||
```typescript
|
||||
import defineAction from '../../../../helpers/define-action';
|
||||
|
||||
export default defineAction({
|
||||
name: 'Mark the cat image as favorite',
|
||||
key: 'markCatImageAsFavorite',
|
||||
description: 'Marks the cat image as favorite.',
|
||||
arguments: [
|
||||
{
|
||||
label: 'Image ID',
|
||||
key: 'imageId',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
description: 'The ID of the cat image you want to mark as favorite.',
|
||||
variables: true,
|
||||
},
|
||||
],
|
||||
|
||||
async run($) {
|
||||
// TODO: Implement action!
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Let's briefly explain what we defined here.
|
||||
|
||||
- `name`: The name of the action.
|
||||
- `key`: The key of the action. This is used to identify the action in Automatisch.
|
||||
- `description`: The description of the action.
|
||||
- `arguments`: The arguments of the action. These are the values that the user provides when using the action.
|
||||
- `run`: The function that is executed when the action is executed.
|
||||
|
||||
## Implement the action
|
||||
|
||||
Open the `actions/mark-cat-image-as-favorite.ts` file and add the highlighted lines.
|
||||
|
||||
```typescript{7-20}
|
||||
import defineAction from '../../../../helpers/define-action';
|
||||
|
||||
export default defineAction({
|
||||
// ...
|
||||
|
||||
async run($) {
|
||||
const requestPath = `/v1/favorites`;
|
||||
const imageId = $.step.parameters.imageId;
|
||||
|
||||
const headers = {
|
||||
'x-api-key': $.auth.data.apiKey,
|
||||
};
|
||||
|
||||
const response = await $.http.post(
|
||||
requestPath,
|
||||
{ image_id: imageId },
|
||||
{ headers }
|
||||
);
|
||||
|
||||
$.setActionItem({ raw: response.data });
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
In this action, we send a request to the cat API to mark the cat image as favorite. We used the `$.http.post` method to send the request. The request body contains the image ID as it's required by the API.
|
||||
|
||||
`$.setActionItem` is used to set the result of the action, so we set the response data as the action item. This is used to display the result of the action in the Automatisch UI and can be used in the next steps of the workflow.
|
||||
|
||||
## Test the action
|
||||
|
||||
Go to the flows page of Automatisch and create a new flow. Add the `Search cat images` as a trigger in the flow. Add the `Mark the cat image as favorite` action to the flow as a second step. Add one of the image IDs you got from the cat API as `Image ID` argument to the action. Click `Test & Continue` button. If you a see JSON response in the user interface, it means that both the trigger and the action we built are working properly.
|
@@ -1,5 +1,19 @@
|
||||
# App
|
||||
|
||||
:::info
|
||||
|
||||
The build integrations section is best understood when read from beginning to end. To get the most value out of it, start from the first page and read through page by page.
|
||||
|
||||
1. [Folder structure](/build-integrations/folder-structure)
|
||||
2. [<mark>App</mark>](/build-integrations/app)
|
||||
3. [Global variable](/build-integrations/global-variable)
|
||||
4. [Auth](/build-integrations/auth)
|
||||
5. [Triggers](/build-integrations/triggers)
|
||||
6. [Actions](/build-integrations/actions)
|
||||
7. [Examples](/build-integrations/examples)
|
||||
|
||||
:::
|
||||
|
||||
Let's start building our first app by using [TheCatApi](https://thecatapi.com/) service. It's a service that provides cat images and allows you to vote or favorite a specific cat image. It's an excellent example to demonstrate how Automatisch works with an API that has authentication and data fetching with pagination.
|
||||
|
||||
We will build an app with the `Search cat images` trigger and `Mark the cat image as favorite` action. So we will learn how to build both triggers and actions.
|
||||
@@ -48,7 +62,7 @@ export default defineApp({
|
||||
|
||||
## Create the favicon
|
||||
|
||||
Even though we have defined the `iconUrl` inside the app definition, we still need to create the icon file. Let's create the `assets` folder inside the `thecatapi` folder and save [this SVG file](/example-app/cat.svg) as `favicon.svg` inside of the `assets` folder. After saving the file, you can go to the `My Apps` page on Automatisch and click on `Add connection` button, and then you will see `The cat API` service with the icon.
|
||||
Even though we have defined the `iconUrl` inside the app definition, we still need to create the icon file. Let's create the `assets` folder inside the `thecatapi` folder and save [this SVG file](../public/example-app/cat.svg) as `favicon.svg` inside of the `assets` folder. After saving the file, you can go to the `My Apps` page on Automatisch and click on `Add connection` button, and then you will see `The cat API` service with the icon.
|
||||
|
||||
:::tip
|
||||
If you're looking for SVG icons for third-party services, you can use the following repositories.
|
||||
|
195
packages/docs/pages/build-integrations/auth.md
Normal file
195
packages/docs/pages/build-integrations/auth.md
Normal file
@@ -0,0 +1,195 @@
|
||||
# Auth
|
||||
|
||||
:::info
|
||||
|
||||
The build integrations section is best understood when read from beginning to end. To get the most value out of it, start from the first page and read through page by page.
|
||||
|
||||
1. [Folder structure](/build-integrations/folder-structure)
|
||||
2. [App](/build-integrations/app)
|
||||
3. [Global variable](/build-integrations/global-variable)
|
||||
4. [<mark>Auth</mark>](/build-integrations/auth)
|
||||
5. [Triggers](/build-integrations/triggers)
|
||||
6. [Actions](/build-integrations/actions)
|
||||
7. [Examples](/build-integrations/examples)
|
||||
|
||||
:::
|
||||
|
||||
## Sign up for the cat API
|
||||
|
||||
Go to the [sign up page](https://thecatapi.com/signup) of the cat API and register your account. It allows you to have 10k requests per month with a free account. You will get an API key by email after the registration. We will use this API key for authentication later on.
|
||||
|
||||
## The cat API docs
|
||||
|
||||
You can find detailed documentation of the cat API [here](https://docs.thecatapi.com). You need to revisit this page while building the integration.
|
||||
|
||||
## Add auth to the app
|
||||
|
||||
Open the `thecatapi/index.ts` file and add the highlighted lines for authentication.
|
||||
|
||||
```typescript{2,13}
|
||||
import defineApp from '../../helpers/define-app';
|
||||
import auth from './auth';
|
||||
|
||||
export default defineApp({
|
||||
name: 'The cat API',
|
||||
key: 'thecatapi',
|
||||
iconUrl: '{BASE_URL}/apps/thecatapi/assets/favicon.svg',
|
||||
authDocUrl: 'https://automatisch.io/docs/apps/thecatapi/connection',
|
||||
supportsConnections: true,
|
||||
baseUrl: 'https://thecatapi.com',
|
||||
apiBaseUrl: 'https://api.thecatapi.com',
|
||||
primaryColor: '000000',
|
||||
auth,
|
||||
});
|
||||
```
|
||||
|
||||
## Define auth fields
|
||||
|
||||
Let's create the `auth/index.ts` file inside of the `thecatapi` folder.
|
||||
|
||||
```bash
|
||||
touch auth/index.ts
|
||||
```
|
||||
|
||||
Then let's start with defining fields the auth inside of the `auth/index.ts` file as follows:
|
||||
|
||||
```typescript
|
||||
export default {
|
||||
fields: [
|
||||
{
|
||||
key: 'screenName',
|
||||
label: 'Screen Name',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
readOnly: false,
|
||||
value: null,
|
||||
placeholder: null,
|
||||
description:
|
||||
'Screen name of your connection to be used on Automatisch UI.',
|
||||
clickToCopy: false,
|
||||
},
|
||||
{
|
||||
key: 'apiKey',
|
||||
label: 'API Key',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
readOnly: false,
|
||||
value: null,
|
||||
placeholder: null,
|
||||
description: 'API key of the cat API service.',
|
||||
clickToCopy: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
We have defined two fields for the auth.
|
||||
|
||||
- The `apiKey` field will be used to authenticate the requests to the cat API.
|
||||
- The `screenName` field will be used to identify the connection on the Automatisch UI.
|
||||
|
||||
:::warning
|
||||
You have to add a screen name field in case there is no API endpoint where you can get the username or any other information about the user that you can use as a screen name. Some of the APIs have an endpoint for this purpose like `/me` or `/users/me`, but in our example, the cat API doesn't have such an endpoint.
|
||||
:::
|
||||
|
||||
## Verify credentials
|
||||
|
||||
So until now, we integrated auth folder with the app definition and defined the auth fields. Now we need to verify the credentials that the user entered. We will do that by defining the `verifyCredentials` method.
|
||||
|
||||
Start with adding the `verifyCredentials` method to the `auth/index.ts` file.
|
||||
|
||||
```typescript{1,8}
|
||||
import verifyCredentials from './verify-credentials';
|
||||
|
||||
export default {
|
||||
fields: [
|
||||
// ...
|
||||
],
|
||||
|
||||
verifyCredentials,
|
||||
};
|
||||
```
|
||||
|
||||
Let's create the `verify-credentials.ts` file inside the `auth` folder.
|
||||
|
||||
```typescript
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
|
||||
const verifyCredentials = async ($: IGlobalVariable) => {
|
||||
// TODO: Implement verification of the credentials
|
||||
};
|
||||
|
||||
export default verifyCredentials;
|
||||
```
|
||||
|
||||
We generally use the `users/me` endpoint or any other endpoint that we can validate the API key or any other credentials that the user provides. For our example, we don't have a specific API endpoint to check whether the credentials are correct or not. So we will randomly pick one of the API endpoints, which will be the `GET /v1/images/search` endpoint. We will send a request to this endpoint with the API key. If the API key is correct, we will get a response from the API. If the API key is incorrect, we will get an error response from the API.
|
||||
|
||||
Let's implement the authentication logic that we mentioned above in the `verify-credentials.ts` file.
|
||||
|
||||
```typescript
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
|
||||
const verifyCredentials = async ($: IGlobalVariable) => {
|
||||
await $.http.get('/v1/images/search');
|
||||
|
||||
await $.auth.set({
|
||||
screenName: $.auth.data.screenName,
|
||||
});
|
||||
};
|
||||
|
||||
export default verifyCredentials;
|
||||
```
|
||||
|
||||
Here we send a request to the `/v1/images/search` endpoint with the API key. If we get a response from the API, we will set the screen name to the auth data. If we get an error response from the API, it will throw an error.
|
||||
|
||||
:::warning
|
||||
You must always provide a `screenName` field to auth data in the `verifyCredentials` method. Otherwise, the connection will not have a name and it will not function properly in the user interface.
|
||||
:::
|
||||
|
||||
## Is still verified?
|
||||
|
||||
We have implemented the `verifyCredentials` method. Now we need to check whether the credentials are still valid or not for the test connection functionality in Automatisch. We will do that by defining the `isStillVerified` method.
|
||||
|
||||
Start with adding the `isStillVerified` method to the `auth/index.ts` file.
|
||||
|
||||
```typescript{2,10}
|
||||
import verifyCredentials from './verify-credentials';
|
||||
import isStillVerified from './is-still-verified';
|
||||
|
||||
export default {
|
||||
fields: [
|
||||
// ...
|
||||
],
|
||||
|
||||
verifyCredentials,
|
||||
isStillVerified,
|
||||
};
|
||||
```
|
||||
|
||||
Let's create the `is-still-verified.ts` file inside the `auth` folder.
|
||||
|
||||
```typescript
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
import verifyCredentials from './verify-credentials';
|
||||
|
||||
const isStillVerified = async ($: IGlobalVariable) => {
|
||||
await verifyCredentials($);
|
||||
return true;
|
||||
};
|
||||
|
||||
export default isStillVerified;
|
||||
```
|
||||
|
||||
:::info
|
||||
`isStillVerified` method needs to return the `truthy` value if the credentials are still valid.
|
||||
:::
|
||||
|
||||
We will use the `verifyCredentials` method to check whether the credentials are still valid or not. If the credentials are still valid, we will return `true`. Otherwise, it will throw an error which will automatically be handled by Automatisch.
|
||||
|
||||
:::warning
|
||||
You might be wondering why we need to have two separate functions even though we use only one of them behind the scenes in this scenario. That might be true in our example or any other APIs similar to the cat API but there are some other third-party APIs that we can't use the same functionality directly to check whether the credentials are still valid or not. So we need to have two separate functions for verifying the credentials and checking whether the credentials are still valid or not.
|
||||
:::
|
||||
|
||||
Now we have completed the authentication of the cat API. Go to the `My Apps` page in Automatisch, try to add a new connection, select `The Cat API` and use the `API Key` you got with an email. Then you can also check the test connection and reconnect functionality there.
|
||||
|
||||
Let's move on to the next page to build a trigger.
|
61
packages/docs/pages/build-integrations/examples.md
Normal file
61
packages/docs/pages/build-integrations/examples.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# Examples
|
||||
|
||||
:::info
|
||||
|
||||
The build integrations section is best understood when read from beginning to end. To get the most value out of it, start from the first page and read through page by page.
|
||||
|
||||
1. [Folder structure](/build-integrations/folder-structure)
|
||||
2. [App](/build-integrations/app)
|
||||
3. [Global variable](/build-integrations/global-variable)
|
||||
4. [Auth](/build-integrations/auth)
|
||||
5. [Triggers](/build-integrations/triggers)
|
||||
6. [Actions](/build-integrations/actions)
|
||||
7. [<mark>Examples</mark>](/build-integrations/examples)
|
||||
|
||||
:::
|
||||
|
||||
## Authentication
|
||||
|
||||
### 3-legged OAuth
|
||||
|
||||
- [Discord](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/discord/auth/index.ts)
|
||||
- [Flickr](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/flickr/auth/index.ts)
|
||||
- [Github](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/github/auth/index.ts)
|
||||
- [Salesforce](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/salesforce/auth/index.ts)
|
||||
- [Slack](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/slack/auth/index.ts)
|
||||
- [Twitter](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/twitter/auth/index.ts)
|
||||
|
||||
### API key
|
||||
|
||||
- [DeepL](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/deepl/auth/index.ts)
|
||||
- [Twilio](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/twilio/auth/index.ts)
|
||||
- [SMTP](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/smtp/auth/index.ts)
|
||||
|
||||
### Without authentication
|
||||
|
||||
- [RSS](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/rss/index.ts)
|
||||
- [Scheduler](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/scheduler/index.ts)
|
||||
|
||||
## Triggers
|
||||
|
||||
### Pagination with descending order
|
||||
|
||||
- [Search tweets - Twitter](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/twitter/triggers/search-tweets/index.ts)
|
||||
- [New issues - Github](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/github/triggers/new-issues/index.ts)
|
||||
- [Receive SMS - Twilio](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/twilio/triggers/receive-sms/index.ts)
|
||||
- [New photos - Flickr](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/flickr/triggers/new-photos/index.ts)
|
||||
|
||||
### Pagination with ascending order
|
||||
|
||||
- [New stargazers - Github](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/github/triggers/new-stargazers/index.ts)
|
||||
- [New watchers - Github](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/github/triggers/new-watchers/index.ts)
|
||||
|
||||
## Actions
|
||||
|
||||
- [Send a message to channel - Slack](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/slack/actions/send-a-message-to-channel/index.ts)
|
||||
- [Send SMS - Twilio](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/twilio/actions/send-sms/index.ts)
|
||||
- [Send a message to channel - Discord](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/discord/actions/send-message-to-channel/index.ts)
|
||||
- [Create issue - Github](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/github/actions/create-issue/index.ts)
|
||||
- [Send an email - SMTP](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/smtp/actions/send-email/index.ts)
|
||||
- [Create tweet - Twitter](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/twitter/actions/create-tweet/index.ts)
|
||||
- [Translate text - DeepL](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/deepl/actions/translate-text/index.ts)
|
@@ -1,5 +1,27 @@
|
||||
# Folder Structure
|
||||
|
||||
:::info
|
||||
|
||||
The build integrations section is best understood when read from beginning to end. To get the most value out of it, start from the first page and read through page by page.
|
||||
|
||||
1. [<mark>Folder structure</mark>](/build-integrations/folder-structure)
|
||||
2. [App](/build-integrations/app)
|
||||
3. [Global variable](/build-integrations/global-variable)
|
||||
4. [Auth](/build-integrations/auth)
|
||||
5. [Triggers](/build-integrations/triggers)
|
||||
6. [Actions](/build-integrations/actions)
|
||||
7. [Examples](/build-integrations/examples)
|
||||
|
||||
:::
|
||||
|
||||
:::warning
|
||||
If you still need to set up the development environment, please go back to the [development setup](/contributing/development-setup) page and follow the instructions.
|
||||
:::
|
||||
|
||||
:::tip
|
||||
We will use the terms **integration** and **app** interchangeably in the documentation.
|
||||
:::
|
||||
|
||||
Before diving into how to build an integration for Automatisch, it's better to check the folder structure of the apps and give you some idea about how we place different parts of the app.
|
||||
|
||||
## Folder structure of an app
|
||||
@@ -35,7 +57,7 @@ As mentioned above, actions are the steps we place after a trigger. Actions are
|
||||
|
||||
## Common
|
||||
|
||||
Common folder is a place where you can put utilities or shared functionality used by other folders like triggers, actions, auth, etc.
|
||||
The common folder is where you can put utilities or shared functionality used by other folders like triggers, actions, auth, etc.
|
||||
|
||||
## Data
|
||||
|
||||
|
96
packages/docs/pages/build-integrations/global-variable.md
Normal file
96
packages/docs/pages/build-integrations/global-variable.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# Global Variable
|
||||
|
||||
:::info
|
||||
|
||||
The build integrations section is best understood when read from beginning to end. To get the most value out of it, start from the first page and read through page by page.
|
||||
|
||||
1. [Folder structure](/build-integrations/folder-structure)
|
||||
2. [App](/build-integrations/app)
|
||||
3. [<mark>Global variable</mark>](/build-integrations/global-variable)
|
||||
4. [Auth](/build-integrations/auth)
|
||||
5. [Triggers](/build-integrations/triggers)
|
||||
6. [Actions](/build-integrations/actions)
|
||||
7. [Examples](/build-integrations/examples)
|
||||
|
||||
:::
|
||||
|
||||
Before handling authentication and building a trigger and an action, it's better to explain the `global variable` concept in Automatisch. Automatisch provides you the global variable that you need to use with authentication, triggers, actions, and basically all the stuff you will build for the integration.
|
||||
|
||||
The global variable is represented as `$` variable in the codebase, and it's a JSON object that contains the following properties:
|
||||
|
||||
## $.auth.set
|
||||
|
||||
```typescript
|
||||
await $.auth.set({
|
||||
key: 'value',
|
||||
});
|
||||
```
|
||||
|
||||
It's used to set the authentication data, and you can use this method with multiple pairs. The data will be stored in the database and can be retrieved later by using `$.auth.data` property. The data you set with this method will not override its current value but expands it. We use this method when we store the credentials of the third-party service. Note that Automatisch encrypts the data before storing it in the database.
|
||||
|
||||
## $.auth.data
|
||||
|
||||
```typescript
|
||||
$.auth.data; // { key: 'value' }
|
||||
```
|
||||
|
||||
It's used to retrieve the authentication data that we set with `$.auth.set()`. The data will be retrieved from the database. We use the data property with the key name when we need to get one specific value from the data object.
|
||||
|
||||
## $.app.baseUrl
|
||||
|
||||
```typescript
|
||||
$.app.baseUrl; // https://thecatapi.com
|
||||
```
|
||||
|
||||
It's used to retrieve the base URL of the app that we defined previously. In our example, it returns `https://thecatapi.com`. We use this property when we need to use the base URL of the third-party service.
|
||||
|
||||
## $.app.apiBaseUrl
|
||||
|
||||
```typescript
|
||||
$.app.apiBaseUrl; // https://api.thecatapi.com
|
||||
```
|
||||
|
||||
It's used to retrieve the API base URL of the app that we defined previously. In our example, it returns `https://api.thecatapi.com`. We use this property when we need to use the API base URL of the third-party service.
|
||||
|
||||
## $.http
|
||||
|
||||
It's an HTTP client to be used for making HTTP requests. It's a wrapper around the [axios](https://axios-http.com) library. We use this property when we need to make HTTP requests to the third-party service. The `apiBaseUrl` field we set up in the app will be used as the base URL for the HTTP requests. For example, to search the cat images, we can use the following code:
|
||||
|
||||
```typescript
|
||||
await $.http.get('/v1/images/search?order=DESC', {
|
||||
headers: {
|
||||
'x-api-key': $.auth.data.apiKey,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## $.step.parameters
|
||||
|
||||
```typescript
|
||||
$.step.parameters; // { key: 'value' }
|
||||
```
|
||||
|
||||
It refers to the parameters that are set by users in the UI. We use this property when we need to get the parameters for corresponding triggers and actions. For example [Send a message to channel](https://github.com/automatisch/automatisch/blob/main/packages/backend/src/apps/slack/actions/send-a-message-to-channel/post-message.ts) action from Slack integration, we have a step parameter called `message` that we need to use in the action. We can use `$.step.parameters.message` to get the value of the message to send a message to the Slack channel.
|
||||
|
||||
## $.pushTriggerItem
|
||||
|
||||
```typescript
|
||||
$.pushTriggerItem({
|
||||
raw: resourceData,
|
||||
meta: {
|
||||
id: resourceData.id,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
It's used to push trigger data to be processed by Automatisch. It must reflect the data that we get from the third-party service. Let's say for search tweets trigger the `resourceData` will be the JSON that represents the single tweet object.
|
||||
|
||||
## $.setActionItem
|
||||
|
||||
```typescript
|
||||
$.setActionItem({
|
||||
raw: resourceData,
|
||||
});
|
||||
```
|
||||
|
||||
It's used to set the action data to be processed by Automatisch. For actions, it reflects the response data that we get from the third-party service. Let's say for create tweet action it will be the JSON that represents the response payload we get while creating a tweet.
|
157
packages/docs/pages/build-integrations/triggers.md
Normal file
157
packages/docs/pages/build-integrations/triggers.md
Normal file
@@ -0,0 +1,157 @@
|
||||
# Triggers
|
||||
|
||||
:::info
|
||||
|
||||
The build integrations section is best understood when read from beginning to end. To get the most value out of it, start from the first page and read through page by page.
|
||||
|
||||
1. [Folder structure](/build-integrations/folder-structure)
|
||||
2. [App](/build-integrations/app)
|
||||
3. [Global variable](/build-integrations/global-variable)
|
||||
4. [Auth](/build-integrations/auth)
|
||||
5. [<mark>Triggers</mark>](/build-integrations/triggers)
|
||||
6. [Actions](/build-integrations/actions)
|
||||
7. [Examples](/build-integrations/examples)
|
||||
|
||||
:::
|
||||
|
||||
:::warning
|
||||
For HTTP-based triggers, Automatisch currently supports only polling. Webhook-based triggers are not supported at the moment, but we are planning to add them in the future.
|
||||
:::
|
||||
|
||||
## Add triggers to the app
|
||||
|
||||
Open the `thecatapi/index.ts` file and add the highlighted lines for triggers.
|
||||
|
||||
```typescript{3,15}
|
||||
import defineApp from '../../helpers/define-app';
|
||||
import auth from './auth';
|
||||
import triggers from './triggers';
|
||||
|
||||
export default defineApp({
|
||||
name: 'The cat API',
|
||||
key: 'thecatapi',
|
||||
iconUrl: '{BASE_URL}/apps/thecatapi/assets/favicon.svg',
|
||||
authDocUrl: 'https://automatisch.io/docs/apps/thecatapi/connection',
|
||||
supportsConnections: true,
|
||||
baseUrl: 'https://thecatapi.com',
|
||||
apiBaseUrl: 'https://api.thecatapi.com',
|
||||
primaryColor: '000000',
|
||||
auth,
|
||||
triggers
|
||||
});
|
||||
```
|
||||
|
||||
## Define triggers
|
||||
|
||||
Create the `triggers/index.ts` file inside of the `thecatapi` folder.
|
||||
|
||||
```typescript
|
||||
import searchCatImages from './search-cat-images';
|
||||
|
||||
export default [searchCatImages];
|
||||
```
|
||||
|
||||
:::tip
|
||||
If you add new triggers, you need to add them to the `triggers/index.ts` file and export all triggers as an array. The order of triggers in this array will be reflected in the Automatisch user interface.
|
||||
:::
|
||||
|
||||
## Add metadata
|
||||
|
||||
Create the `triggers/search-cat-images.ts` file inside of the `thecatapi` folder.
|
||||
|
||||
```typescript
|
||||
import defineTrigger from '../../../../helpers/define-trigger';
|
||||
|
||||
export default defineTrigger({
|
||||
name: 'Search cat images',
|
||||
key: 'searchCatImages',
|
||||
pollInterval: 15,
|
||||
description: 'Triggers when there is a new cat image.',
|
||||
|
||||
async run($) {
|
||||
// TODO: Implement trigger!
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Let's briefly explain what we defined here.
|
||||
|
||||
- `name`: The name of the trigger.
|
||||
- `key`: The key of the trigger. This is used to identify the trigger in Automatisch.
|
||||
- `pollInterval`: The interval in minutes in which the trigger should be polled. Even though we allow to define `pollInterval` field, it's not used in Automatisch at the moment. Currently, the default is 15 minutes and it's not possible to change it.
|
||||
- `description`: The description of the trigger.
|
||||
- `run`: The function that is executed when the trigger is triggered.
|
||||
|
||||
## Implement trigger
|
||||
|
||||
:::danger
|
||||
|
||||
- Automatisch expects you to push data in **reverse-chronological order** otherwise, the trigger will not work properly.
|
||||
- You have to push the `unique identifier` (it can be IDs or any field that can be used to identify the data) as `internalId`. This is used to prevent duplicate data.
|
||||
|
||||
:::
|
||||
|
||||
Implement the `run` function by adding highlighted lines.
|
||||
|
||||
```typescript{6-29}
|
||||
import defineTrigger from '../../../../helpers/define-trigger';
|
||||
|
||||
export default defineTrigger({
|
||||
// ...
|
||||
async run($) {
|
||||
let page = 0;
|
||||
let response;
|
||||
|
||||
const headers = {
|
||||
'x-api-key': $.auth.data.apiKey,
|
||||
};
|
||||
|
||||
do {
|
||||
let requestPath = `/v1/images/search?page=${page}&limit=10&order=DESC`;
|
||||
response = await $.http.get(requestPath, { headers });
|
||||
|
||||
response.data.forEach((image: IJSONObject) => {
|
||||
const dataItem = {
|
||||
raw: image,
|
||||
meta: {
|
||||
internalId: image.id,
|
||||
},
|
||||
};
|
||||
|
||||
$.pushTriggerItem(dataItem);
|
||||
});
|
||||
|
||||
page += 1;
|
||||
} while (response.data.length >= 10);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
We are using the `$.http` object to make HTTP requests. Our API is paginated, so we are making requests until we get less than 10 items, which means the last page.
|
||||
|
||||
We do not have to return anything from the `run` function. We are using the `$.pushTriggerItem` function to push the data to Automatisch. $.pushTriggerItem accepts an object with the following fields:
|
||||
|
||||
- `raw`: The raw data that you want to push to Automatisch.
|
||||
- `meta`: The metadata of the data. It has to have the `internalId` field.
|
||||
|
||||
:::tip
|
||||
|
||||
`$.pushTriggerItem` is smart enough to understand if the data is already pushed to Automatisch or not. If the data is already pushed and processed, it will stop the trigger, otherwise, it will continue to fetch new data. The check is done by comparing the `internalId` field with the `internalId` field of the data that is already processed. The control of whether the data is already processed or not is scoped by the flow.
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
|
||||
`$.pushTriggerItem` also understands whether the trigger is executed with `Test & Continue` button in the user interface or it's a trigger from a published flow. If the trigger is executed with `Test & Continue` button, it will push only one item regardless of whether we already processed the data or not and early exits the process, otherwise, it will fetch the remaining data.
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
|
||||
Let's say the trigger started to execute. It fetched the first five pages of data from the third-party API with five different HTTP requests and you still need to get the next page but you started to get an API rate limit error. In this case, Automatisch will not lose the data that is already fetched from the first five requests. It stops the trigger when it got the error the first time but processes all previously fetched data.
|
||||
|
||||
:::
|
||||
|
||||
### Test the trigger
|
||||
|
||||
Go to the flows page of Automatisch and create a new flow. Choose `The cat API` app and the `Search cat images` trigger and click `Test & Continue` button. If you a see JSON response in the user interface, it means that the trigger is working properly.
|
Reference in New Issue
Block a user