Zapier - Catch Hook - JSON Array - Loop over each item in array - javascript

I need to use a Zapier webhook to take some incoming JSON data, which contains an array of items, loop that array and do an action for each element.
Here's a sample of incoming JSON data:
{
"first_name": "Bryan",
"last_name": "Helmig",
"age": 27,
"data": [
{
"title": "Two Down, One to Go",
"type": "Left"
},
{
"title": "Talk the Talk",
"type": "Right"
},
{
"title": "Know the Ropes",
"type": "Top"
}
]
}
The size of the array will be dynamic.
The problem is that when I import this data in the hook, it gives me
data
title: Two Down, One to Go
type: Left
title: Talk the Talk
type: Right
title: Know the Ropes
type: Top
So, basically it says that data is just a big string of all this stuff together.
Can anyone help me figure out if it's possible to have a Zap loop over this and do something, e.g., insert data into a sheet, for ever item in the array? I'm aware of the "Code" actions, I've chosen JavaScript, which I could parse out the string, but that doesn't seem efficient. Plus, in reality, there will be a lot of data in the objects inside the JSON array.
EDIT: SOLVED! ANSWER BELOW

So, the first part is to Catch Raw Hook for a trigger. It's the normal "Webhooks", but you have to click to show the less common variations. With the Catch Raw Hook, your data will not be turned automatically turned into variables via the Zapier app, you'll have the raw JSON data.
Once you have the raw JSON, in my case, you'll have an action, and this will be the "Code" action. I'm using JavaScript. In my template, I'm grabbing the entire JSON string (your whole imported JSON is a string right now, not an object, so we can't use "." (dot) notation to access parts of it).
You'll need to JSON.parse() the string in the code. But first, let me explain that Zapier has a pre-defined variable called inputData that you'll use in your code. Then in the top of the "Edit Template" section of your "Code" Action, you'll see you can name the variable of that JSON string you imported.
Now the fun part! In the code, you'll type:
// of course, you can change the variables to what you want
// but 'inputData' is unique, can't change that
const myData = JSON.parse(inputData.rawJsonData);
So, my raw data is a string, it's not JSON yet, so this line of code makes it a JSON object. And now, as an object we can loop over it or .map or access 'this.that' or whatever you want.
The next important thing to mention about "Code" in Zapier, is that to get your stuff out, you return. So, in the next few lines, I'm going to return a .map function that returns each item in an array. And it's tough to grasp how Zapier treats this, but it actually runs the next "Action" you create (e.g. adding a row to a sheet) for each time you loop in that .map. So, let's take a look below:
return myData.data.map(item => {
return item;
});
If you remember, I had an array called "data" in my raw JSON I listed in the original question. It will loop over that array and since I'm returning, then it will perform an "Add Row to Sheet" (in my case) for each loop, thus, inserting all of my data as multiple rows in my spreadsheet.
So the finished code:
const myData = JSON.parse(inputData.rawJsonData);
return myData.data.map(item => {
return item;
});

Related

How to pass an array of objects through a query string according to REST?

What is the best practice to pass an array of objects throught query string in REST style?
For example, the array:
examples[] = [
{
name: "foo",
value: "1"
},
{
name: "bar",
value: "2"
}
]
I thought about it:
/items?examples[0][name]=foo&examples[0][value]=1&examples[1}[name]=bar&examples[1][value]=2
Are there other ways to do this?
Upd:
I need readable URL to show it to the user in the address field. It should display state of some filters in the table, I'm not sending it to the backend.
Since you're parsing this manually in JS, you could keep the structure you have and just write a parsing function
var items = {};
location.search.split("?")[1].split("&").map((q) => {
var [token, value] = q.split("="),
[idx, key] = /\[([0-9+])\]\[(\w+)\]/g.exec(token).slice(1, 3);
if (!items[idx]){
items[idx] = {};
}
items[idx][key] = value;
})
This will yield you something with a structure like
{
"0": {
"key1": "data"
"key2": "data:
},
"1": {
"key1": "data"
"key2": "data"
}
}
If you need it to end up an array, it would be pretty easy to convert, but keeping it as an object with numeric strings for keys will prevent an error if it's not sequential.
Also, note there's no error checking or anything here, so if you're going to have query string params that aren't in that format, you'll want to test for that and handle them differently.
You shouldn't take care about how pass data for a backend, Angular do it for you.
About your example, you probably want to update or save several item. So it's not into the url that you will pass your data but into the Request Body :
this.httpService.post(yourUrl, examples, yourHttpOptions).subscribe( (response) => {
// you manage your response data
});
REST does not care how you encode information into your identifiers. You can use any scheme you want, so long as it is consistent with the production rules defined by RFC 3986.
REST cares a little bit about how you share information about creating URI, in the sense that that information should be shared in some readily standardizable form, like an HTML form, or a URI Template.
We don't, to my knowledge, have a "readily standardizable form" that describes how to transform a json array to a query string.
But... REST does allow code on demand; embedding, for example, a bunch of java script into a resource where that javascript knows how to encode the json into the URI... that is in bounds, so long as you have the code on demand itself referenced in a readily standardizable way (like we have with HTML and script tags).
In practice? urlencode the json representation and put it onto the query string directly. That will get you through until you start to discover the real requirements that your URI design needs to support (requirements like: operators needing to be able to understand the access logs).

