Best answer

Setting up dictionary input fields

  • 12 November 2020
  • 20 replies
  • 1244 views

Userlevel 3
Badge +1

Hi, I am trying to replicate Inwise’s Add/Update Subscriber Action in my developer account. Everything is working fine except Dictionary input (Please check screenshot attached).

Error: Cannot read property 'length' of undefined

I have no idea why array.length is not working inside Zapier code mode but it works on any other IDE.

fields.length throws error
In working condition


Can you please let me know how do we actually handle dictionary input fields? I

icon

Best answer by ikbelkirasan 16 November 2020, 13:57

View original

This post has been closed for comments. Please create a new post if you need help or have a question about this topic.

20 replies

Userlevel 7
Badge +12

@adilalich - Awesome! Glad it worked for you :D

Userlevel 3
Badge +1

@ikbelkirasan IT WORKED! :grinning:  Thank you so much.

Userlevel 7
Badge +12

@adilalich - Oh ok, no problem. Maybe you didn’t use the code block?

 

Anyway, here’s the updated code:

const fields = [];
for (let name in bundle.inputData.fields) {
fields.push({
name,
content: bundle.inputData.fields[name],
});
}

const options = {
url: "https://api.inwise.com/rest/v1/contacts",
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
"X-API-KEY": bundle.authData.api_key,
},
params: {},
body: {
email: bundle.inputData.email,
add_to_groups_ids: bundle.inputData.add_to_groups_ids,
mobile_number: bundle.inputData.mobile_number,
fields,
},
};

return z.request(options).then((response) => {
// The code in this block runs after the server has already responded to our request.
response.throwForStatus();
return response.json;
});
Userlevel 3
Badge +1

@ikbelkirasan I did but the post was probably flagged and needs to be reviewed by moderators. Please find attached a doc file.

Userlevel 7
Badge +12

@adilalich - Can you post the whole source code? Just make sure to replace any secret values with a placeholder.

Userlevel 3
Badge +1

@ikbelkirasan  PLEASE DO!

This is the code which converts  dictionary into array of objects. 


// dictionary value which user inputs
    var arr = bundle.inputData.fields
//  var arr  = options.body.fields ????
    
// convert dictionary into how API expects fields     
   var field = [];
    for(var i in arr) {
      field.push({
        "name": i,
        "content": arr[i]
    });
    
    

}


     

Userlevel 3
Badge +1

@ikbelkirasan  PLEASE DO!

const options = {
  url: 'https://api.inwise.com/rest/v1/contacts',
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'X-API-KEY': bundle.authData.api_key
  },
  params: {
  },
  body: {
    'email': bundle.inputData.email,
    'add_to_groups_ids': bundle.inputData.add_to_groups_ids,
    'mobile_number': bundle.inputData.mobile_number,
    'fields': bundle.inputData.fields
  }
}

return z.request(options)
  .then((response) => {
    response.throwForStatus()
    
    const result = z.JSON.parse(response.content);

// dictionary value which user inputs
    var arr = bundle.inputData.fields
//  var arr  = options.body.fields ????
    
// convert dictionary into how API expects fields     
   var field = [];
    for(var i in arr) {
      field.push({
        "name": i,
        "content": arr[i]
    });
    
    

}
  return result;
  
 });
     

Userlevel 3
Badge +1
const options = {
url: 'https://api.inwise.com/rest/v1/contacts',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-API-KEY': bundle.authData.api_key
},
params: {
},
body: {
'email': bundle.inputData.email,
'add_to_groups_ids': bundle.inputData.add_to_groups_ids,
'mobile_number': bundle.inputData.mobile_number,
'fields': bundle.inputData.fields
}
}

return z.request(options)
.then((response) => {
response.throwForStatus()

const result = z.JSON.parse(response.content);

// dictionary value which user inputs
var arr = bundle.inputData.fields
// var arr = options.body.fields ????

// convert dictionary into how API expects fields
var field = [];
for(var i in arr) {
field.push({
"name": i,
"content": arr[i]
});



}
return result;

});

@ikbelkirasan PLEASE DO!

 

Userlevel 7
Badge +12

@adilalich Yup, that’s possible. Can you copy & paste your code here so I can tweak it for you?

Userlevel 3
Badge +1

@ikbelkirasan How can I convert dictionary into an Array of objects before calling z.request(options)? Is it even possible? Looks like I will have to make the request like it is expected i.e Array of Objects and convert that into dictionary in response BUT still the input designer have fields input type set to dictionary - You see the dilemma.

Userlevel 7
Badge +12

