Google Sheets - Mailchimp API - Create Template - google-apps-script

WHAT I AM TRYING TO DO:
I am trying to create a template (custom HTML) using Mailchimp API according to this documentation.
WHAT I HAVE TRIED SO FAR:
Took raw HTML of the template I created using 'drag-and-drop'. Tested it using 'code-your-own'. Saved in a variable in apps script. Used to the following code, with data set as that variable. I got the following error
{instance=2fb8b5eb-f11c-4260-a958-f16e5bc7c98b, detail=The resource submitted could not be validated. For field-specific details, see the 'errors' array., type=http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/, title=Invalid Resource, errors=[{field=, message=Schema describes object, NULL found instead}], status=400}
I then set the data to simpler HTML as shown below. I got the same error.
I tried using an already created template (accessed through TEMPLATE_ID) and tried to edit that (just the name of the template). I got the same error though I am able to access the template. The changes I made were:
var TEMPLATE_ID = 'MY_TEMPLATE_ID';
var endpoint = 'templates/' + TEMPLATE_ID;
var data = {
'name': 'new test name'
}
In params
'method': 'PATCH'
I also tried to GET method to see the templates, campaigns, lists. I am successfully able to do that.
I looked up the various answers on SO, one of them suggested using mergefields, I tried it too with the same error.
var data = {
'name': 'Test Template',
'html': '<html><head></head><body><p>TEST</p><body></html>',
'mergefields': {}
};
MWE:
function mailchimpCampaign(){
// URL and params for the Mailchimp API
var root = 'https://us19.api.mailchimp.com/3.0/';
var endpoint = 'templates';
var data = {
'name': 'Test Template',
'html': '<html><head></head><body><p>TEST</p><body></html>'
};
var payload = JSON.stringify(data);
// parameters for url fetch
var params = {
'method': 'POST',
'muteHttpExceptions': true,
'headers': {
'Authorization': 'apikey ' + API_KEY,
'content-type': 'application/json'
},
'data': payload
};
try {
// call the Mailchimp API
var response = UrlFetchApp.fetch(root + endpoint, params);
var data = response.getContentText();
var json = JSON.parse(data);
Logger.log(json);
}
catch (error) {
// deal with any errors
Logger.log(error);
};
}
Any help will be appreciated. Thanks.

This is for future readers.
So while I was hitting my head on this error. I tried using UrlFetchApp.getRequest() and it showed me that payload was empty.
The problem was I had to payload instead of data that I was using.
Updated working code:
var params = {
'method': 'POST',
'muteHttpExceptions': true,
'headers': {
'Authorization': 'apikey ' + API_KEY,
'content-type': 'application/json'
},
'payload': payload
};

Related

Google Apps Script UrlFetchApp GET to a node.js endpoint results in an empty body

