Blank response from UrlFetchApp in Google App Script - google-apps-script

I'm trying to test the endpoints of an API and all the responses return blank with no errors.
I've tested using curl and the response actually has data in:
curl --request GET https://myapiurl.com/endpoint --header "authorization: bearer TOKEN"
Here's the segment of GAS code. The token property is set when I run a POST call to retrieve it, it expires after a while:
var url = 'https://myapiurl.com/endpoint';
var token = 'bearer TOKEN';
var headers = {
'authorization': token
};
var options = {
'headers' : headers
};
var response = UrlFetchApp.fetch(url,options);
var data = JSON.parse(response.getContentText());
The response should be a JSON object with a full list of keys/values. The response from curl is exactly what it should be, but the GAS version is blank, no errors.
I am completely at a loss, any help would be much appreciated!

Related

Call external Api with Bearer Token From google App Script

I am calling External web api with Bearer Authorization Token from google AppScript but getting Bearer Token null. I tried from Postmann it is working properly but from appscript i am getting Authorization Null.
Here is my google App Script Code:
var headers = { Authorization: 'Bearer Token'
};
var requestOptions = {
'method': 'GET',
'header':headers,
'redirect': 'follow',
'muteHttpExceptions':true
};
var res=UrlFetchApp.fetch('myapp/api/getxml', requestOptions); //Add RESTAPI Endpoint where
var json=res.getContentText();
Logger.log(res);
can you please check and tell me if i am missing something.
Thank you so much for your time.

Convert API requests to Google Apps Script

