I am trying to learn how to use the Skyscanner Flights API with Google Script. It seems that the information available online is not adapted to newbies like me.
From what I got, the procedure to gain access to the flights' prices is :
- to send a HTTP POST request with information about which flights we want information about
- then send a HTTP GET request which will give us the pricing information
I would like to do that with Google Script.
Here is my code so far :
function sky1() {
/*
Link to Skyscanner.com help : http://business.skyscanner.net/portal/en- GB/Documentation/FlightsLivePricingList
Link to Skyscanner api demo (api key given there): http://business.skyscanner.net/portal/en- GB/Documentation/FlightsLivePricingQuickStart
*/
var apikey = "prtl6749387986743898559646983194";// is given on skyscanner website for testing
var url = "http://partners.api.skyscanner.net/apiservices/pricing/v1.0/?apikey=" + apikey;
// Post http request to skyscanner
var post_resp=sendHttpPost(url,apikey);
}
function sendHttpPost(url) {
// post_params
var post_params = {
"Country": "CH",
"Currency": "CHF",
"Locale": "en-GB",
"Adults": 1,
"Children": 0,
"Infants": 0,
"OriginPlace": "12015",
"DestinationPlace": "5772",
"OutboundDate": "2015-08-09",
"InboundDate": "2015-08-23",
"LocationSchema": "Default",
"CabinClass": "Economy",
"GroupPricing": true
};
var options =
{
"method" : "POST",
"contentType" : "application/json", // didn't get what this means
"payload" : JSON.stringify(post_params), // didn't get what this means
"muteHttpExceptions" : true, // avoids error message
};
var post_resp=UrlFetchApp.fetch(url,options);
Logger.log(post_resp.getResponseCode());
return post_resp;
}
Any help would be very appreciated. This gives me a 415 response rode instead of a 201 indicating that a session has been created.
PS: I am not a programmer, I would be very grateful if we keep thing simple.
Skyscanner API team here. You may be interested to see a reference Javascript implementation at https://github.com/Skyscanner/skyscanner-api-js. I also recommend using Fiddler (a network tracing tool) to compare the request/response from the test harness at http://business.skyscanner.net/portal/en-GB/Documentation/FlightsLivePricingQuickStart with that of your code.
Related
I'm working with the Google Analytics API for the first time and I'm trying to create a new property. I wrote a JS function in Google App Script:
function insertProperty() {
var resource =
{
// "accountId": "177832616",
"resource":{
"name": "Test Property 7",
// "dataRetentionResetOnNewActivity": false,
"websiteUrl": "https://www.test.com"
}
}
var accountID = '177832616';
var request = Analytics.Management.Webproperties.insert(resource, accountID);
// request.execute(function (response) { console.log(property.id) });
}
This is the error the API throws:
GoogleJsonResponseException: API call to analytics.management.webproperties.insert failed with error: Field name is required. (line 56, file "Code")
The insert() method seems to take two parameters: insert(Webproperty resource, string accountId);
Since it's not recognizing the name key/value I added to resource, my guess is I haven't declared the variable as a Webproperty type and I'm not sure how to do this. I assumed Webproperty was a { } variable type, but at this point I'm not sure what to try next. Doing research online, I'm not able to find anything regarding the API's Webproperty so any context/info is helpful.
From your question, I could understand that Google Analytics API is used with Advanced Google services of Google Apps Script. In this case, resource of Analytics.Management.Webproperties.insert(resource, accountId) can directly use the request body of the method of "Web Properties: insert". I think that the reason of your error is due to this. So please modify as follows and test it again.
From:
var resource =
{
// "accountId": "177832616",
"resource":{
"name": "Test Property 7",
// "dataRetentionResetOnNewActivity": false,
"websiteUrl": "https://www.test.com"
}
}
To:
var resource = {
"name": "Test Property 7",
"websiteUrl": "https://www.test.com"
}
Note:
When accountId is not correct, an error occurs. Please be careful this.
From iansedano's comment, in this case, request of var request = Analytics.Management.Webproperties.insert(resource, accountID); directly returns the values. So you can see the value like console.log(request) and console.log(request.toString()).
Reference:
Web Properties: insert
I'm trying to use Google Apps Scripts to post to Salesforce to create a new account. I'm able to use my credentials fine to query with SOQL. When I try to post, it basically returns data as if I'm describing the Account, and the new account doesn't get created. I tried using the workbench rest API with this payload and can create an account no problem, so I know it's not an issue with fields/values.
function pushToSalesforce(){
var userProperties = PropertiesService.getUserProperties();
var instance_url = "https://na9.salesforce.com";
var access_token = userProperties.getProperty('access_token');
var payload = {
"Name" : "testaccount",
"Website" : "testaccountstuff.com",
"Platform__c" : "API",
"Industry" : "Apparel"
};
var queryUrl = instance_url + '/services/data/v26.0/sobjects/account/';
var headers =
{
"method" : "POST",
"contentType" : "application/json",
"payload": JSON.stringify(payload),
"headers": {
"Authorization" : "Bearer "+access_token,
"Accept": "application/json"
}
};
var response = UrlFetchApp.fetch(queryUrl, headers);
}
I'm going nuts trying to figure out what the issue is. Anybody have an idea?
Sounds like your app is making a GET instead of POST. Is this language / HTTP library case-sensitive? Documentation seems to use lowercase
You are supposed to send a POST to /services/data/v49.0/sobjects/Account (you're using very old API version but that shouldn't matter). What exactly do you see in response? It may look "describe'ish" but it's unlikely to be a real describe result unless you explicitly call /services/data/v49.0/sobjects/Account/describe.
A GET call to /services/data/v49.0/sobjects/Account is a discovery, a way for the API to self-document. Returns very basic info about the object, something like
{
"objectDescribe" : {
"activateable" : false,
"createable" : true,
"custom" : false,
(... snip...)
"updateable" : true,
"urls" : {
"compactLayouts" : "/services/data/v48.0/sobjects/Account/describe/compactLayouts",
"rowTemplate" : "/services/data/v48.0/sobjects/Account/{ID}",
"approvalLayouts" : "/services/data/v48.0/sobjects/Account/describe/approvalLayouts",
"defaultValues" : "/services/data/v48.0/sobjects/Account/defaultValues?recordTypeId&fields",
"listviews" : "/services/data/v48.0/sobjects/Account/listviews",
"describe" : "/services/data/v48.0/sobjects/Account/describe",
"quickActions" : "/services/data/v48.0/sobjects/Account/quickActions",
"layouts" : "/services/data/v48.0/sobjects/Account/describe/layouts",
"sobject" : "/services/data/v48.0/sobjects/Account"
}
},
"recentItems" : [ ]
}
A proper describe call would instead return info about all columns you can see in the table, all relations (foreign keys) to this object...
In my actual script was the "my domain" custom instance_url for my company (but didn't want to broadcast it), e.g. "https://companyname.lightning.force.com". I tried using my server instance "na85" instead and it worked fine! Super weird because I have another function using the other instance_url with a GET and it worked no problem. Thanks for your help!
A brief description of the project: I am looking to toggle the email forwarding option in the settings of one of my gmail accounts through a google script. This will be a function I would like to call every night between certain hours forwarding my mail from main_email#gmail to secondary_email#gmail.
I am having a difficult time finding the easiest way to toggle this through a google script. The simplest solution seems to be described here where they use an HTTP request. However in all honesty I don't completely understand how it all works, much less if it is the simplest way.
https://developers.google.com/gmail/api/v1/reference/users/settings/updateAutoForwarding
The code that I try and run on the gmail account to enable/disable email forwarding is the following:
function updateForwarding() {
var userID = "main_email#gmail.com"
var response = UrlFetchApp.fetch("https://www.googleapis.com/gmail/v1/users/" + userID + "/settings/autoForwarding", {
method: 'put',
enabled: true,
emailAddress: "secondary_email#gmail.com",
disposition: "leaveInInbox"
});
Logger.log(response.getContentText());
}
However I get the following error:
Request failed for
https://www.googleapis.com/gmail/v1/users/main_email#gmail.com/settings/autoForwarding
returned code 401. Truncated server response: { "error": { "errors": [
{ "domain": "global", "reason": "required", "message": "Login
Required", "locationType": "header", ... (use muteHttpExceptions
option to examine full response) (line 4, file "Code")
I recognize this is shows I need to provide credentials for making the request, but I don't understand how I would do that. I read on the tutorial (https://developers.google.com/gmail/api/auth/about-auth) I need to authorize my app with gmail and get an API key, so I have gone to the google developers console to create that. However, I have no idea how to authenticate or make the call through a Google script after a few hours of google.
Here are the key and secret I was given:
Is this the easiest solution to toggle gmail forwarding? If so, how do I authenticate my call? If not, what is the easiest solution to being able to toggle my gmail forwarding off/on?
You need to pass oAuth token in header information
function updateForwarding() {
var userID = "main_email#gmail.com";
var header = {
Authorization: 'Bearer ' + ScriptApp.getOAuthToken(),
}
var response = UrlFetchApp.fetch("https://www.googleapis.com/gmail/v1/users/" + userID + "/settings/autoForwarding", {
method: 'put',
enabled: true,
headers: header,
emailAddress: "secondary_email#gmail.com",
disposition: "leaveInInbox"
});
Logger.log(response.getContentText());
}
As noted in the authorization section of https://developers.google.com/gmail/api/v1/reference/users/settings/updateAutoForwarding, you need to use OAuth with the given scopes to make that call, not just an API key. You appear to have a client id, but you need to plug this into a library to handle the OAuth process for you. The OAuth process will then give you a Bearer token to add to your request (although most OAuth libraries will handle this for you).
It looks like https://github.com/googlesamples/apps-script-oauth2 is the current recommened way to do this if you're using UrlFetchApp (based on https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app).
I have searched the documentation in Google Directions API, and also looked around online and cannot find an answer to my conundrum. My agency has developed an API to find the latest possible departure between origins and destinations using transit, and there are a few which are returning "No_Result" errors. However, I am able to return results when I search Google Maps manually.
My Google Directions API program sends out the following query:
https://maps.googleapis.com/maps/api/directions/json?units=imperial&origin=650+Memorial+Dr+chicopee+MA&destination=50+College+St+South+Hadley+MA&arrival_time=1461301200&mode=transit
which returns:
{
"available_travel_modes" : [ "DRIVING", "BICYCLING", "WALKING" ],
"geocoded_waypoints" : [
{
"geocoder_status" : "OK",
"place_id" : "ChIJ7VtqLK7d5okR-bTUfKuHVpo",
"types" : [ "street_address" ]
},
{
"geocoder_status" : "OK",
"place_id" : "ChIJxwHLSqzb5okR1rrjYhcDvkc",
"types" : [ "premise" ]
}
],
"routes" : [],
"status" : "ZERO_RESULTS"
}
However, when I query manually using Google maps, I am able to return a result via transit.
https://www.google.com/maps/dir/650+Memorial+Drive,+Chicopee,+MA/50+College+Street,+South+Hadley,+MA/#42.2678007,-72.7164286,11z/data=!3m1!4b1!4m18!4m17!1m5!1m1!1s0x89e6ddae2c6a5bed:0x9a5687ab7cd4b4f9!2m2!1d-72.5797548!2d42.1751992!1m5!1m1!1s0x89e6dbac4b2aac81:0xe9809aca8e8e0bdc!2m2!1d-72.5766752!2d42.2538136!2m3!6e1!7e2!8j1461200400!3e3
I have double-checked any obvious mistakes (like using "Rd" instead of "St", or inputting an address that doesn't exist) but have not found any. I have also changed the departure/arrival times in the program, with no luck.
The error message looks like it is indicating that MODE as TRANSIT is not an option between that origin/destination pair - but then the manual interface doesn't have an issue.
Does anyone know why Google Maps might be rejecting the API query, but not the manual query? Or any resources to help figure out this problem? Thanks!!
The 'All caps' response is (unintentionally, but) misleadingly wrong - the Google Maps API server doesn't do proper error checking here, and if you give it an all-caps mode parameter it will return driving directions no matter which mode you wrote.
Real answer is that the API doesn't support all modes in all places, even though the Google Maps app does. You can file feature requests to try to push for this parity. For example, public transit in Japan:
https://issuetracker.google.com/issues/35826181
Test queries to demonstrate that Maps Directions responses don't care which mode you specify if you do it in all-caps (be sure to add your API key):
Driving -
https://maps.googleapis.com/maps/api/directions/json?departure_time=now&destination=place_id%3AChIJp4QhcgzyGGARZaBIPuJzfpg&mode=DRIVING&origin=place_id%3AChIJlyOpErWHGGAR0156e32g1Xs&key=API_KEY
Transit -
https://maps.googleapis.com/maps/api/directions/json?departure_time=now&destination=place_id%3AChIJp4QhcgzyGGARZaBIPuJzfpg&mode=TRANSIT&origin=place_id%3AChIJlyOpErWHGGAR0156e32g1Xs&key=API_KEY
Walking -
https://maps.googleapis.com/maps/api/directions/json?departure_time=now&destination=place_id%3AChIJp4QhcgzyGGARZaBIPuJzfpg&mode=WALKING&origin=place_id%3AChIJlyOpErWHGGAR0156e32g1Xs&key=API_KEY
The mode (mode=transit) in your query string should be capitalized - try mode=TRANSIT instead.
I think this is helpful for this error .Actually the main problem is let and long are not correctly formatted and position changed.so apply this code. and enjoy
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix({
origins: [latOffice + "," + longOffice],
destinations: [latitudeS + "," + longitudeS],
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.METRIC,
avoidHighways: true,
avoidTolls: true
}, function (response, status) {
if (status == google.maps.DistanceMatrixStatus.OK && response.rows[0].elements[0].status != "ZERO_RESULTS") {
var distance2 = response.rows[0].elements[0].distance.text;
var duration2 = response.rows[0].elements[0].duration.text;
duration = duration2;
} else {
//alert("Your Request For Distance Not Available");
Swal.fire('Oops...', 'Your Request For Distance Not Available!', 'error');
}
How to create microsoft or google translate button for each div?
Each div has content in different language and I would like to add a translate button for each div and make it respond to only that div like the button in the following link.
http://www.bing.com/widget/translator
But when I use the code mentioned in the link above, it translates the whole webpage. I would like to translate each div separately by clicking on the respective translate button.
Can the same thing be done easily using google translate?
Any translator is fine with me. Kindly help. Thanks.
This how the users' post appear on my website.
I would like to have a translate button for each of the divs so that the users can translate each div into any language they want.
Each of my div has an id.
Below I'm explaining how to get started with Microsoft Translator API. The very same functionality can be implemented via Google Translate API however it was somehow easier for me with MS as they offer 2M characters/monthly translation for free whereas Google charges minimum of 1$ for testing.
Prerequisites:
Sign up for free subscription on Microsoft Translator. For that you will be asked to create new MS account or login with existing one.
Register your application on Azure Datamarket.
Registration example. Note: There are two important fields here Client ID and Client secret you will need them for access token requests.
Implementation:
First things first, every request to the API should include access token. Expiration time is 10 minutes so you will have to renew them before they expire. Ideally the process should be done on the back-end side to protect your Client secret and result (token + expiration time) send back to web application.
Node.js example:
var request = require("request");
var options = {
method: 'POST',
url: 'https://datamarket.accesscontrol.windows.net/v2/OAuth2-13/',
form: {
// Client ID & Client secret values (see screenshot)
client_id: 'translator_3000',
client_secret: 'ZP8LzjZkKuFAb2qa05+3nNq+uOcqzWK7e3J6qCN1mtg=',
scope: 'http://api.microsofttranslator.com',
grant_type: 'client_credentials'
}
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
Response contains few fields including access_token, use its value for further requests.
{
"token_type": "http://schemas.xmlsoap.org/ws/2009/11/swt-token-profile-1.0",
"access_token": "http%3a%2f%2fschemas.xmlsoap.org%2fws%2f2005%2f05%2fidentity%2fclaims%2fnameidentifier=translator_3000&http%3a%2f%2fschemas.microsoft.com%2faccesscontrolservice%2f2010%2f07%2fclaims%2fidentityprovider=https%3a%2f%2fdatamarket.accesscontrol.windows.net%2f&Audience=http%3a%2f%2fapi.microsofttranslator.com&ExpiresOn=1435405881&Issuer=https%3a%2f%2fdatamarket.accesscontrol.windows.net%2f&HMACSHA256=st9LJ0F8CKSa6Ls59gQN0EqMWLFed5ftkJiOCVXE4ns%3d",
"expires_in": "600",
"scope": "http://api.microsofttranslator.com"
}
Now when we have access token it's time for translation request. Note: These are JSONP requests and access token is supplied using query string parameter appId in the format Bearer <token> (separated by space). Query string also includes text parameter - text of your post and to parameter - language code selected by user, list of all supported codes and language friendly names you can get from API as well.
Here is example:
var settings = {
"url": "https://api.microsofttranslator.com/v2/Ajax.svc/Translate",
"method": "GET",
"dataType": "jsonp",
"jsonp" : "oncomplete",
"data" : {
"text" : "Good Morning StackOverflow",
"to" : "uk",
"appId" : "Bearer http%3a%2f%2fschemas.xmlsoap.org%2fws%2f2005%2f05%2fidentity%2fclaims%2fnameidentifier=translator_3000&http%3a%2f%2fschemas.microsoft.com%2faccesscontrolservice%2f2010%2f07%2fclaims%2fidentityprovider=https%3a%2f%2fdatamarket.accesscontrol.windows.net%2f&Audience=http%3a%2f%2fapi.microsofttranslator.com&ExpiresOn=1435405881&Issuer=https%3a%2f%2fdatamarket.accesscontrol.windows.net%2f&HMACSHA256=st9LJ0F8CKSa6Ls59gQN0EqMWLFed5ftkJiOCVXE4ns%3d"
}
}
$.ajax(settings).done(function (response) {
console.log(response);
});
Response is translated string to be replaced with post original text:
"Доброго ранку StackOverflow"
And lastly, all language codes:
http://api.microsofttranslator.com/V2/Ajax.svc/GetLanguagesForTranslate
and friendly names for selected codes:
http://api.microsofttranslator.com/V2/Ajax.svc/GetLanguageNames?locale=en&languageCodes=["en", "de", "es", "uk"]
Official documentation included.
Use the Class element <div class="micropost293"> shown below.
<div class="micropost293"><p>Тестирование</p>
<div class="micropost293_control" lang="en"></div>
<script>
function googleSectionalElementInit() {
new google.translate.SectionalElement({
sectionalNodeClassName: 'micropost293',
controlNodeClassName: 'micropost293_control',
background: '#f4fa58'
}, 'google_sectional_element');
}
</script>
</div>
//Place this Script at bottom of page.
<script src="//translate.google.com/translate_a/element.js?cb=googleSectionalElementInit&ug=section&hl=en"></script>