UrlFetchApp function truncates my api json call - google-apps-script

This is the code I am running to grab assignments from the Canvas LMS API.
var response = UrlFetchApp.fetch(canvas_link + "api/v1/courses?access_token="+api_key+"&enrollment_state=active");
var courses = JSON.parse(response.getContentText());
var assignments = UrlFetchApp.fetch(canvas_link + "api/v1/courses/" + courses[3].id + "/assignments?access_token="+api_key)
var assignmentsArray = JSON.parse(assignments)
It grabs the cources using an api key then requests assignments for those courses using the course id. Everytime I get the error that it Truncated my output. The assignmentsArray always returns a length of 10 when I know that there is more assignments in the course. And it will return less than 10 if there is less than 10 assignments.
I have tried using the UrlFetchApp.getRequest() function to get the request and put that into my browser it works and returns json for all the assignments.
I have tried adding headers and other options the the options for the UrlFetchApp.fetch(url, options) to see if they did anyting, but it didn't work.

Related

how to use nextPageToken

I have a script that archives old classrooms, until the end of 2021 it was working fine.
In the lasts months I got an error (the script works ok, but terminate with error) and today I was investigating it, the script runs only once per month.
The error is due to a supposed change in .nextPageToken function.
var parametri = {"courseStates": "ARCHIVED"};
var page = Classroom.Courses.list(parametri);
var listaClassi = page.courses;
var xyz = page.nextPageToken;
if (page.nextPageToken !== '') {
parametri.pageToken = page.nextPageToken;
page = Classroom.Courses.list(parametri);
listaClassi = listaClassi.concat(page.courses);
};
var xyz has been added to better understand what was happening.
So, in this case the list does not have pagination, is only one page. var xyz returns "undefined", and the "if" statement results "true", this makes that variable listaClassi got appended the same content a second time. That generate the error and the abnormal end of the script.
I found an issue reported here https://issuetracker.google.com/issues/225941023?pli=1 that may be related with my problem.
Now I could change .nextPageToken with .getNextPageToken but I found no docs on the second function and many issues reporting that is not working, can anyone help me?
When using the nextPageToken value obtained to the response make sure to enter it as a separate parameter with a slightly different name. You will obtain nextPageToken in the response, the pageToken parameter needs to be entered in the request. It does look like you are doing it right, the way you add the parameter is a bit odd, yet it should be functional.
To discard problems with the Classroom API (that we can certainly take a look at) try with this simple code example in a new Google Apps Script project, remember you will need to add an Advanced service, information about advanced services can be found in this documentation article https://developers.google.com/apps-script/guides/services/advanced. Use listFiles as the main method in your Apps Script project.
function listFiles() {
var totalClasses = 0;
nextPageToken = "";
console.log("Found the following classes:")
do {
var response = loadPage(nextPageToken);
var classes = response.courses;
for (let x in classes){
console.log("Class ID: " + classes[x].id + " named: '" + classes[x].name + "'.");
}
totalClasses += classes.length;
} while (nextPageToken = response.nextPageToken)
console.log("There are " + totalClasses + " classes.")
}
function loadPage(token = ""){
return Classroom.Courses.list({
fields: 'nextPageToken,courses(id,name)',
pageSize: 10,
pageToken: token
});
}
When we first make the API call with Apps Script we don't specify a pageToken, since it is the first run we don't have one. All calls to the List method may return a nextPageToken value if the returned page contains an incomplete response.
while (nextPageToken = response.nextPageToken)
In my code at the line above once response.nextPageToken is empty (not in the response) inside the condition block JavaScript will return false, breaking the loop and allowing the code to finish execution.
To have your incident reviewed by a Google Workspace technician you can also submit a form to open a ticket with the Google Workspace API Support team at https://support.google.com/a/contact/wsdev.

Delay in between two calls (POST and GET) in Google Apps script