This post is following my previous one ->
How to turn Postman API's request into Apps Script code?
I'm trying to convert 3 API requests into a single piece of code via Google Apps Script.
The purpose is to export automatically a set of data from my CRM platform into Google Sheet.
Based on my CRM platform documentation, I need to do 3 API requests in order to get the final set of data I want:
Creating an export job (using a POST request)
Retrieve the job status from previous request (using GET request)
Retrieve the exported data (using GET request)
Below is the code for the 1st API request (kindly provided by Tanaike):
function exportjob() {
var url = 'https://api.intercom.io/export/content/data';
var options = {
"method": "post",
"headers": {
"Authorization": "Bearer 123456789",
"Accept": "application/json",
},
"contentType": "application/json",
"payload": JSON.stringify({
"created_at_after": 1654041600,
"created_at_before": 1656547200
})
}
var response = UrlFetchApp.fetch(url, options);
console.log(response.getContentText())
}
The result of this request is the following
Info {"job_identifier":"5gf58ty4y5y45229r", "status":"pending", "download_url":"", "download_expires_at":""}
Next step is to add the 2 other API requests in my script (Retrieve the job status and retrieve the data).
However I have a couple of issues:
For the 2nd API request
How do I include the job_identifier ID in my code? (given in the 1st request)
For the 3rd API request
How do I retrieve the data with the URL provided in the 2nd API request?
The data comes as ZIP file, how do I convert it to CSV so Google Sheet can open it?
How do get the final set of data to be exported in a google sheet?
Apologies for the long post, I'm trying to summarize the documentation from my CRM platform as much as I can.
Any help on how to retrieve the job POST and retrieve the set of data to a google sheet via CSV would be highly appreciated.
Thank you
1. About For the 2nd API request
If this is for Retrieve a job status, it seems that the sample curl command is as follows.
curl https://api.intercom.io/export/content/data/v5xsp8c19ji0s82 \
-X GET \
-H 'Authorization:Bearer <Your access token>'
-H 'Accept: application/json'
It seems that the value of job_identifier can be retrieved from your 1st request shown in your question. Ref
When this request is done for the first time, it seems that status returns pending. By this, it seems that until status is changed to complete, it is required to wait. Ref
2. About For the 3rd API request
If this is for Retrieve the exported data, it seems that the sample curl command is as follows.
curl https://api.intercom.io/download/content/data/xyz1234 \
-X GET \
-H 'Authorization:Bearer <Your access token>' \
-H 'Accept: application/octet-stream’
In this case, the document says Your exported message data will be streamed continuously back down to you in a gzipped CSV format.. I thought that in this case, the returned data might be able to be ungzipped with Utilities.ungzip, and the ungzipped data might be able to be parsed with Utilities.parseCsv.
3. Using your 3 requests, how about the following sample script?
function exportjob2() {
var accessToken = "###your access token###"; // Please set your access token.
// 1st request: This is from https://stackoverflow.com/a/73032528
var url1 = 'https://api.intercom.io/export/content/data';
var options1 = {
"method": "post",
"headers": {
"Authorization": "Bearer " + accessToken,
"Accept": "application/json",
},
"contentType": "application/json",
"payload": JSON.stringify({
"created_at_after": 1654041600,
"created_at_before": 1656547200
})
}
var response1 = UrlFetchApp.fetch(url1, options1);
var { job_identifier } = JSON.parse(response1.getContentText());
// 2nd request <--- Modified
var url2 = 'https://api.intercom.io/export/content/data/' + job_identifier;
var options2 = {
"headers": {
"Authorization": "Bearer " + accessToken,
"Accept": "application/json",
},
}
var response2 = UrlFetchApp.fetch(url2, options2);
// console.log(response2.getContentText()); // for debug.
var { download_url, status } = JSON.parse(response2.getContentText());
while (status == "pending") {
Utilities.sleep(5000); // Please adjust this value. The current wait time is 5 seconds.
response2 = UrlFetchApp.fetch(url2, options2);
// console.log(response2.getContentText()); // for debug.
var obj = JSON.parse(response2.getContentText());
status = obj.status;
download_url = obj.download_url;
}
if (!download_url) {
throw new Error("download_url has no value.");
}
// 3rd request
var options3 = {
"headers": {
"Authorization": "Bearer " + accessToken,
"Accept": "application/octet-stream",
},
}
var response3 = UrlFetchApp.fetch(download_url, options3);
var blob = response3.getBlob().setContentType("application/zip");
var csvs = Utilities.unzip(blob);
// Create a new Spreadsheet and put the CSV data to the 1st tab.
var ss = SpreadsheetApp.create("sample Spreadsheet");
csvs.forEach((b, i) => {
var ar = Utilities.parseCsv(b.getDataAsString());
var sheet = i == 0 ? ss.getSheets()[i] : ss.insertSheet("sample" + (i + 1));
sheet.getRange(1, 1, ar.length, ar[0].length).setValues(ar);
});
}
I'm not sure whether the downloaded the gzip file has the correct mimeType. So I added the mimeType like var blob = response3.getBlob().setContentType("application/x-gzip").
Note:
When this script is run, the flow of your showing question is done. But, I cannot test this API because I have no account. So, when an error occurs, please check each value and your access token again. And, please provide the error message. By this, I would like to confirm it.
I thought that the value of download_url returned from the 1st request might be the same with the value of download_url returned from 2nd request. But, I cannot test this API because I have no account. So, please check it, and when my understanding is correct, you can modify the above script.
This sample script creates a new Spreadsheet. But, if you want to put the CSV data to the existing Spreadsheet, please modify the above script.
Reference:
fetch(url, params)

Api call works with curl but not with google apps script, what am I missing? [duplicate]