@adilalich I see. So, you need to send an array of objects containing the “name” and “content” values. However, you’re converting it to an array after making the request. You should be doing that before calling z.request(options). If you look closely, you’ll see that your options contains fields value before the conversion.

 

Userlevel 3
Badge +1

Update: Since API request expects “fields” field to look like an array of objects, and our dictionary with key (fields) is an object of key/value pairs, I tried to reverse engineered the whole process.

Step 1: I converted dictionary into how api expects the request for “fields”
 


Step 2: I changed response to revert dictionary into how “fields” request is made in API call
 


Step 3: Check response
 


​​​​@ikbelkirasan 

Userlevel 3
Badge +1

 

Hey @ikbelkirasan - I have used bundle.inputData.fields in the response I don’t see see dictionary. 
 

img: fields array is missing 

To get a response which also shows fields array, I had to tinker with the raw response. 

 

img 2: How the response should look like

Please suggest how I can achieve this? 

Userlevel 7
Badge +12

@adilalich Can you expand a bit on the use case here as I’m not getting it, unfortunately?

If all you want to do is to read the dictionary key-value pairs from the input data then you can just get it from bundle.inputData.fields which will return an object containing all the key-value pairs that were mapped in the zap editor.

The part I’m not understanding is why you’re parsing the fields from the response? Are you trying to compare bundle.inputData.fields with response.contact_details.fields?

 

Userlevel 3
Badge +1

@ikbelkirasan Yes, I get this part, and I have tried transforming raw response to match the response expected by a dictionary but it didn’t work.

 

const response = {
"is_new": false,
"contact_details": {
"id": 429241260,
"fields": [
{
"name": "field1",
"content": "Albert"
},
{
"name":"field2",
"content":"mc2"
}
],
"email": "albertmc@gmail.com",
"confirmed": true,
"last_update_date": "2020-11-14 01:22:37",
"registration_date": "2020-11-13 17:38:00"
}
}

var fields = response.contact_details.fields
console.log(fields);

var mapped = fields.map(f => ({ [f.name]: f.content }) );
var newObj = Object.assign({}, ...mapped );
console.log(newObj );

console.log(newObj) gives 

{ field1: "Albert", field2: "mc2" }

Userlevel 7
Badge +12

@adilalich - Dictionary field type is basically a JavaScript object (Not an array of objects). So, according to the zap screenshot, you should get something like this:

{
"inputData: {
"fields": {
"field1": "Esa",
"field2": "Babar"
}
}
}

 

Userlevel 3
Badge +1

UPDATE: My Javascript had few issues which I resolved BUT integration is still not working.

When I Test Action in Test your API Request section, I get the dictionary working. Here, I am inputting fields as expected by the requestBody
 

Test your API Request

This is how my request body looks like:

 body: {
    'email': bundle.inputData.email,
    'add_to_groups_ids': bundle.inputData.add_to_groups_ids,
    'mobile_number': bundle.inputData.mobile_number,
    'fields': bundle.inputData.fields
    
  }

But when I test via a zap it doesn’t work. Like @Zane said “The data that the user mapped to a dictionary input field will be available to your code in bundle.inputData.keyofyourdict.” which in my case is bundle.inputData.fields.

 


I know I am almost there, and will appreciate if someone can take me over the line.

Userlevel 3
Badge +1

@Zane  @ikbelkirasan Thank you for steering me in the right direction but I can’t seem to get my head around dictionary. I know my JS code to transform response data is correct


“The code you’re showing us above is referencing the response data - what your API returns to your integration.”

@Zane isn’t that how we approach this? We can’t do anything with the requestBody - we can only play with its response

 

img: This is how request body should look like

As you can see in img above - value of key “name” can be field1, field2, field3 .. field20 where field1 will be mapped to firstName, field 2 mapped with lastName etc

my code shared in the original post takes the response and transform it into how a dictionary should look like i.e value of “name” : value of “content

 

Input Designer

 

Userlevel 7
Badge +9

The code you’re showing us above is referencing the response data - what your API returns to your integration.  To figure out why that’s not an array as expected, I’d start by adding some z.console.log statements and watching the monitor section of the developer UI.  Also have a look at your server logs and make sure you’re sending what you expect to be sending.  

The data that the user mapped to a dictionary input field will be available to your code in bundle.inputData.keyofyourdict.

 

 

 

Userlevel 7
Badge +12

Hi @adilalich - Did you try to z.console.log(response.json) to make sure the API response is as expected?

Let’s say your dictionary input Field is called my_dict, in order to access field1 value, you should be able to get it from bundle.inputData.my_dict.field1. I hope this helpful to you!