I am using Google Apps Script to make a UrlFetchApp call to a node.js API endpoint. I own both the Google Apps Script code and node.js code & endpoint, so I can watch what is happening.
When I use Postman, it works. But when I use GAS UrlFetchApp, it doesn't work, as req.body in node is empty { }. I even looked at the code that Postman creates for JavaScript Fetch and try to nearly duplicate it, except for things I know GAS' UrlFetchApp needs. I've done quite a few UrlFetchApp calls with GAS to various external endpoints. So, I'm not new, but can't figure this one out.
Here is my Google Apps Script code:
var url = 'https://xxxxxxxxxxx.azurewebsites.net/api/account';
var data = {
"email": address,
"apiKey": 'xxxxxxxxxxxxxxxxxxx'
}
var payLoadInfo = JSON.stringify(data);
var options = {
"method": "GET",
"headers": {'Content-Type': 'application/json'},
// 'Content-Type': 'application/json',
// "contentType": 'application/json',
redirect: 'follow',
"muteHttpExceptions": true,
"body": payLoadInfo,
// "payload": JSON.stringify(data)
// payload: payLoadInfo
};
var response = UrlFetchApp.fetch(url, options);
The commented out parts of "options" are several different ways I've tried to get it to work. I know in the past that I've usually used "payload" instead of "body" like I am this time (Postman suggested it). When I use "payload", it fails completely, not even getting to my node code. I also tried putting the apiKey in the header.
Here is the node.js API endpoint code:
router.get("/account", async (req, res) => {
var apiKey = process.env.API_KEY;
console.log('apiKey = ' + apiKey);
console.log('req.body = ' + JSON.stringify(req.body, null, 2));
console.log('req.body.apiKey = ' + req.body.apiKey);
if (req.body.apiKey != apiKey) {
console.log('apiKey is not equal');
res.status(401).send({ error: "You are not authorized." });
} else {
process the request...
}
When I use "payload" in "options" I get a 500, and the server code never executes.
When I use "body" in "options", I see the server code execute, but the console.log('req.body = ' + JSON.stringify(req.body, null, 2)), just comes back with an empty object {}, and then since req.body.apiKey != apiKey, it consoles "apiKey is not equal" and sends a 401. When using Postman, the req.body object consoles fine, showing the email & apiKey.
No matter what combinations of things I put into options, it fails either with 500 or 401. However, Postman works great with pretty much the same parameters, headers, etc.
Here is what Postman shows for the code:
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
myHeaders.append("Cookie", "ARRAffinity=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; ARRAffinitySameSite=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
var raw = JSON.stringify({"email":"xxxxxxxxxxxxxxxxx#gmail.com","apiKey":"xxxxxxxxxxxxxxxx"});
var requestOptions = {
method: 'GET',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
I even tried including the cookie and "redirect: follow", but none works.
What am I missing?
I got it to work, thanks to help from #Tanaike (see comments above).
It seems that unlike normal "fetch" in node.js, URLFetchApp in Google Apps Script will not send a body along with a GET.
I still used GET, but changed to sending the param in the URL and the apiKey in the header.

Upload multiple attachments via Jira API using UrlFetchApp.fetch

I am using google app script server side coding to upload multiple files using Jira Rest API. I have used urlFetchApp.fetch() method for it. The payload i am passing is file blob data with 'Content-Type: false' as i am unable to pass it as formData through server side coding.
With this approach i am able to pass single file at a time to Jira attachments API, I have to call Jira API for each file.
Below is sample code,
function updateJiraTicket(fileUploadArr, ticketId){
const jira_Api = getJiraInstanceKeys();
const JIRA_URL= jira_Api["URL"] + ticketId + "/attachments";
const JIRA_LOGIN = jira_Api["LOGINNAME"];
const JIRA_PASSWORD = jira_Api["PASSWORD"];
const PROJECT = jira_Api["PROJECT"];
//fileUploadArr format getting passed from file upload UI side control
//fileUploadArr = [{“fileData”:”{base64 file data}”, “fileType”:”image/jpg”,”fileName”:”testimg1”},{“fileData”:”{base64 file data}”, “fileType”:”image/jpg”,”fileName”:”testimg2”}]
fileUploadArr.forEach(function(arr) {
let file = getFile(arr.fileData, arr.fileType, arr.fileName);
let formdata = {'file' : file };
let params = {
method: 'POST',
headers: {
'Authorization': 'Basic ' + Utilities.base64Encode(JIRA_LOGIN+':'+JIRA_PASSWORD),
'Content-Type': false,
'X-Atlassian-Token': 'no-check'
},
"payload": formdata,
muteHttpExceptions: true
}
let result = UrlFetchApp.fetch(JIRA_URL, params);
let response = result.getContentText();
})
}
function getFile(data, type, name) {
var file = Utilities.newBlob(Utilities.base64Decode(data), type, name);
return file;
}
Can anyone help with this?

Invalid customer.address object error when trying to create new Stripe customers in Google Script

I'm trying to automate the creation and updating of customers on my stripe account with a Google Script, but when passing the customer object, even though it seems to align with the structure laid out in the docs I receive a 400 error response from the Stripe API stating the address object is invalid.
Current Function: (for POSTing the customer object to the Stripe API)
function SendCustomer(details) {
// determine endpoint based on if sheet row has stripe_customer_id value
var endpoint;
if (details.stripe_customer_id && details.stripe_customer_id.length() > 0) {
// We're updating an existing customer
endpoint = CUSTOMERS_ENDPOINT + '/' + details.stripe_customer_id;
} else {
// We're creating a new customer
endpoint = CUSTOMERS_ENDPOINT;
}
var cust = {
'address': JSON.stringify({
'line1': details.street,
'line2': '',
'city': details.city,
'state': details.state,
// Google Sheets holds a Number, so convert to String as required by Stripe API
'postal_code': details.postal_code ? details.postal_code.toString() : details.postal_code,
'country': 'US'
}),
'email': details.email,
'phone': details.phone_cell,
'name': details.fname + ' ' + details.lname
}
Logger.log(cust);
var options = {
'method' : 'post',
'headers': {
'Authorization': 'Bearer ' + API_KEY
},
'payload' : cust
};
var cust_response = UrlFetchApp.fetch(endpoint, options)
var json_response = JSON.parse(cust_response.getContentText());
return json_response.id
}
Error Message when running the above function:
"error": {
"message": "Invalid object",
"param": "address",
"type": "invalid_request_error"
}
What am I doing wrong? From what I can tell, I'm following the defined structure of the customer.address object per the API docs. Could it be the way that UrlFetchApp.fetch() is sending the payload that's messing it up? If so, how can I fix it?
After trying many different methods, I finally figured out how to properly construct any nested object (such as the address object in this case) to be sent correctly to the Stripe API through Google Apps Scripts. Catching this line in the UrlFetchApp documentation, gave me the idea on how to handle the construction of the customer.address object so that it's parsed correctly on Stripe's end.
payload - Description: "...A JavaScript object is interpreted as a
map of form field names to values, where the values can be either
strings or blobs."
This reminded me of how I saw other form data posted through various services when viewing them in the Chrome Developer Console. So, using that clue I was able to construct the proper structure as such:
var cust = {
'address[line1]': details.street,
'address[line2]': '',
'address[city]': details.city,
'address[state]': details.state,
'address[postal_code]': details.postal_code ? details.postal_code.toString() : details.postal_code,
'address[country]': 'US',
'email': details.email,
'phone': details.phone_cell,
'name': details.fname + ' ' + details.lname
}
Logger.log(cust);
var options = {
'method' : 'POST',
'content-type': 'application/x-www-form-urlencoded',
'headers': {
'Authorization': 'Bearer ' + API_KEY,
},
'payload' : cust
};
var cust_response = UrlFetchApp.fetch(endpoint, options)
var json_response = JSON.parse(cust_response.getContentText());

Generating zoho ticket using google apps script

I am trying to use zoho desk api in google apps script.
I am trying to genereate ticket through google script.But getting error.
Whereas if I do it in PHP its working fine.
Please find both codes for reference:
PHP CODE which is working
$auth_token = '12345ab';//your_auth_token
$org_id=12345; //your_organization_id
$ticket_data=array(
"departmentId"=>$getdepartmentid,
"contactId"=>$getcontactid,
"subject"=>$ticket_subject,
"description"=>$ticket_desc,
"priority"=>$priority,
"status"=>$ticketstatus,
"email"=>$contact_email,
"classification"=>$classification,
"channel"=>"Application"
);
$headers=array(
"Authorization: $auth_token",
"orgId: $org_id",
"contentType: application/json; charset=utf-8",
);
$url="https://desk.zoho.in/api/v1/tickets";
$ticket_data=(gettype($ticket_data)==="array")? json_encode($ticket_data):$ticket_data;
$ch= curl_init($url);
curl_setopt($ch,CURLOPT_HTTPHEADER,$headers);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE);
curl_setopt($ch,CURLOPT_POST,TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS,$ticket_data); //convert ticket data array to json
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response= curl_exec($ch);
$info= curl_getinfo($ch);
GOOGLE APPS SCRIPT(which is not working)
var authtoken = "12345ab"; //your_auth_token
var org_id=12345; //your_organization_id
var department=23220000000057620; // ID of department
var contact=23220000000066959; //ID of customer
var subject=location_urgent_inbox_folder_name + ' /' + Name_of_file_to_be_attached;
var description="Ticked via drive";
var status="open";
const ticketData = {
subject: subject,
departmentId: department, // Replace this with whatever yours is.
contactId: contact, // Replace this with whatever yours is.
description: description,
status: status
};
const zohoUrl = 'https://desk.zoho.in/api/v1/tickets';
try {
var response = UrlFetchApp.fetch(zohoUrl, {
"method": 'POST',
"muteHttpExceptions": true,
"headers": {
Authorization: authtoken,
orgId: org_id,
contentType: 'application/json',
},
"payload": JSON.stringify(ticketData),
});
Logger.log(response.getContentText());
const parsed = JSON.parse(response.getContentText());
} catch (error) {
Logger.log(error.toString());
}
Assuming I am looking at the right section of the right documentation (https://desk.zoho.com/DeskAPIDocument#Tickets_Createaticket), I think these are your issues:
Server's JSON-encoded response contains no message property, hence Logger.log(result.message); logs undefined. (Maybe trying logging response.getContentText() to see what properties are available in your case -- or refer to the API documentation.)
Authorization and orgId headers are missing in the request you send. (Looks like authtokens are deprecated (https://desk.zoho.com/DeskAPIDocument#Authentication) and you instead need to use OAuth 2.0 (https://desk.zoho.com/DeskAPIDocument#OauthTokens).)
Data needs to be sent in request's body. (You appear to be sending it in the query string.)
I've not read the documentation in detail but I don't see any mention of query string parameters authtoken and JSONString (CTRL+F returns no matches). So you might want to get rid of them in your code and instead follow what the documentation says.
The code below is untested and won't work (as you need to replace with your own credentials). But it should give you an idea of how you can accomplish this.
// See: https://desk.zoho.com/DeskAPIDocument#Tickets#Tickets_Createaticket
// Required: subject, departmentId, contactId
const ticketData = {
subject: location_urgent_inbox_folder_name + ‘ /’ + Name_of_file_to_be_attached, // Taken from your question. Presume these are declared, valid and in scope.
departmentId: '12345', // Replace this with whatever yours is.
contactId: '12345', // Replace this with whatever yours is.
description: 'Ticked via drive',
status: 'open'
};
const zohoUrl = 'https://desk.zoho.in/api/v1/tickets';
try {
// See: https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app#fetchurl,-params
const response = UrlFetchApp.fetch(zohoUrl, {
method: 'POST',
contentType: 'application/json',
headers: {
orgId: '12345' // Replace this with whatever yours is.
Authorization: 'Zoho-oauthtoken ....' // See: https://desk.zoho.com/DeskAPIDocument#OauthTokens
},
payload: JSON.stringify(ticketData),
});
Logger.log(response.getContentText());
const parsed = JSON.parse(response.getContentText());
} catch (error) {
Logger.log(error.toString());
}
I've never worked with any of Zoho's APIs and haven't worked with Google Apps Script for a while, so apologies if I'm missing something.
Issue resolved,
Posting answer so that it might help someone
//create ticket in zoho
var authtoken = "abcd"; //your_auth_token
var org_id="12345"; //your_organization_id
var department="54321"; // ID of department in which ticket to be raised
var contact="9999"; //ID of customer
var subject="Ticket via google script";
var description="Ticket via google script";
var status="open";
const ticketData = {
subject: subject,
departmentId: department, // Replace this with whatever yours is.
contactId: contact, // Replace this with whatever yours is.
description: description,
status: status
};
const zohoUrl = 'https://desk.zoho.in/api/v1/tickets';
try {
var response = UrlFetchApp.fetch(zohoUrl, {
"method": 'POST',
"muteHttpExceptions": true,
"headers": {
Authorization: authtoken,
orgId: org_id,
contentType: 'application/json',
},
"payload": JSON.stringify(ticketData),
});
const parsed = JSON.parse(response.getContentText());
} catch (error) {
Logger.log(error.toString());
}

CouchDb 2.1.1 Admin API Compaction PUT Request

I am working in NodeJS with CouchDB 2.1.1.
I'm using the http.request() method to set various config settings using the CouchDB API.
Here's their API reference, yes, I've read it:
Configuration API
Here's an example of a working request to set the logging level:
const http = require('http');
var configOptions = {
host: 'localhost',
path: '/_node/couchdb#localhost/_config/',
port:5984,
header: {
'Content-Type': 'application/json'
}
};
function setLogLevel(){
configOptions.path = configOptions.path+'log/level';
configOptions.method = 'PUT';
var responseString = '';
var req = http.request(configOptions, function(res){
res.on("data", function (data) {
responseString += data;
});
res.on("end", function () {
console.log("oldLogLevel: " + responseString);
});
});
var data = '\"critical\"';
req.write(data);
req.end();
}
setLogLevel();
I had to escape all the quotes and such, which was expected.
Now I'm trying to get CouchDb to accept a setting for compaction.
The problem is that I'm attempting to replicate this same request to a different setting but that setting doesn't have a simple structure, though it appears to be "just a String" as well.
The CouchDB API is yelling at me about invalid JSON formats and I've tried a boatload of escape sequences and attempts to parse the JSON in various ways to get it to behave the way I think it should.
I can use Chrome's Advanced Rest Client to send this payload, and it is successful:
Request Method: PUT
Request URL: http://localhost:5984/_node/couchdb#localhost/_config/compactions/_default
Request Body: "[{db_fragmentation, \"70%\"}, {view_fragmentation, \"60%\"}, {from, \"23:00\"}, {to, \"04:00\"}]"
This returns a "200 OK"
When I execute the following function in my node app, I get a response of:
{"error":"bad_request","reason":"invalid UTF-8 JSON"}
function setCompaction(){
configOptions.path = configOptions.path+'compactions/_default';
configOptions.method = 'PUT';
var responseString = '';
var req = http.request(configOptions, function(res){
res.on("data", function (data) {
responseString += data;
});
res.on("end", function () {
console.log("oldCompaction: " + responseString);
});
});
var data = "\"[{db_fragmentation, \"70%\"}, {view_fragmentation, \"60%\"}, {from, \"23:00\"}, {to, \"04:00\"}]\"";
req.write(data);
req.end();
}
Can someone point at what I'm missing here?
Thanks in advance.
You need to use node's JSON module to prepare the data for transport:
var data = '[{db_fragmentation, "70%"}, {view_fragmentation, "60%"}, {from, "23:00"}, {to, "04:00"}]';
// Show the formatted data for the requests' payload.
JSON.stringify(data);
> '"[{db_fragmentation, \\"70%\\"}, {view_fragmentation, \\"60%\\"}, {from, \\"23:
00\\"}, {to, \\"04:00\\"}]"'
// Format data for the payload.
req.write(JSON.stringify(data));