Error handling - retry urlfetch on error until success - google-apps-script

I've looked at all the relevant questions here (such as this), but still cannot make sense of this VERY simple task.
So, trying to verify numbers using the NumVerify API. We're still on the free license on APILAYER so we're getting the following error from time to time
Request failed for https://apilayer.net returned code 500
I'd like to add a loop so that the script will try again until a proper response is received.
Here is a snippet based on several answers here:
function numverifylookup(mobilephone) {
console.log("input number: ",mobilephone);
var lookupUrl = "https://apilayer.net/api/validate?access_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&number="+mobilephone+"&country_code=IL";
try {
var response = UrlFetchApp.fetch(lookupUrl);
if (response) {//Check for truthy value
var json = response.getContentText();
} else {
Utilities.sleep(2000);
continue;//If "get" returned a falsy value then continue
}
} catch(e) {
continue;//If error continue looping
}
var data = JSON.parse(response);
Sadly, still not working due to the following error:
Continue must be inside loop. (line 10
Any thoughts?
I think it's actually better to solve this using muteHTTPexepctions but couldn't quite make it work.
Thanks!

I think I got this to work as below:
function numverify(mobilephone);
console.log("input number: ",mobilephone);
var lookupUrl = "https://apilayer.net/api/validate?access_key=XXXXXXXXXXXX&number="+mobilephone+"&country_code=IL";
var i = 0;
var trycount = 1;
var errorcodes = "";
while (i != 1) {
var response = UrlFetchApp.fetch(lookupUrl, {muteHttpExceptions: true });
var responsecode = response.getResponseCode();
var errorcodes = errorcodes + "," + responsecode;
if (responsecode = 200) {//Check for truthy value
var json = response.getContentText();
var i = 1
} else {
var trycount = trycount + 1;
Utilities.sleep(2000);
}
}
var data = JSON.parse(response);
var valid = data.valid;
var localnum = data.local_format;
var linetype = data.line_type;
console.log(data," ",valid," ",localnum," ",linetype," number of tries= ",trycount," responsecodes= ", errorcodes);
var answer = [valid,localnum,linetype];
return answer;
}
I'll circle back in case it still doesn't work.
Thanks for helping!

You cannot use continue to achieve what you want, instead you can / need to call the function again:
function numverifylookup(mobilephone) {
console.log("input number: ", mobilephone);
var lookupUrl = "https://apilayer.net/api/validate?access_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&number=" + mobilephone + "&country_code=IL";
try {
var response = UrlFetchApp.fetch(lookupUrl);
if (response) {//Check for truthy value
var json = response.getContentText();
} else {
Utilities.sleep(2000);
numverifylookup(mobilephone);
}
} catch (e) {
Utilities.sleep(2000);
numverifylookup(mobilephone);//If error rerun the function
}
var data = JSON.parse(response);
}
As you can draw from the documentation the statement continue can only be used inside of loops, like e.g. the for loop.

Related

Google App Scripts / TwitterLib getting error Exception when trying to post a tweet

Trying to implement TwitterLib to send tweets from Google Sheets. I am using Google App Scripts, and the following code -
var sheet = SpreadsheetApp.getActive().getSheetByName('View');
var startRowNumber = 1;
var endRowNumber = sheet.getLastRow();
function sendTweets() {
var twitterKeys = {
TWITTER_CONSUMER_KEY: "xxxxxxxxxxxxxxxxxxx",
TWITTER_CONSUMER_SECRET: "xxxxxxxxxxxxxxxxxxx",
TWITTER_ACCESS_TOKEN: "xxxxxxxxxxxxxxxxxxx",
TWITTER_ACCESS_SECRET: "xxxxxxxxxxxxxxxxxxx"
}
var props = PropertiesService.getScriptProperties();
props.setProperties(twitterKeys);
var params = new Array(0);
var service = new Twitterlib.OAuth(props);
var quote;
var identifier;
for (var currentRowNumber = startRowNumber; currentRowNumber <= endRowNumber; currentRowNumber++) {
var row = sheet.getRange(currentRowNumber + ":" + currentRowNumber).getValues();
// check that the second column (Date) is equal to today
if (isToday(row[0][1])) {
quote = row[0][0];
identifier = currentRowNumber - 1;
if (!service.hasAccess()) {
console.log("Authentication Failed");
} else {
console.log("Authentication Successful");
var status = quote + "\n\n" + "#Quotes #Motivation";
try {
var response = service.sendTweet(status, params);
console.log(response);
} catch (e) { console.log(e) }
}
break;
}
}
}
function isToday(date) {
var today = new Date();
var dateFromRow = new Date(date);
return dateFromRow.getDate() == today.getDate() &&
dateFromRow.getMonth() == today.getMonth() &&
dateFromRow.getFullYear() == today.getFullYear()
}
I have signed up for Twitter DEV and have my API Key and Secret (CONSUMER_KEY and CONSUMER_SECRET above) and Access Token and Access Secret as well. I have turned on OAuth 1.0a, Read and write and Direct Message selected, and a Callback URI of (https://script.google.com/macros/s/YOUR_SCRIPT_ID/usercallback) - Replacing YOUR_SCRIPT_ID with the actual one I have.
I am seeing an Authentication Successful message in my Console, but seeing this error when running inside Apps Scripts IDE:
Send tweet failure. Error was: {"name":"Exception"}
Nothing more. I am not sure what else to check to see what I am doing wrong. Any help or resources to read over would greatly be appreciated! Thank you so much!
JJ

Data Studio Connector getData() not running

I can't seem to get the getData() function to run on this connector I'm building. Data studio displays my Schema properly, however when I go to 'explore' the data, an error is thrown. Looking in the project executions, the 'getData' function never runs at all.
Data Studio has encountered a system error.
Sorry, we encountered an error and were unable to complete your request.
There's no debug errors shown, and I'm not sure how to continue debugging this.
Here is my code...
var cc = DataStudioApp.createCommunityConnector();
function isAdminUser(){
return true
}
function responseToRows(requestedFields, response){
return response.map(function(item) {
var row = [];
requestedFields.asArray().forEach(function(field){
var id = field.getId()
row.push(item[id])
});
console.log(row);
return { values: row };
});
}
function getAuthType() {
var response = { type: 'NONE' };
return response;
}
function getConfig(){
var json = UrlFetchApp.fetch("<api-url>");
var data = JSON.parse(json);
var config = cc.getConfig();
var tables = data.TableNames
var configElement = config
.newSelectSingle()
.setId('tables')
.setName("Choose your data source")
.setHelpText('Choose your data source');
for(i=0;i<tables.length;i++){
configElement
.addOption(config.newOptionBuilder().setLabel(tables[i]).setValue(tables[i]))
}
return config.build();
}
function getSchema(request){
var fields = cc.getFields();
var types = cc.FieldType;
var table = request.configParams.tables;
var data = UrlFetchApp.fetch("<api-url>"+"?name="+table);
var itemArray = JSON.parse(data);
var singleRow = itemArray["Items"][0];
var keys = Object.keys(singleRow)
for(i=0;i<keys.length;i++){
var nestedKeys = Object.keys(singleRow[keys[i]])
var propName = keys[i];
var dataType = nestedKeys[0]
if(dataType == "S"){
fields.newDimension()
.setId(propName)
.setName(propName)
.setType(types.TEXT)
}else if (dataType == "N"){
fields.newMetric()
.setId(propName)
.setName(propName)
.setType(types.NUMBER)
}
}
console.log(fields.build());
console.log('get schema')
return { schema: fields.build() };
}
function getData(request){
var fields = cc.getFields();
console.log(fields);
console.log('getdata running');
// TODO: Create Schema for requested field
var table = request.configParams.tables;
var requestedFieldIds = request.fields.map(function(field) {
return field.name
});
var requestedFields = fields.forIds(requestedFieldIds);
// TODO: Fetch and Parse data from API
var response = UrlFetchApp.fetch("<api-url>"+"?name="+table);
var parsedResponse = JSON.parse(response)
// TODO: Transform parsed data and filter for requested fields
var rows = responseToRows(requestedFields, parsedResponse)
return {
schema: requestedFields.build(),
rows: rows
}
}
To see debug traces, you could simply log it with console.log() and take a look at your logs in the Google Apps Scripts dashboard :
https://script.google.com/home/executions
I don't know if this is related to your problem, but in my case I was trying to use URL Parameters and getData(request) wouldn't run no matter what values I input - it ended up being that I had to create a production deployment and Publish > Deploy from Manifest and then create an actual published version (not just FROM HEAD).

How to test my google script URL as deploy web app for two data?

I would like to discuss with anyone here regarding my problem.
My problem is that, I cannot successfully test my code.gs in google script with two data when I deploy it as web app. When I test it only one data it say 'Ok', but when I try to test adding a second data it say 'unsupported parameter'.
When I deploy the script as web app, the link is as below:
https://script.google.com/macros/s/AKfycbyXlCLBDNzJGXWNkrEHtWP0jaxnpvX0dPUnXjwilioUd7up-SU/exec
how can I test it?
Is it like,
[1]
https://script.google.com/macros/s/AKfycbyXlCLBDNzJGXWNkrEHtWP0jaxnpvX0dPUnXjwilioUd7up-SU/exec?BBTTempData=32.56&RTtempData=25.6
or
[2]
https://script.google.com/macros/s/AKfycbyXlCLBDNzJGXWNkrEHtWP0jaxnpvX0dPUnXjwilioUd7up-SU/exec?BBTTempData=32.56/RTtempData=25.6
My code is just like below:
function doGet(e) {
Logger.log( JSON.stringify(e) ); // view parameters
var result = 'Ok'; // assume success
if (e.parameter == undefined) {
result = 'No Parameters';
}
else {
var id = '<mygooglespreadsheet_id>'; //docs.google.com/spreadsheetURL/d
var sheet = SpreadsheetApp.openById(id).getActiveSheet();
var newRow = sheet.getLastRow() + 1;
var rowData = [];
rowData[0] = new Date(); // Timestamp in column A
for (var param in e.parameter) {
Logger.log('In for loop, param='+param);
var value = stripQuotes(e.parameter[param]);
//Logger.log(param + ':' + e.parameter[param]);
switch (param) {
case 'BBTTempData': //Parameter
rowData[1] = value; //Value in column B
break;
case 'RTtempData':
rowData[2] = value;
break;
default:
result = "unsupported parameter";
}
}
Logger.log(JSON.stringify(rowData));
// Write new row below
var newRange = sheet.getRange(newRow, 1, 1, rowData.length);
newRange.setValues([rowData]);
}
// Return result of operation
return ContentService.createTextOutput(result);
}
function stripQuotes( value ) {
return value.replace(/^["']|['"]$/g, "");
}
The code, I get it in YouTube https://www.youtube.com/watch?v=tWTv4-QUQ0E.
A discussion is good for me.
Thanks.
Using 2 parameters you should use BBTTempData=32.56&RTtempData=25.6 I've tested this and it works fine for me. Perhaps you need to re-deploy the web app to get it to work if you've been making changes to the code.

Why "Unexpected Error" on UrlFetchApp GAS

My code has an issue when run by trigger but running manually is ok.
i have the following function
var url = "https://api.facebook.com/method/links.getStats?urls="+links+"&format=json";
var getParams = {
"method": "get",
"validateHttpsCertificates":false,
"accept": "application/json",
"muteHttpExceptions": true
};
var stats = UrlFetchApp.fetch(url,getParams);
Utilities.sleep(3000);
var cont = JSON.parse(stats.getContentText());
Running by trigger it logs "Unexpected Error"
according to my research i found that is an usual issue, i read that the rules to run manually are diferent than by trigger (even the ip are diferent)
"Apps Script uses two different UrlFetchApp pipelines: one for when the code is run by a user and one for when the code is run by a trigger. The trigger pipeline has some slightly different rules, which is why you are occasionally seeing these errors."
Well i think this is a serious issue and if google do it on purpose to regulate Fetch calls, i think is an offense for users and basically should not exist trigger service.
Any idea for the Solution?
I am found a posible temporal solution:
Util.fetchJSON = function (url) {
var maxTries = 3;
var tries = 0;
var res, body;
do {
tries++;
if (tries > 1) {
Utilities.sleep(1000);
Logger.log('GET %s (try #%s)', url, tries);
} else {
Logger.log('GET %s', url);
}
res = UrlFetchApp.fetch(url);
body = res.getContentText();
} while (!body && (tries < maxTries));
if (!body) {
throw new Error('Unable to fetch JSON after ' + tries + ' attempts: ' + url);
}
return JSON.parse(body);
};
But i dont know how to apply it to my original function: (help)
(this is a part of my original function)
function soyEspiritual() {
do {
try {
var pipe = "http://pipes.yahoo.com/pipes/pipe.run?_id=888ed60ff6a5ee79c05ec6963f6d3efe&_render=json";
var pipedata = UrlFetchApp.fetch(pipe,{method:"get"});
Utilities.sleep(3000);
var object = JSON.parse(pipedata.getContentText());

Get data from webpage using Google Apps Script and Yahoo Query Language

Using Google Apps Script, I've written the following function to extract a piece of information to a spreadsheet:
function myFunction(symbol, elemento) {
var url = "http://www.example.com/query?symbol=" + symbol;
switch (elemento) {
case 'one':
var xpath='//*[#id="sectionTitle"]/h1';
break;
case 'two':
var xpath='//*[#id="headerQ"]/div[1]/div/span[2]'
break;
}
var query = "select * from html where url = '" + url + "' and xpath = '" + xpath + "'";
var yql = "https://query.yahooapis.com/v1/public/yql?format=json&q=" + encodeURIComponent(query);
var response = UrlFetchApp.fetch(yql);
var json = JSON.parse(response.getContentText());
switch(elemento){
case 'one':
return json.query.results.h1;
break;
case 'two':
return ponto(json.query.results.span.content);
break;
}
}
Now, this works OK when typing the function into a cell, but "sometimes" I get the error #ERROR! in a cell with the note:
TypeError: Can't read "h1" property of null. (line 54).
Deleting that cell and typing the function again usually works.
Why is this function volatile (ie: it does work, but only sometimes)?
You will need to do some error checking with your fetch. Any request over the internet may fail.
If no results are found the results object value will be null. I put in a quick backoff, but you may need to play with the numbers to suit your needs.
var response = UrlFetchApp.fetch(yql);
var json = JSON.parse(response.getContentText());
var backoff = 1;
while((json.query.results == null || response.getResponseCode() != 200)){
Utilities.sleep((Math.pow(2,backoff)*1000) + (Math.round(Math.random() * 1000)));
response = UrlFetchApp.fetch(yql);
json = JSON.parse(response.getContentText());
backoff++;
}