DavidLeDeaux

Parsing Webhooks

Blog Post created by DavidLeDeaux Employee on Feb 1, 2019

Last week we touched on creating webhooks, and this week we'll cover a way to capture a webhook and pull out information that you want to use.

 

Prerequisites

For this article, we'll be relying on Google Sheets using their published application capability.

We'll be working in the Script Editor which is very javascript heavy, so a background in javascript programming is helpful.

google_published_app from GitHub - davidledeaux/RallyWebhooks: Proof of concept ways to use Rally (Agile Central) webhooks 

 

 

Setting Up

The idea here is that we'll use the scripting capability of Google Sheets to create a published application.  This means that we'll have a unique URL that we can point webhooks to and then use javascript to parse the incoming JSON payload and write some logic around what we want to do with it.

 

Log into Google and access your Sheets at https://sheets.google.com

Start a new spreadsheet and give it a name like Agile Central Webhooks

Click Tools -> Script Editor

 

At this point you should have a blinky cursor in the myFunction() function:

 

In order for Google to accept requests as a published application, there are two mandatory functions needed; doGet() and doPost().  These two functions correspond with the HTTP GET and POST methods and define the behavior of your script depending on how it is accessed.  For our example, we'll only be using doPost(), but it is interesting to see how you could return responses to data that has been collected in the backend spreadsheet if someone performs a GET request.

 

So the first thing you'll do is to replace the existing function with your own.   In our example we don't really want our app serving anything important for a GET request, so we simply respond to any requests with a generic "request received" message.  We'll be doing the bulk of our work within the doPost() function.

function doGet(e) {
return HtmlService.createHtmlOutput("request received");
}

//this is a function that fires when the webapp receives a POST request
function doPost(e) {

}

 

 

Code Overview

The first thing we want to do is add a few lines to grab the data from our POST request and assign it to a variable and convert it to JSON data that we can access as a dictionary.

var params = JSON.stringify(e.postData.contents);
params = JSON.parse(params);
var data = JSON.parse(e.postData.contents);

 

The next few lines will set up some variable to give us some shortcuts to some data that we'll reference frequently.  The bulk of the interesting data will be in the changes section of the message payload, however we'll be pulling supplemental information from other areas of the message as well.

var changes = data.message.changes;
var state = data.message.state;
var object_type = data.message.object_type

 

In this next block of code we're pulling out details about the current state of the artifact; the formatted ID of the work item that was changed, the name of the work item and the time of the update.

for (var key in state) {
if (state[key].name == "FormattedID") {
var formatted_id = state[key].value;
}

if (state[key].name == "Name") {
var artifact_name = state[key].value;
}

if (state[key].name == "LastUpdateDate") {
var update_date = state[key].value;
}
}

 

Because we can have several changes that can occur on a work item at one time, we have to iterate through all of the changes in the changes section and pull out before and after values.  One thing that complicates this section is that, depending on what was changed, the structure of the changes element might not always be the same.  This is why we see three different methods to gather old and new values. 

 

In my example, I'm simply concatenating the results into a single string to store in a spreadsheet cell later on.  This mimics the changes summary emails that are sent out by notifications, however you might want to handle each change separately for processing depending on your end goal.

var what_changed = "";
for (var key in changes) {
if (changes[key].name != "VersionId") {
var changes_key = changes[key];

if (typeof changes_key.value === 'object' && changes_key.value !== null) {
if (changes_key.value.name) {
var new_value = changes_key.value.name;
var old_value = changes_key.old_value.name;
} else {
var new_value = changes_key.value.value;
var old_value = changes_key.old_value.value;
}
} else {
var new_value = changes_key.value;
var old_value = changes_key.old_value;
}

var what_changed = what_changed + changes_key.display_name + "<br>" + "Was: <br>" + old_value + "<br><br> Now: " + new_value + "<br><br>";
}
}

 

Finally, we log the results to a spreadsheet.

var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = Math.max(sheet.getLastRow(),1);
sheet.insertRowAfter(lastRow);
sheet.getRange(lastRow + 1, 1).setValue(update_date);
sheet.getRange(lastRow + 1, 2).setValue(object_type);
sheet.getRange(lastRow + 1, 3).setValue(formatted_id);
sheet.getRange(lastRow + 1, 4).setValue(artifact_name);
sheet.getRange(lastRow + 1, 5).setValue(what_changed);

SpreadsheetApp.flush();

 

And send a canned response that we received the post request.

return HtmlService.createHtmlOutput("post request received");

 

This is a very simple example of a way to get data into a spreadsheet, but it doesn't have to end there.  For example, you could have Google generate an email using 

MailApp.sendEmail('myemail@company.com', 'Work Item Changed', 'Work item was changed. Here are the changes ' + what_changed);

 

Or, you could turn around and have Google make a call to update another system with a command like

var response = UrlFetchApp.fetch('https://api.myothersite.com/someendpoint/');

 

 

Publishing the App

Once we have all of our code in place, we need to turn it into a published application and get our URL.  To start that process, we'll click Publish -> Deploy as web app...

 

Give the project a name

 

In the next dialog, we have to have the app impersonate someone who is authenticated since the webhook isn't capable of passing credentials. 

 

After clicking Deploy, you'll get a URL that you can use as a TargetURL in your webhook.  You could take this URL and PATCH your webhook you created from the  Creating a Webhook in Agile Central blog post.

Outcomes