My first request on StackOverflow! I really hope you can help me!
I want to create a process to automatize a data report from a system to a sheet; I thought I could use their API, apps script, and export the data on google sheets.
To do so, I need to run two calls on the API:
A POST call, which runs the report within the system (it requires a date range as body).
In return, I will get an ID that is associated with the data generated and it expires after some time.
A GET call, which is a URL that contains the ID generated in the first call and created with a concatenation.
The first call works fine; I get in return the ID successfully.
My problem is when I run the second call, I don’t get any data in return, and I don’t understand what’s the issue, I can see the URL is concatenated correctly because if I copy the URL from the log and I test it on another apps script or on Postman, it works perfectly fine!
Could someone help me in case I am doing something wrong?
Here’s the code:
function callEvents() {
var API_KEY = "xxx";
var data = { 'Start Date': '2021-05-03', 'End Date': '2021-06-03' }
var options = {
'method' : 'post',
'contentType': 'application/json',
'payload' : JSON.stringify(data) };
//This is the first call
var urlEncoded = encodeURI('https://website/api/dataviewresult/
etc/json/?api_key=' + API_KEY);
var url = UrlFetchApp.fetch(urlEncoded, options);
var result = JSON.parse(url.getContentText());
Logger.log(url.getContentText());
//here I retrieve the ID to use in the second call
var ipdataview = (result["contents"]["id"]);
Logger.log(ipdataview);
//here is the concatenation and the second call
var urlEncoded2 = encodeURI('https://website/api/dataviewresult/etc/json/'+ipdataview+'/?api_key=' + API_KEY);
Logger.log(urlEncoded2);
var response = UrlFetchApp.fetch(urlEncoded2);
Logger.log(response.getContentText());
I found out the solution, I was doing the second call (Get) too soon from the first one, so the data was not being picked up.
I used utilities.sleep() for about 2 seconds and it worked perfectly.
Thank you for everyone helping!
S

How to get the currency information from this site

I'm trying to bring to my google sheets the currency information from the site:
https://www.bbva.mx/personas/informacion-financiera-al-dia.html
I'm trying to use IMPORTHTML and IMPORTXML but none of this is working for me
The information I need is this
Any help on this please ???
Maybe using Apps scripts ?
Edit:
this is the code im using
function fetchData() {
var url = 'https://www.bbva.mx/personas/informacion-financiera-al-dia.html';
var dolarTable = UrlFetchApp.fetch(url).getContentText();
Logger.log(dolarTable)
var match = dolarTable.match(/Dólar(.*)\s+(.*)\s+(.*)\s+(.*)\s+(.*)\s+(.*)\s+(<\/tr>)/);
var string = match[0].replace(/(\r\n|\n|\r)/gm," ");
string = string.replace(/\s/g, "");
var dollar = string.search("\\$");
var value = string.indexOf("$", dollar + 1);
var substrings = string.substring(value);
var almostThere = substrings.substring(0).indexOf("<");
var number = substrings.substring(0, almostThere);
return SpreadsheetApp.getActiveSpreadsheet().getSheets[0].getRange('A1').setValue(number);
}
getting this error
Regular expression operation exceeded execution time limit (line 5, file "Code")
Okay so the problem you're running into here is that while in Sheets, the IMPORTHTML and IMPORTXML Imports data from a table or list within an HTML page, the webpage you're trying to access is using active server scripts to generate the HTML content.
In Apps Script, there is a built-in UrlFetchApp class which you can use to get HTML data - it has its own limitations, but allows you to get the data from a page into your script for usage.
The page you're trying to get uses a frame that contains an .aspx file, and it's this generated content that has the information you're trying to retrieve. Honestly, this solution is a little ad-hoc as I've used UrlFetchApp.fetch() to get the data, then used regular expressions and built-in JavaScript string functions to get the information out as generically as I can:
function fetchData() {
var dolarTable = UrlFetchApp.fetch('https://bbv.infosel.com/bancomerindicators/indexv8.aspx').getContentText();
var match = dolarTable.match(/Dólar(.*)\s+(.*)\s+(.*)\s+(.*)\s+(.*)\s+(.*)\s+(<\/tr>)/);
var string = match[0].replace(/(\r\n|\n|\r)/gm," ");
string = string.replace(/\s/g, "");
var dollar = string.search("\\$");
var value = string.indexOf("$", dollar + 1);
var substrings = string.substring(value);
var almostThere = substrings.substring(0).indexOf("<");
var number = substrings.substring(0, almostThere);
SpreadsheetApp.getActiveSpreadsheet().getSheets()[0].getRange('A1').setValue(number);
}
This will fetch the HTML data of the page, then reduce what you're looking for by substring filtering. I've kept it generic so as long as the structure of the page doesn't change too much, it should still work even if the value of the amount changes.

How to appendRow (or write data more generally) to Google Sheets from a custom function

I've written a custom function [=ROUTEPLAN(origin,destination,mode,departuretime)] in the Google Sheets script editor. The function assigns a unique ID to the request, calls the Google Maps Directions API, passes as params the arguments as listed in the function, parses the JSON and extracts the duration, end latitude and end longitude for each step of the journey, and then appends a row for each step, with the request ID for the whole journey, the sequential step number, the duration, end latitude and end longitude:
function ROUTEPLAN() {
//Call the google route planner api
//(variables for api declared here but removed for brevity)
var routeResponse = UrlFetchApp.fetch("https://maps.googleapis.com/maps/api/directions/json?origin=" + origin
+ "&destination=" + destination
+ "&mode=" + mode +
"&region=uk&departure-time=" + departuretime
+ "&key=MYAPIKEY")
//Assign a unique ID to this request
var requestID = Date.now() + Math.random();
//Parse JSON from routeResponse
var json = routeResponse.getContentText();
var data = JSON.parse(json);
//Insert the RequestID, step number, duration, end Latitude and end Longitude for each step of the journey into the RouteDetails sheet
var steps = data["routes"][0]["legs"][0]["steps"];
for (i = 0; i < steps.length; i++) {
var stepID = i + 1;
var duration = steps[i]["duration"]["value"];
var endLat = steps[i]["end_location"]["lat"];
var endLng = steps[i]["end_location"]["lng"];
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("RouteDetails")
sheet.appendRow([requestID,stepID,duration,endLat,endLng]);
}
}
Or at least that's what I want it to do. It worked fine until I tinkered with it, and now I'm getting an ERROR when I call the function in the spreadsheet, telling me I don't have permission to call appendRow. I know why this is happening (although I don't understand why it wasn't happening before), but I cannot work out what I'm supposed to do about it.
If appendRow exists, there must be some circumstance in which it can be used to write data the sheet, but I can't figure out the circumstances in which permission to write to the sheet would be granted.
The purpose of the sheet is to provide data to a chatbot (the chatbot app has read & write permissions to the sheet). I'm not intending to provide access beyond that (i.e. i'm not intending to publish this for wider use). I've tried going down the installable trigger route, but despite following all the instructions that made absolutely no difference to the outcome. From the limited understanding I gained from reading about API Executables, that doesn't seem to be an option either.
Can anyone tell me how to solve this? Thank you :-)
A custom function can not modify the structure of the spreadsheet, so calling appendRow() is not allowed as stated in the documentation:
A custom function cannot affect cells other than those it returns a value to. In other words, a custom function cannot edit arbitrary cells, only the cells it is called from and their adjacent cells. To edit arbitrary cells, use a custom menu to run a function instead
If you want to return multiple rows from your function, it needs to return a two dimensional array. Note however that custom functions have the same limitation as native functions of not being able to overwrite content i.e. if you try to return two rows but the row below is already filled the function will error out.