How to access arrays with HTTP Get call in nodejs

How to get access to arrays data by requesting HTTP GET call with headers in
nodeJS. I am getting undefined error when I am trying to call the 3rd party
services. I make HTTP GET call with two headers.
This is response from HTTP GET call.
Here How I can access to "description".
{
"dotdList": [
{
"title": "From ₹ 10,299",
"description": "Haier 181 Single Door",
"url": "https://dl.flipkart.com/dl/home-kitchen/home-appliances/refrigerators/pr?sid=j9e,abm,hzg&offer=nb:mp:07de369c12&affid=fstlistgm",
"imageUrls": [
{
"url": "https://rukminim1.flixcart.com/image/800/800/j2z1fgw0/refrigerator-new/m/j/c/hrd-1813bms-r-3-haier-original-imaeu7gzwfskmxfx.jpeg?q=90",
"resolutionType": "default"
},
{
"url": "https://rukminim1.flixcart.com/image/200/200/j2z1fgw0/refrigerator-new/m/j/c/hrd-1813bms-r-3-haier-original-imaeu7gzwfskmxfx.jpeg?q=90",
"resolutionType": "low"
},
{
"url": "https://rukminim1.flixcart.com/image/400/400/j2z1fgw0/refrigerator-new/m/j/c/hrd-1813bms-r-3-haier-original-imaeu7gzwfskmxfx.jpeg?q=90",
"resolutionType": "mid"
},
{
"url": "https://rukminim1.flixcart.com/image/800/800/j2z1fgw0/refrigerator-new/m/j/c/hrd-1813bms-r-3-haier-original-imaeu7gzwfskmxfx.jpeg?q=90",
"resolutionType": "high"
}
],
"availability": "LIVE"
}
]
}
How to access to description.
Here is my actual code
var request = require('request');
request({
url: 'https://affiliate-api.flipkart.net/affiliate/offers/v1/dotd/json',
method: 'GET',
headers: {
'Fk-Affiliate-Id':'XXXXX',
'Fk-Affiliate-Id': 'XXXXXXXXXXX'
}
}, function(error, response, body) {
if(!error && response.statusCode == 200) {
let dataFs = JSON.parse(body);
let titleN = `${dataFs["dotdList"][0]["title"]}`;
console.log("error in fun");
sendTextMessage(sender, titleN);
}else {
console.error(response.error);
console.log("else error");
}
});
Part 2.This is another Response JSON
How Can I access objects from array. here I am making HTTP GET call to another url to get JSON data. below is the reponse data.
Where I am not able to access to array of data. I need to access offer_name
[
{
"featured": "0",
"exclusive": "0",
"promo_id": "P74192",
"offer_id": "180",
"offer_name": "Dominos.co.in CPS - India",
"coupon_title": "Garlic Bread & Dip free",
"category": "Food & Beverage",
"coupon_description": "TnC: Valid on Saturday",
"coupon_type": "Coupon",
"coupon_code": "NET09",
"ref_id": "src=vcommission&utm_source=Vcommission&utm_medium=Affiliate&utm_term=paid&utm_campaign=OLOHome",
"link": "http://tracking.vcommission.com/aff_c?offer_id=180&aff_id=36792",
"coupon_expiry": "2017-08-12",
"added": "2017-08-01",
"preview_url": "https://pizzaonline.dominos.co.in/",
"store_link": "http://tracking.vcommission.com/aff_c?offer_id=180&aff_id=36792",
"store_image": "http://media.vcommission.com/brand/files/vcm/180/dominos.jpg"
}
]
Answering your questions
Part 1
You already access the data's title via dataFs["dotdList"][0]["title"], and you can access the description the same way: dataFs["dotdList"][0]["description"].
Part 2
This one is quite similar to your old one. You should be able to access the fields you want via responseData[0]["offer_name"].
Explanation of Response objects, arrays, etc.
In your responses you get an array object, which you can tell by having values surrounded by brackets ([ /* data */ ]). To access values within an array, you use the access operator, like so: arrayValue[0], where 0 is the key or index of the object you are trying to fetch.
In both of your questions you are trying to access the first (and only) object within the array, and thus you can short cut that by using the 0 index of the array, i.e. responseData[0].
Within those arrays, though, you have objects. JSON Objects specifically (as is given to you by the HTTP GET request) can have fields with values which can be a string ("string"), number (0), or a boolean values (true or false). You can access the fields of an object by either accessing them using the dot operator (object.field) or by using the access operator, but with specific key (object["field"]). Using the access operator is especially useful if your field's key uses a space or number.
Putting those things together we can figure out your questions quite easily:
dataFS is an object, and we are wanting to access the elements underneath the objects in the array called "dotdList". Thus, we can access the list via the access operator (dataFs["dotdList"]), then access the first (and only) object via using the 0 index (dataFs["dotdList"][0]), and lastly accessing the fields we want by either using the dot or the access operator (dataFs["dotdList"][0]["description"] or `dataFs["dotdList"][0].description). If you need to do this multiple times, it is recommended to store the object in a variable, i.e:
var dotd = dataFs["dotdList"][0];
console.log(dotd.description) // got description!
The second part is also quite easy to figure out; you get back an array, you want the first object, and then you want to access the field: thus, access the first object using the 0 index (responseData[0]) and then access the fields you want (responseData[0].offer_name).
Always check to make sure what you are trying to access is there (i.e.the array itself in #1 and the objects within the array in both). If it isn't, your code will start throwing errors!

Why does my array need parsing, when they look the same in the console?

I'm working on a D3 component when a question springs to mind. As I'm experementing with different arrays, I'm wondering why they need different treatment of data, when they all contain the same.
First case: I have a 'hardcoded' array, which looks like the following:
var tmp = [
{
"Weight": 0.0,
"Speed": 59.9,
"Depth": 362.24000,
"Time": "2014-04-09T10:01:23",
"Id": 0
}, {
"Weight": 10.0,
"Speed": 59.9,
"Depth": 394.07000,
"Time": "2014-04-09T10:01:56",
"Id": 1
}];
Or, when inspected in Chrome console:
Whenever I feed my component with this array, the component works fine and all lines / axis are drawn correctly.
Second case: I fetch an array from my controller using d3.json, and get the following returned when logging it to console:
[{"Weight":0.0,"Speed":59.9,"Depth":362.24000,"Time":"2014-04-09T10:01:23","Id":0},{"Weight":10.0,"Speed":59.9,"Depth":394.07000,"Time":"2014-04-09T10:01:56","Id":1}]
So, whenever I'm trying to do a json.foreach() (json is the name of the array from controller):
json.forEach(function(d) {
var date = format(d.Time);
d.Time = date;
});
I get an error saying the following when starting the foreach function:
Uncaught TypeError: undefined is not a function.
In order for this to work, I had to do a JSON.parse(json) on the data returned from my controller through d3.json(), and then my array looks like the following:
I should also mention that my asp.net mvc controller returns this:
string json = JsonConvert.SerializeObject(Model.Trend.ToArray());
return Json(json, JsonRequestBehavior.AllowGet);
I get the fact that my array returned from controller looks like a string of values when inspecting it, but I really don't understand why.
So, I guess my question really boils down to this;
Why does my array "tmp" work, but my array fetched with d3.json needs to be parsed before working?
The 'tmp' array is parsed for you by the browser when the script is run. You can check this when you deliberately create a faulty array by for example place a double bracket somewhere.
Your browser will tell you it doesn't understand what you want the 'tmp' variable to be.
However, when you create a call to your MVC controller, it doesn't know beforehand what result type to expect from that controller. Maybe some other controller it will call later on in your application will return XML data, which needs another way of parsing.
An easier method to fetch JSON data from 'anywhere' is to use the jQuery .getJSON method.
This requires no extra call to parse the data.
Also, what does you D3 call look like? What function did you declare to handle the callback?
try
$.each(json, function (index, d) {
var date = format(d.Time);
d.Time = date;
});

About the path syntax of this JSON

What would be the syntax path to thumbnails.data?
also, could such an output be simplified, to just {}'s, rather than []'s and {}'s?
{
"returnValue":true,
"results":[
{
"_id":"++HUS_WBo9OoOpWA",
"_kind":"com.palm.media.audio.file:1",
"_rev":3357,
"album":"Elements of Love: Ballads",
"albumArtist":"Earth, Wind & Fire",
"artist":"Earth, Wind & Fire",
"bookmark":0,
"createdTime":0,
"disc":{
"position":1,
"total":1
},
"duration":0,
"genre":"Rhythm & Blues",
"isRingtone":false,
"modifiedTime":1300682209,
"path":"/media/internal/Track 03 - Devotion.mp3",
"searchKey":"Earth, Wind & Fire Elements of Love: Ballads Devotion",
"size":6976284,
"sortKey":{
"trackAndDisc":100003
},
"thumbnails":[
{
"_id":"d1e",
"data":"/media/internal/Track 03 - Devotion.mp3:216:5998",
"type":"embedded"
}
],
"title":"Devotion",
"track":{
"position":3,
"total":0
}
}
]
}
Thanks
If myData holds the data structure in question, you would use
myData.results[0].thumbnails[0].data
As for simplification of your output, yes, it certainly could be simplified, but we'd have to see the code which generates that to tell you how to accomplish it.
How do I get to the thumbnails data?
Assuming your JSON object is stored in the variable myData:
myData.results[0].thumbnails[0].data
Note that this is for the specific example you posted and will always return the first thumbnails data for the first result. In actual code, you will probably loop over both the arrays (results and thumbnails) to extract all the thumbnails data for all the results objects.
Can this JSON object be simplified?
It most certainly could be - it depends on what the purpose is and how it's being generated. If it's being returned by a webservice that you have no control over, then no, you can't change it, obviously. If you're generating it, then sure, you define the object and it's meaning. For example, you could restrict the number of thumbnails to just 1 always, and so, instead of having an array of thumbnails, you'd have just a thumbnail object.
However, as I see it right now, it makes a lot sense - your results could include 1 or more items, hence an array; there could more than 1 thumbnail images and so an array is used there as well...
Are you planning to have more than one thumbnail per result? If not, you can just have:
"thumbnails":{
"_id":"d1e",
"data":"/media/internal/Track 03 - Devotion.mp3:216:5998",
"type":"embedded"
},
and access it as: results[i].thumbnails.data

Comparing variable size Objects in Javascript

I'm working on an auto-updating table of information using AJAX, but I've run into a bump in the road. I'm using PHP to return a JSON object on each request, which contains data in the following format:
({
"table": {
"544532": {
"field1": "data",
"field2": "data2",
"field3": "data3",
.....
},
"544525": {
"field1": "data",
"field2": "data2",
"field3": "data3",
.....
},
......
}
}); //
I use Prototype.js to get the list of IDs into an array:
var ids = Object.keys(data.table).sort();
However, random rows of the table could be disappear from the list at any time, and new rows could be added to the end at any time. I assume I would store the array of IDs from the previous request and compare those with the new array, but since random rows can disappear, thus shifting the IDs after that one, how do I compare these so that I can only add new rows or remove deleted rows from the page?
Unfortunately Prototype doesn't include a Set type which would have made things a whole lot simpler. So we'll have to make do with this:
Array.prototype.subtract = function(a){
return this.reject(this.include.bind(a));
}
The above adds a much needed subtract function. We can use it like this:
added_ids = new_ids.subtract(old_ids);
removed_ids = old_ids.subtract(new_ids);
It's not too slow either since some browsers supports indexOf which Prototype's include checks for and uses.
PS. Array already has an intersect function, if you'd like a complement too here it is...
Array.prototype.complement = function(a){
return a.reject(this.include.bind(this));
}
Essentially a.subtract(b) is the same as b.complement(a).
Im sure there are better ways to do this - but you will need to store the rows that are shown in the table somewhere - perhaps an array - then loop the JSON object comparing the rows against the array.
You should update your JSON data structure when the table is updated. That would be that data model for the page. Then you can just call Object.keys(data.table) everytime you need it.

Categories