This question already exists:
How to convert this curl example to google apps script / javascript? [duplicate]
Closed 1 year ago.
So this part works:
function authenticateToggl()
{
url = "https://api.track.toggl.com/api/v8/me";
//Put it all together.
var options =
{
'method' : 'get',
'headers' : {"Authorization": 'Basic ' + Utilities.base64Encode('email#gmail.com:mypassword')},
};
//Make Login call to When I work.
var responseGetPlan = UrlFetchApp.fetch(url, options);
var strResponseGetPlan = responseGetPlan.getContentText();
Logger.log('Get Plan Response: ' + strResponseGetPlan); //Log response.
var parsedData = JSON.parse(strResponseGetPlan); //Parse into JSON format.
var strId = parsedData.data.api_token;
return strId;
}
That returned me a string api token, which I can use in api curl calls like this:
curl -v -u c8f4c3TOKENe5a580bfeab:api_token -X GET https://api.track.toggl.com/api/v8/workspaces/1001455/projects
Doing that I appropriately got back my list of projects per the api docs.
But when I tried to translate that into google apps script, it fails. I'm sure it is that my header is formatted wrong?
function nextStep(){
UrlFetchApp.fetch('https://api.track.toggl.com/api/v8/workspaces/1001455/projects', {//
'headers': {'Authorization': "Basic c8f4c3TOKENe5a580bfeab:api_token"},
'method':'get'
});
}
I get back a 403 authentication error. Does the word basic not apply here? using the same url, method, and token.
It seems you need to convert your string token to base64 encoding,
function nextStep(){
//API Key requires base64 encoding. Use Google Apps Scripts built in method
var base64token = Utilities.base64Encode("c8f4c3TOKENe5a580bfeab:api_token");
UrlFetchApp.fetch('https://api.track.toggl.com/api/v8/workspaces/1001455/projects', {
'headers': {'Authorization': "Basic "+base64token},
'method':'get'
});
}
Additional References:
Github - Google-Apps-Scripts-Toggl-Request
Github - toggl-appscript

Uploading from Google Drive to BOX through AppScript

Currently working on a google sheet and implementing a script that will upload a file from Drive to BOX .
I got the authentication down (I am able to get the folder list through the script connecting to the API) but when I get to the uploading part, I am getting an empty request and the file is not getting uploaded to the target folder
My script below:
function uploadFile() {
var boundary = "test";
var blob = DriveApp.getFileById('<I got my file ID here>').getBlob();
var service = getService();
var attributes = "{\"name\":\"test document.pdf\", \"parent\":{\"id\":\"<I got my folder ID here>\"}}";
var requestBody = Utilities.newBlob(
"--"+boundary+"\r\n"
+ "Content-Disposition: form-data; name=\"attributes\"\r\n\r\n"
+ attributes+"\r\n"+"--"+boundary+"\r\n"
+ "Content-Disposition: form-data; name=\"file\"; filename=\""+blob.getName()+"\"\r\n"
+ "Content-Type: " + blob.getContentType()+"\r\n\r\n").getBytes()
.concat(blob.getBytes())
.concat(Utilities.newBlob("\r\n--"+boundary+"--\r\n").getBytes());
var options = {
method: "post",
contentType: "multipart/form-data; boundary="+boundary,
payload: requestBody,
muteHttpExceptions: true,
headers: {'Authorization': 'Bearer ' + service.getAccessToken()}
};
var request = UrlFetchApp.fetch("https://upload.box.com/api/2.0/files/content", options);
Logger.log(request.getContentText()); // empty response
}
Thanks
Modification points:
When I check the official document of "Upload file" of the BOX API, I found the following curl sample. Ref
$ curl -i -X POST "https://upload.box.com/api/2.0/files/content" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: multipart/form-data" \
-F attributes="{"name":"Contract.pdf", "parent":{"id":"11446498"}}" \
-F file=#<FILE_NAME>
When the request of multipart/form-data is run, it seems that at Google Apps Script, the content type is automatically created including the boundary.
When above curl command is converted to Google Apps Script, it becomes as follows.
Modified script:
function uploadFile() {
var blob = DriveApp.getFileById('<I got my file ID here>').getBlob();
var service = getService();
var attributes = {"name":"test document.pdf", "parent":{"id":"<I got my folder ID here>"}};
var requestBody = {attributes: Utilities.newBlob(JSON.stringify(attributes), "application/json"), file: blob};
var options = {
method: "post",
payload: requestBody,
muteHttpExceptions: true,
headers: {'Authorization': 'Bearer ' + service.getAccessToken()}
};
var request = UrlFetchApp.fetch("https://upload.box.com/api/2.0/files/content", options);
Logger.log(request.getContentText());
}
Note:
In this sample script, it supposes that your access token of service.getAccessToken() can be used for uploading the file using the API. Please be careful this.
References:
Upload file of BOX API
fetch(url, params)

