Building Webhook Trigger
Last update: 16.05.2022
Triggers section we saw how to set up polling triggers for your custom connector. In this section, we will see how we can set up the triggers for webhook-based applications.
Setting up a webhook trigger is almost the same as a polling trigger except you need to add additional code to subscribe & unsubscribe the webhook dynamically when a user publishes/unpublishes the workflow.
For simplicity’s sake, we are skipping input/output schema code. Assuming you have set up basic trigger fields, let’s proceed with the subscribe & unsubscribe code.
Select the webhook trigger type as Webhook, and code boxes for Subscribe & Unsubscribe will appear in the UI.
Subscribe & Unsubscribe
Most SaaS applications provide APIs to Subscribe & Unsubscribe webhook events dynamically. With APIFuse Connector SDK you can utilize these APIs and let the APIFuse handle publish/unpublish workflow actions while your code takes care of the webhook subscription.
Below objects are available for you to complete the webhook subscription.
- oauthCredentials
- This object contains the client id/secret and other OAuth details you configured in the authentication section.
- You can use this object to refresh the salesforce access token
- connectionData
- This object contains user authentication data. The data depends on the authentication type configured “Authentication” section
- OAuth 2 – connectionData object will contain the Token API response ie access_token, refresh_token, and any additional data returned by token API. In our case, Salesforce token API returns access_token, refresh_token, and instance_url. We will use instance_url to make the API call to “SObject Describe” API
- Basic Authentication – connectionData object will contain username & password fields with the values provided by your users.
- Custom Authentication – connectionData object will contain the inputs you defined in the Authentication section with the values entered by users.
- inputs
- This object contains values for your input fields when your user is configuring the workflow. Sometimes you may need input from the user for building out the output schema or additional input schema. In those cases, you can utilize the inputs field.
- If you take the Google Sheets connector, to construct the output schema we would need to know the spreadsheet file id, drive id, and book id. To fetch book ids you need to know the spreadsheet id and to fetch spreadsheet ids you need to know the drive id. To achieve this, you can write the following code.
- webhookUrl
- String variable prepopulated with webhook URL that you need to register with your application. Do not define the local variable in this name. webhookUrl is a global variable.
- updateConnectionData
- This is a javascript function that you can call in case you refreshed the access token and you want to update this in the APIFuse data store. Some applications create a new refresh token when you refresh an access token, in those cases old refresh token will not work hence you have to store the newly generated refresh token.
Your code for Subscribe should output a non-null webhook object. This object can contain any data that you may need when unregistering the webhook.
Sample code for subscribing webhook:
async function refreshAccessToken() { let data = { grant_type: 'refresh_token', client_id: oauthCredentials.client_id, client_secret: oauthCredentials.client_secret, refresh_token: connectionData.refresh_token } return axios({ url: `https://abc-staging.us.auth0.com/oauth/token`, method: 'post', data: data, headers: { 'Content-Type': 'application/json' }, }) } async function subscribe(webhookUrl) { let data = { "operationName": "webhook", "variables": { "input": { "name": "CommentEvent Create", "url": webhookUrl, "eventList": ["commentEvent"] } } } console.log(data); return axios.post(`https://app.abc.ca/api/webhook`, data, { headers: { 'Authorization': 'Bearer ' + connectionData.access_token, 'Content-Type': 'application/json' } }) } async function subscribeWebhook(){ // Refreshing access token before proceeding const tokenRs = await refreshAccessToken(); // update the refresh token in APIFuse datastore connectionData.access_token = tokenRs.data.access_token; connectionData.refresh_token = tokenRs.data.refresh_token; await updateConnectionData(connectionData); // Make API Call to register the webhook // webhookUrl is pre populated with webhook url. Do not declare variable with same name. let res = await subscribe(webhookUrl); // Here we are populating webhook object with API Response, because we need webhook id from the application ABC to unsubscribe later // Do NOT declare a webhook variable. Just assign the value. webhook = res.data; } subscribeWebhook()
Sample code for unsubscribing webhook. This is almost the same as subscribing code except, that you need to populate the unregistered boolean variable with true if the unsubscription is successful.
async function refreshAccessToken() { let data = { grant_type: 'refresh_token', client_id: oauthCredentials.client_id, client_secret: oauthCredentials.client_secret, refresh_token: connectionData.refresh_token } return axios({ url: `https://abc-staging.us.auth0.com/oauth/token`, method: 'post', data: data, headers: { 'Content-Type': 'application/json' }, }) } async function unsubscribe(webhookId) { console.log(data); return axios.post(`https://app.abc.ca/api/webhook/${webhookId}`, {}, { headers: { 'Authorization': 'Bearer ' + connectionData.access_token, 'Content-Type': 'application/json' } }) } async function unsubscribeWebhook() { const tokenRs = await refreshAccessToken(); connectionData.refresh_token = tokenRs.data.refresh_token connectionData.access_token = tokenRs.data.access_token; await updateConnectionData(connectionData); // webhook object prepopulated with the content you added in the subscription code let res = await unsubscribe(webhook.id); if(res.status ===200){ unregistered = true; }else{ unregistered = false; } } unsubscribeWebhook();