I recently started using Google Apps Script to automate some Google Analytics reporting tasks. Many objects returned by Google Analytics Services have 'get' functions that return a URL in the form of a string. Actually, many Google Apps Script objects have functions that return these resource URLs, not just Google's Analytics Services. The indication is that I can somehow use these URLs to reference Google Apps resources and get objects in return, but I don't know how.
I tried simply loading one of these URLs in a browser expecting JSON or something else I could use, but received a 404 error instead. The same happened when I tried requesting the URL using a Google Apps Script UrlFetchApp.
Here's a simple example:
var accountId = '0123456789'; // Pretend this is a valid account number
// Get the first WebProperty
var webProp = Analytics.Management.Webproperties.list(accountId).getItems()[0];
// ...getHref() is along the lines of "https://www.googleapis.com/analytics/v3/management/accounts/0123456789"
var parentHref = webProp.getParetLink().getHref();
The question is, what do I do with parentHref to get an Analytics Account object back? I feel like I'm missing something that should be fairly basic...
Resources:
Google Apps Script Reference for Analytics Services
Read Using OAuth 2.0 to Access Google APIs, will help you get what you need.
I add a very basic code that can serve as a guide.
/* CODE FOR DEMONSTRATION PURPOSES */
function authorizeGAS() {
var result = false;
var oauthConfig = UrlFetchApp.addOAuthService("google");
oauthConfig.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");
oauthConfig.setRequestTokenUrl("https://www.google.com/accounts/OAuthGetRequestToken?" +
"scope=https://www.googleapis.com/auth/analytics.readonly");
oauthConfig.setAuthorizationUrl("https://www.google.com/accounts/OAuthAuthorizeToken");
oauthConfig.setConsumerKey(ScriptProperties.getProperty("YOUR_ANALYTICS_CONSUMER_KEY"));
oauthConfig.setConsumerSecret(ScriptProperties.getProperty("YOUR_ANALYTICS_CONSUMER_SECRET"));
var requestData = {
"method": "GET",
"oAuthServiceName": "google",
"oAuthUseToken": "always"
};
var URL = "https://www.googleapis.com/analytics/v3/management/accounts/~all/webproperties/~all/profiles";
try {
result = JSON.parse(UrlFetchApp.fetch(URL, requestData).getContentText());
} catch (e) {
if (e.message) Logger.log(e.message);
}
Logger.log(result);
return result;
}
It's not about activating the API. It's obviously active since he is already getting analytics data.
You can't just urlfetch those URLs, because you are missing the OAuth-related code that goes with calling a URL that requires authentication and permission.
Related
I have the following code in Google Apps Script which retrieves CSV data from a webpage via HTTP using basic authentication and places it into a spreadsheet:
CSVImport.gs
function parseCSVtoSheet(sheetName, url)
{
// Credentials
var username = "myusername";
var password = "mypassword";
var header = "Basic " + Utilities.base64Encode(username + ":" + password);
// Setting the authorization header for basic HTTP authentication
var options = {
"headers": {
"Authorization": header
}
};
// Getting the ID of the sheet with the name passed as parameter
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getSheetByName(sheetName);
var sheetId = sheet.getSheetId();
// Getting the CSV data and placing it into the spreadsheet
var csvContent = UrlFetchApp.fetch(url, options).getContentText();
var resource = {requests: [{pasteData: {data: csvContent, coordinate: {sheetId: sheetId}, delimiter: ","}}]};
Sheets.Spreadsheets.batchUpdate(resource, spreadsheet.getId());
}
This has been working up until recently where randomly I get the following error on the UrlFetchApp.fetch line:
Exception: Unexpected error: http://www.myurl.com/data/myfile.csv (line 21, file "CSVImport")
I have tried:
Putting the credentials directly in the URL instead of in an Authorization header (I received a different error saying "Login information disallowed").
Encoding the credentials to base64 right when I pass it into the headers object (didn't work, same error).
Removing authentication altogether (predictably I received a 401 response from the HTTP page).
I'm not sure what else to try and why this randomly broke down all of a sudden. Any advice?
This is related to a new bug, see here
Many users are affected, I recommend you to "star" the issue to increase visibility and hopefully accelerate the process.
I had the same situation. At that time, I could noticed that when the built-in function of Google Spreadsheet is used for the URL, the values can be retrieved. In that case, as the current workaround, I used the following flow.
Put a formula of =IMPORTDATA(URL).
Retrieve the values from the sheet.
When above flow is reflected to your URL of http://www.myurl.com/data/myfile.csv, it becomes as follows.
About basic authorization for URL:
When I saw your script, I confirmed that you are using the basic authorization. In this case, the user name and password can be used for the URL like http://username:password#www.myurl.com/data/myfile.csv.
From your script, when the values of username and password are myusername and mypassword, respectively, you can use the URL as http://myusername:mypassword#www.myurl.com/data/myfile.csv.
Here, there is an important point. If the specific characters are included in username and password, please do the url encode for them.
Sample script:
function myFunction() {
const url = "http://myusername:mypassword#www.myurl.com/data/myfile.csv"; // This is your URL.
// Retrieve the values from URL.
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getSheetByName(sheetName);
sheet.clear();
var range = sheet.getRange("A1");
range.setFormula(`=IMPORTDATA("${url}")`);
// Retrieve the values from sheet to an array.
SpreadsheetApp.flush();
var values = sheet.getDataRange().getValues();
range.clear();
console.log(values)
}
When above script is run, the values from the URL are put to the sheet, and the values are retrieved as 2 dimensional array for values. If you want to leave only values without the formula, I think that you can copy and paste the values.
In this answer, I used IMPORTDATA. But for each situation, other functions might be suitable. In that case, please check them.
Note:
This is the current workaround. So when this issue was removed, I think that you can use your original script.
References:
IMPORTDATA
setFormula()
Disable Chrome V8 Runtime Engine until Google fix this.
To disable:
From Menu click on Run > Disable new Apps Script runtime powered by Chrome V8
As per #346 from the official issue tracker https://issuetracker.google.com/issues/175141974
hey guys I have found a possible solution that is working for me try
inputting empty {} like this
UrlFetchApp.fetch(apiLink, {});
it worked for me
I tried this, and it too is working for me. Works even when using the "new Apps Script runtime powered by Chrome V8".
I am working with Google Maps Javascript API & using places library. Although I am able to get the location address but I also need to get the location domain information like suppose if the location is a business & also has a website URL linked to that location. Can someone guide me to the right API or library that also provides the Domain information of a location ? So far I have not come across any.
Use places library to get other information as well
//make a request variable attaching the data you require , make sure to use only those which you require as detail request are billed separately
var request = {
query: 'yourquery',
fields: ['address_component', 'website']
};
service = new google.maps.places.PlacesService(map);
service.getDetails(request, callback);
//Here you get the result
function callback(place, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
var website = place.website; // get the website, may be empty
var type = place.address_component.types[0]; //this is an array and can be empty
}
}
I have an app, that links one service with Google Sheets by OAuth 1.0.
I click "login" in addon menu, send signature and callback domain (current sheet). Then in service I click on button, get request token and it returns me to the specified domain with parameters.
function onOpen(e)
{
Logger.log( SpreadsheetApp.getActiveSpreadsheet().getUrl() );
Logger.log( e.source.getUrl() );
}
But .getUrl() doesn't contain them.
According to >this< I can't use doGet(e) in Sheets and, because of OAuth, I can't use Web App, because I still need to pass these parameters to Sheets.
I tried to get it on client-side by window.top.location.href, but had cross-domain errors.
Question: Can I get it? Or is it impossible?
So, a partial answer to my question:
We need 2 different scripts. The first as Sheets web addon, the second as Web App. Next, we need to implement all the steps presented in the screenshot:
1) After steps 0, 1, 2 Service Provider should redirect us to Helper script (Web App) with the following code:
function doGet(e)
{
var token = e.parameter.oauth_token,
code = e.parameter.oauth_verifier,
response;
if(token && code && Root.setVerificationCode(token, code))
response = "Success";
else
response = 'Error';
return HtmlService.createHtmlOutput(response);
}
Here we retrieving GET parameters and send them to Sheets web addon (Root).
Click Resources -> Libraries and add your addon as library. Root is just an identifier.
2) Sheets addon code:
function setVerificationCode(token, code)
{
var oauth = new OAuth();
if(oauth.getAccessToken(code))
{
// change menu here
return true;
}
else
return false;
}
These are full steps you need to implement OAuth 1.0.
P.S. Now I have problems with changing menu, but it'll be my next question.
Trying out the Content Service API and the example is returning HTML when it should be returning JSON, what am I doing wrong?
https://developers.google.com/apps-script/guides/content
function doGet(request) {
var events = CalendarApp.getEvents(
new Date(Number(request.parameters.start) * 1000),
new Date(Number(request.parameters.end) * 1000));
var result = {
available: events.length == 0
};
return ContentService.createTextOutput(JSON.stringify(result))
.setMimeType(ContentService.MimeType.JSON);
}
GAS from another file trying to make the request:
function myFunction() {
var url = "published URL";
url+="?start=1325437200&end=1325439000";
var options = {
method:"get"
}
var response = UrlFetchApp.fetch(url,options).getContentText();
response = JSON.parse(response); //error, unexpected token <
}
Your usage of ContentService is correct, the code works exactly as is. Here is a link to my copy of your code published as a web app:
https://script.google.com/macros/s/AKfycbzx2L643LHw0oQAq1jBmKQh2ju_znGfmdj78dUypj36iF-s91w/exec
The problem you are running into is related to Authorization or Authentication, if the published script is not authorized, an HTML error message is returned.
To check if that is your issue, simply access the published URL directly in your browser. If you see JSON displayed, then Authorization is not the problem. If you see the "Authorization is required to perform that action" error message, open your published script and choose "doGet" from the Run menu, then follow the authorization prompts.
More likely, the problem is related to how your script is published. In order to access your published script from another script, it must be published with the "Who has access to the app" setting as "Anyone, Even anonymous". If you use any other value, Google returns an HTML login page instead of your JSON response, and you get the error you are seeing.
This happens because requests sent from Google Apps Script via URLFetchApp are not authenticated, they don't carry the credentials of the user running the code with them, and come in as anonymous requests.
If you don't allow "Anyone, even anonymous" in your publishing settings, Google redirects non-authenticated requests to the Google login page.
Here is the problem, I have a Google Chrome extension and I want to use the BOSS API in it. The problem is that I do not know if it is possible to use the API without a webserver running.
The documentation does not provide any example using JavaScript. Thus my question:
Is it possible to use the Yahoo BOSS OAuth with JavaScript only?
Probably not...
All the examples Yahoo provides are using server side languages
http://developer.yahoo.com/boss/search/boss_api_guide/codeexamples.html
First you'd have to figure out how to use OAuth with JavaScript, and how will you obscure your API keys from users in a JS File? If you don't have to worry about that, say you are just using this for personal use. Maybe check out the code sample for Node.JS and modify it for your own uses.
http://developer.yahoo.com/boss/search/boss_api_guide/codeexamples.html#oauth_js
function yahooSearch(consumerKey, consumerSecret, query, count,
callback_error_data_response){
var webSearchUrl = 'https://yboss.yahooapis.com/ysearch/web';
var finalUrl = webSearchUrl + '?' + qs.stringify({
q: query, //search keywords
format: 'json',
count: count,
});
var oa = new OAuth(webSearchUrl, webSearchUrl, consumerKey, consumerSecret, "1.0", null, "HMAC-SHA1");
oa.setClientOptions({ requestTokenHttpMethod: 'GET' });
oa.getProtectedResource(finalUrl, "GET", '','', callback_error_data_response);
}
// Use this function to make a call back. Make sure to provide the right key, secret and query for this to work correctly yahooSearch('YAHOO CONSUMER KEY GOES HERE', 'YAHOO CONSUMER SECRET GOES HERE', 'SEARCH QUERY', 10, function(error, data, response){
// enter some code here and access the results from the "data" variable in JSON format
});
You can go to YQL Console and then enter your request, you can select Json or XML, after your result is fetched, look at the bottom of the page and then copy the url. You will be able to use that url inside script tags in an html doc and run it with your browser without a server.