Sheets & Appscripts Hubspot POST Request with Authentication Token Problem

I've created a GAS app to provide better pipeline reporting from our Hubspot instance. So far the app works and I have successfully created a Sales Pipeline that shows up in Google sheets. I am trying to add a capability that requires a POST method to query Hubspot's CRM V3. I got it to work in Postman but cannot replicate it in GAS.
The error I get is "Authentication credentials not found." The headers print to the log so I assume they are being generated properly. My guess is that my access Token and payload are not being passed properly to the API during the request. Any help on the matter would be much appreciated.
function getConversions() {
// Prepare authentication to Hubspot
var service = getService();
var headers = {headers: {'Authorization': 'Bearer ' + service.getAccessToken()}};
Logger.log(headers);
var raw = JSON.stringify({"filterGroups":[{"filters":[{"propertyName":"hs_analytics_last_visit_timestamp","operator":"GT","value":"1561514165666"}]}],"limit":100,"after":0});
var options = {
'method' : 'post',
headers: headers,
'contentType': 'application/json',
// Convert the JavaScript object to a JSON string.
body : raw,
redirect: 'follow',
"muteHttpExceptions": true
};
var response = UrlFetchApp.fetch('https://api.hubapi.com/crm/v3/objects/contacts/search?', options);
var result = JSON.parse(response.getContentText());
Logger.log(result);
};
How about this modification?
Modification points:
When I checked the official document of Search of HubSpot API, I found the curl sample. When this sample is converted to Google Apps Script, I noticed several modification points in your script.
UrlFetchApp.fetch has no properties of body and redirect.
About followRedirects, the official document says as follows.
If false the fetch doesn't automatically follow HTTP redirects; it returns the original HTTP response. The default is true.
In your URL, https://api.hubapi.com/crm/v3/objects/contacts/search? is used. If you don't use the API key, how about modifying to https://api.hubapi.com/crm/v3/objects/contacts/search?
When above modification is reflected to your script, it becomes as follows.
Modified script:
Please modify as follows.
From:
var options = {
'method' : 'post',
headers: headers,
'contentType': 'application/json',
// Convert the JavaScript object to a JSON string.
body : raw,
redirect: 'follow',
"muteHttpExceptions": true
};
To:
var options = {
method : 'post',
headers: headers,
contentType: 'application/json',
payload : raw,
muteHttpExceptions: true
};
Note:
Above modification is required for your script. But I'm worry about the error of Authentication credentials not found.. In this modification, it supposes that your access token of service.getAccessToken() can be used for this request. When I saw the official document, the API key can be also used. If the access token cannot be used, how about using the API key? It's like below.
https://api.hubapi.com/crm/v3/objects/contacts/search?hapikey=YOUR_HUBSPOT_API_KEY
References:
Search of HubSpot API
fetch(url, params)
function getConversions() {
// Prepare authentication to Hubspot
var service = getService();
var headers = {headers: {'Authorization': 'Bearer ' + service.getAccessToken()}};
var url = 'https://api.hubapi.com/crm/v3/objects/contacts/search'
//Logger.log(headers);
var raw = {"filterGroups":[{"filters":[{"propertyName":"hs_analytics_last_visit_timestamp","operator":"GT","value":"1561514165666"}]}],"limit":100,"after":0};
var options = {
method : 'post',
contentType: "application/json",
// Convert the JavaScript object to a JSON string.
payload : JSON.stringify(raw),
muteHttpExceptions: true
};
var response = UrlFetchApp.fetch('https://api.hubapi.com/crm/v3/objects/contacts/search?hapikey=myapikey',options);
var result = JSON.parse(response.getContentText());
Logger.log(response)
Logger.log(result);
};