Google geocoding returns zero results, Unity3D

I am trying to connect to google maps api and get lant/long of place, but no matter what I'm trying to get, I receive ZERO_RESULTS every time. For example if I type
http://maps.googleapis.com/maps/api/geocode/json?address=Moscow+Tverskaya+18 into browser, it gives me correct result, but if I'm trying to send the exact same string via WWW class from unity I get zero results.
IEnumerator GetGoogleCoords() {
var url = "http://maps.googleapis.com/maps/api/geocode/json?";
var qs = "";
// qs += "address=" + savedAddress;
qs += "address=Moscow +Tverskaya+18";
var req = new WWW(url + "?" + qs);
Debug.Log(url + qs);
yield return req;
Debug.Log(req.text);
}
I tried every request and in every order
You have an extra "?" in your url as #Engerlost said.
This post is about how to prevent doing similar mistakes again.
Best programming practice would be to build the full url not in WWW constructor but in a separate line.
var url = "http://maps.googleapis.com/maps/api/geocode/json?";
var qs = "address=Moscow +Tverskaya+18";
var fullUrl = url + "?" + qs
var request = new WWW(fullUrl);
That is, one line should contain only one job. Which makes it much easier to manage the code. In your case, it gets much easier to debug and see there is an error building the full url. Now you are able to easily add a Debug.Log if you suspicious about final url which goes into WWW as parameter.
Debug.Log("Request url: " + fullUrl);
And you would easily see the resulting url contains two "?" characters.