Related
Can I make a cross-domain JSONP request in JavaScript without using jQuery or other external library? I would like to use JavaScript itself and then parse the data and make it an object so I could use it. Do I have to use an external library? If not, how can I do it?
function foo(data)
{
// do stuff with JSON
}
var script = document.createElement('script');
script.src = '//example.com/path/to/jsonp?callback=foo'
document.getElementsByTagName('head')[0].appendChild(script);
// or document.head.appendChild(script) in modern browsers
Lightweight example (with support for onSuccess and onTimeout). You need to pass callback name within URL if you need it.
var $jsonp = (function(){
var that = {};
that.send = function(src, options) {
var callback_name = options.callbackName || 'callback',
on_success = options.onSuccess || function(){},
on_timeout = options.onTimeout || function(){},
timeout = options.timeout || 10; // sec
var timeout_trigger = window.setTimeout(function(){
window[callback_name] = function(){};
on_timeout();
}, timeout * 1000);
window[callback_name] = function(data){
window.clearTimeout(timeout_trigger);
on_success(data);
}
var script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.src = src;
document.getElementsByTagName('head')[0].appendChild(script);
}
return that;
})();
Sample usage:
$jsonp.send('some_url?callback=handleStuff', {
callbackName: 'handleStuff',
onSuccess: function(json){
console.log('success!', json);
},
onTimeout: function(){
console.log('timeout!');
},
timeout: 5
});
At GitHub: https://github.com/sobstel/jsonp.js/blob/master/jsonp.js
What is JSONP?
The important thing to remember with jsonp is that it isn't actually a protocol or data type. Its just a way of loading a script on the fly and processing the script that is introduced to the page. In the spirit of JSONP, this means introducing a new javascript object from the server into the client application/ script.
When is JSONP needed?
It is 1 method of allowing one domain to access/ process data from another in the same page asyncronously. Primarily, it is used to override CORS (Cross Origin Resource Sharing) restrictions which would occur with an XHR (ajax) request. Script loads are not subject to CORS restrictions.
How is it done
Introducing a new javascript object from the server can be implemented in many ways, but the most common practice is for the server to implement the execution of a 'callback' function, with the required object passed into it. The callback function is just a function you have already set up on the client which the script you load calls at the point the script loads to process the data passed in to it.
Example:
I have an application which logs all items in someone's home. My application is set up and I now want to retrieve all the items in the main bedroom.
My application is on app.home.com. The apis I need to load data from are on api.home.com.
Unless the server is explicitly set up to allow it, I cannot use ajax to load this data, as even pages on separate subdomains are subject to XHR CORS restrictions.
Ideally, set things up to allow x-domain XHR
Ideally, since the api and app are on the same domain, I might have access to set up the headers on api.home.com. If I do, I can add an Access-Control-Allow-Origin: header item granting access to app.home.com. Assuming the header is set up as follows: Access-Control-Allow-Origin: "http://app.home.com", this is far more secure than setting up JSONP. This is because app.home.com can get everything it wants from api.home.com without api.home.com giving CORS access to the whole internet.
The above XHR solution isn't possible. Set up JSONP On my client script: I set up a function to process the reponse from the server when I make the JSONP call.:
function processJSONPResponse(data) {
var dataFromServer = data;
}
The server will need to be set up to return a mini script looking something like "processJSONPResponse('{"room":"main bedroom","items":["bed","chest of drawers"]}');" It might be designed to return such a string if something like //api.home.com?getdata=room&room=main_bedroom is called.
Then the client sets up a script tag as such:
var script = document.createElement('script');
script.src = '//api.home.com?getdata=room&room=main_bedroom';
document.querySelector('head').appendChild(script);
This loads the script and immediately calls window.processJSONPResponse() as written/ echo/ printed out by the server. The data passed in as the parameter to the function is now stored in the dataFromServer local variable and you can do with it whatever you need.
Clean up
Once the client has the data, ie. immediately after the script is added to the DOM, the script element can be removed from the DOM:
script.parentNode.removeChild(script);
My understanding is that you actually use script tags with JSONP, sooo...
The first step is to create your function that will handle the JSON:
function hooray(json) {
// dealin wit teh jsonz
}
Make sure that this function is accessible on a global level.
Next, add a script element to the DOM:
var script = document.createElement('script');
script.src = 'http://domain.com/?function=hooray';
document.body.appendChild(script);
The script will load the JavaScript that the API provider builds, and execute it.
the way I use jsonp like below:
function jsonp(uri) {
return new Promise(function(resolve, reject) {
var id = '_' + Math.round(10000 * Math.random());
var callbackName = 'jsonp_callback_' + id;
window[callbackName] = function(data) {
delete window[callbackName];
var ele = document.getElementById(id);
ele.parentNode.removeChild(ele);
resolve(data);
}
var src = uri + '&callback=' + callbackName;
var script = document.createElement('script');
script.src = src;
script.id = id;
script.addEventListener('error', reject);
(document.getElementsByTagName('head')[0] || document.body || document.documentElement).appendChild(script)
});
}
then use 'jsonp' method like this:
jsonp('http://xxx/cors').then(function(data){
console.log(data);
});
reference:
JavaScript XMLHttpRequest using JsonP
http://www.w3ctech.com/topic/721 (talk about the way of use Promise)
I have a pure javascript library to do that https://github.com/robertodecurnex/J50Npi/blob/master/J50Npi.js
Take a look at it and let me know if you need any help using or understanding the code.
Btw, you have simple usage example here: http://robertodecurnex.github.com/J50Npi/
/**
* Loads data asynchronously via JSONP.
*/
const load = (() => {
let index = 0;
const timeout = 5000;
return url => new Promise((resolve, reject) => {
const callback = '__callback' + index++;
const timeoutID = window.setTimeout(() => {
reject(new Error('Request timeout.'));
}, timeout);
window[callback] = response => {
window.clearTimeout(timeoutID);
resolve(response.data);
};
const script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.src = url + (url.indexOf('?') === -1 ? '?' : '&') + 'callback=' + callback;
document.getElementsByTagName('head')[0].appendChild(script);
});
})();
Usage sample:
const data = await load('http://api.github.com/orgs/kriasoft');
I wrote a library to handle this, as simply as possible. No need to make it external, its just one function. Unlike some other options, this script cleans up after itself, and is generalized for making further requests at runtime.
https://github.com/Fresheyeball/micro-jsonp
function jsonp(url, key, callback) {
var appendParam = function(url, key, param){
return url
+ (url.indexOf("?") > 0 ? "&" : "?")
+ key + "=" + param;
},
createScript = function(url, callback){
var doc = document,
head = doc.head,
script = doc.createElement("script");
script
.setAttribute("src", url);
head
.appendChild(script);
callback(function(){
setTimeout(function(){
head
.removeChild(script);
}, 0);
});
},
q =
"q" + Math.round(Math.random() * Date.now());
createScript(
appendParam(url, key, q), function(remove){
window[q] =
function(json){
window[q] = undefined;
remove();
callback(json);
};
});
}
Please find below JavaScript example to make a JSONP call without JQuery:
Also, you can refer my GitHub repository for reference.
https://github.com/shedagemayur/JavaScriptCode/tree/master/jsonp
window.onload = function(){
var callbackMethod = 'callback_' + new Date().getTime();
var script = document.createElement('script');
script.src = 'https://jsonplaceholder.typicode.com/users/1?callback='+callbackMethod;
document.body.appendChild(script);
window[callbackMethod] = function(data){
delete window[callbackMethod];
document.body.removeChild(script);
console.log(data);
}
}
/**
* Get JSONP data for cross-domain AJAX requests
* #private
* #link http://cameronspear.com/blog/exactly-what-is-jsonp/
* #param {String} url The URL of the JSON request
* #param {String} callback The name of the callback to run on load
*/
var loadJSONP = function ( url, callback ) {
// Create script with url and callback (if specified)
var ref = window.document.getElementsByTagName( 'script' )[ 0 ];
var script = window.document.createElement( 'script' );
script.src = url + (url.indexOf( '?' ) + 1 ? '&' : '?') + 'callback=' + callback;
// Insert script tag into the DOM (append to <head>)
ref.parentNode.insertBefore( script, ref );
// After the script is loaded (and executed), remove it
script.onload = function () {
this.remove();
};
};
/**
* Example
*/
// Function to run on success
var logAPI = function ( data ) {
console.log( data );
}
// Run request
loadJSONP( 'http://api.petfinder.com/shelter.getPets?format=json&key=12345&shelter=AA11', 'logAPI' );
If you are using ES6 with NPM, you can try node module "fetch-jsonp".
Fetch API Provides support for making a JsonP call as a regular XHR call.
Prerequisite:
you should be using isomorphic-fetch node module in your stack.
Just pasting an ES6 version of sobstel's nice answer:
send(someUrl + 'error?d=' + encodeURI(JSON.stringify(json)) + '&callback=c', 'c', 5)
.then((json) => console.log(json))
.catch((err) => console.log(err))
function send(url, callback, timeout) {
return new Promise((resolve, reject) => {
let script = document.createElement('script')
let timeout_trigger = window.setTimeout(() => {
window[callback] = () => {}
script.parentNode.removeChild(script)
reject('No response')
}, timeout * 1000)
window[callback] = (data) => {
window.clearTimeout(timeout_trigger)
script.parentNode.removeChild(script)
resolve(data)
}
script.type = 'text/javascript'
script.async = true
script.src = url
document.getElementsByTagName('head')[0].appendChild(script)
})
}
I am trying to integrate Google Calendar API with Js inside an application. I tried to follow Google Quickstart. If I paste the example code in an HTML doc, change the clientID and the API key, I get the error attached when I open the file in Chrome.
Also, with console.log(gapi.client) I get back null.
The first block of code is where gapi functions are called (calendar_model.js).
The second block is where I link the api script to the document (I need to do that by js, in a file called dependency.js).
The third block is my index.js, from where I call the function in dependency.js.
console.log("first");
// Client ID and API key from the Developer Console
var CLIENT_ID = 'xxxxxxxxxxxxxxxxx.apps.googleusercontent.com';
var API_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx';
// Array of API discovery doc URLs for APIs used by the quickstart
var DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"];
// Authorization scopes required by the API; multiple scopes can be
// included, separated by spaces.
var SCOPES = "https://www.googleapis.com/auth/calendar.readonly";
var authorizeButton;
var signoutButton;
/**
* On load, called to load the auth2 library and API client library.
*/
function handleClientLoad() {
console.log("gapi type: " + typeof gapi + '\n');
console.log("gapi client type: " + typeof gapi.client + '\n');
gapi.load('client:auth2', initClient);
}
/**
* Initializes the API client library and sets up sign-in state
* listeners.
*/
function initClient()
{
console.log("initClient callback start");
gapi.client.init({
apiKey: API_KEY,
clientId: CLIENT_ID,
discoveryDocs: DISCOVERY_DOCS,
scope: SCOPES
}).then(function () {
// Listen for sign-in state changes.
gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus);
console.log(gapi);
// Handle the initial sign-in state.
updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
authorizeButton.onclick = handleAuthClick;
signoutButton.onclick = handleSignoutClick;
}, function(error) {
appendPre(JSON.stringify(error, null, 2));
});
}
window.testMicroAppDependency = {
calendarInit: function(){
var calendar_root = document.getElementById("gcalendar-root");
//create authorize button
var x = document.createElement("button");
x.setAttribute("id", "authorize_button");
//x.style = "display: none";
calendar_root.appendChild(x);
//create signout button
x = document.createElement("button");
x.setAttribute("id", "signout_button");
//x.style = "display: none";
calendar_root.appendChild(x);
authorizeButton = document.getElementById('authorize_button');
signoutButton = document.getElementById('signout_button');
x = document.createElement("script");
x.src = "https://apis.google.com/js/api.js";
x.async = true;
x.defer = true;
x.setAttribute("onload", "handleClientLoad()");
x.setAttribute("onreadystatechange", "if (this.readyState === 'complete') this.onload()");
calendar_root.appendChild(x);
}
}
registry.add("microapp", "googlecalendar", {
init: function (parentNode, options) {
this._waitForDependency(function (error, dependency) {
if (error) {
console.error("Unable to start Google Calendar MicroApp: " + error);
} else {
var content = document.createElement("div");
content.setAttribute("id", "gcalendar-root");
parentNode.appendChild(content);
dependency.calendarInit();
}
});
},
_waitForDependency: function(callback) {
var timeout = 5000;
var startTime = new Date().getTime();
var interval = setInterval(function() {
if (window.hasOwnProperty("testMicroAppDependency")) {
clearInterval(interval);
callback(null, window.testMicroAppDependency);
}
if (new Date().getTime() - startTime > timeout) {
clearInterval(interval);
callback("Loading of HelloWorld MicroApp scripts timed out.", null);
}
console.log("... (waiting for testMicroAppDependency)");
}, 100);
}
});
Here is the console where I log the type of gapi and of gapi.client. gapi is an object, so the library is loaded, but gapi.client is undefined.
I am pretty a newbie in web dev, maybe it's a silly issue or I didn't comprehend something about Google API, but I can't get resolve it.
Any help is appreciated :)
The main issue you are having is you are calling initClient function as an explicit function here:
gapi.load('client:auth2', initClient())
you have to pass it as an implicit function because gapi.load will use it as a callback (I recommend you to check more about them). Therefore, it must be passed like this:
gapi.load('client:auth2', initClient)
Notice the subtle, but really important difference between the parenthesis in initClient() and initClient.
Also, you have these variables in the air without assigning them values for what I could see:
var authorizeButton;
var signoutButton;
They should be assigned the button elements to eventually handle them in your code:
var authorizeButton = document.getElementById('authorize_button');
var signoutButton = document.getElementById('signout_button');
we are using Ember 1.10.1 with Ember CLI 0.2.1, I'm currently trying to integrate Natero into our app, looking at the quickstart guide I thought about using an initializer to do it. It appears to work with Chrome but with other browser I'm getting the error: _na is undefined. The general idea was to dynamically inject the script and wait for the promise to be resolved to set the _naobject on the window.
What would be a better approach to handle this ?
import Ember from 'ember';
/* jshint ignore:start */
import ENV from 'webapp/config/environment';
/* jshint ignore:end */
export function initialize(/* container, application */) {
/* jshint ignore:start */
let src = 'https://events.natero.com/scripts/natero_analytics.min.js';
let injectScript = function (src) {
return new Ember.RSVP.Promise(function (resolve) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.src = src;
script.onload = function () {
resolve();
};
document.getElementsByTagName('head')[0].appendChild(script);
});
};
injectScript(src).then(function() {
/*
* On each page that loads, initialize the natero analytics js library.
* The userId and accountId can be set here if known at initialization time.
* Once the userId/accountId are set they are stored in a cookie for later use,
* so that they only need to be set once per session.
*/
// http://apidocs.natero.com/quickstarte.html
// https://login.natero.com/itcenter.html
let authKey = ENV.natero.authKey,
apiKey = ENV.natero.apiKey,
settings = {
trackUnload: true,
debugUrl: "https://test.natero.com/v1/" + authKey + "/" + apiKey,
disableEventSend: false, // disable the sending of events
debug: false // console debug prints
};
if (['production', 'prd'].indexOf(ENV.environment) > -1) {
delete settings['debugUrl'];
}
window._na = new na(
apiKey,
authKey,
settings
);
});
/* jshint ignore:end */
Ember.Router.reopen({
notifyNatero: function () {
// https://github.com/emberjs/ember.js/issues/10180
let currentRoute = Webapp.__container__.lookup('controller:application').get('currentRouteName');
_na.setModuleId(currentRoute);
}.on('didTransition')
});
}
export default {
name: 'natero',
initialize: initialize
};
I just changed the order. give it try
let injectScript = function (src) {
return new Ember.RSVP.Promise(function (resolve) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
document.getElementsByTagName('head')[0].appendChild(script);
script.onload = function () {
resolve();
};
script.src = src;
});
};
One more options is you can include it in index.html and running your current success callback function ie.,loading https://test.natero.com/v1/ script can be done in Application beforeModel hook
I am working on an application that is using Google Cloud Storage. I would like to use the JSON_API to manage uploading/downloading the pictures our user's provide. My goal is to grab the access_token using my service account method, and pass it off the the JSON_API JavaScript client api.
Here's my fancy pants class to grab the access_token:
<?php
require_once 'google-api-php-client/src/Google_Client.php';
require_once 'google-api-php-client/src/contrib/Google_StorageService.php';
class Model_Storage_Auth
{
const CLIENT_ID = "clientid.apps.googleusercontent.com";
const SERVICE_ACCOUNT_NAME = "accountname#developer.gserviceaccount.com";
const KEY_FILE = "/super/secret/path/key.p12";
const ACCESS_TOKEN = 'access_token';
const APP_NAME = 'Fancy App';
private $google_client;
function __construct()
{
$this->google_client = new Google_Client();
$this->google_client->setApplicationName(self::APP_NAME);
}
public function getToken()
{
//return '{}';
if(is_null($this->google_client->getAccessToken()))
{
try{$this->google_client->setAccessToken(Session::get(self::ACCESS_TOKEN, '{}'));}catch(Exception $e){}
if(is_null($this->google_client->getAccessToken()))
{
$scope = array();
$scope[] = 'https://www.googleapis.com/auth/devstorage.full_control';
$key = file_get_contents(self::KEY_FILE);
$this->google_client->setAssertionCredentials(new Google_AssertionCredentials(
self::SERVICE_ACCOUNT_NAME,
$scope,
$key)
);
$this->google_client->setClientId(self::CLIENT_ID);
Google_Client::$auth->refreshTokenWithAssertion();
$token = $this->google_client->getAccessToken();
Session::set(self::ACCESS_TOKEN, $token);
}
}
return $this->google_client->getAccessToken();
}
}
I took the google JavaScript example and modified it a little bit to try to add my implementation, here it is:
<?php
$access_token = json_decode(html_entity_decode($access_token), true);
?>
<!--
Copyright (c) 2012 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License. You may obtain a copy of
the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations under
the License.
To run this sample, replace YOUR_API_KEY with your application's API key.
It can be found at https://code.google.com/apis/console under API
Access. Activate the Google Cloud Storage service at
https://code.google.com/apis/console/ under Services
-->
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="https://apis.google.com/js/client.js"></script>
<script type="text/javascript">
/**
* The number of your Google Cloud Storage Project.
*/
var projectNumber = 'HAS REAL NUMBER IN MINE';
/**
* Enter a client ID for a web application from the Google Developer
* Console. In your Developer Console project, add a JavaScript origin
* that corresponds to the domain from where you will be running the
* script.
*/
var clientId = 'YOUR_CLIENT_ID';
/**
* Enter the API key from the Google Developer Console, by following these
* steps:
* 1) Visit https://code.google.com/apis/console/?api=storage
* 2) Click on "API Access" in the left column
* 3) Find section "Simple API Access" and use the "API key." If sample is
* being run on localhost then delete all "Referers" and save. Setting
* should display "Any referer allowed."
*/
var apiKey = 'YOUR_API_KEY';
/**
* To enter one or more authentication scopes, refer to the documentation
* for the API.
*/
var scopes = 'https://www.googleapis.com/auth/devstorage.full_control';
/**
* Constants for request parameters. Fill these values in with your custom
* information.
*/
var API_VERSION = 'v1beta1';
var PROJECT = projectNumber;
/**
* The name of the new bucket to create.
*/
var BUCKET = 'code-sample-bucket';
/**
* The name of the object inserted via insertObject method.
*/
var object = "";
/**
* Get this value from the API console.
*/
var GROUP =
'group-0000000000000000000000000000000000000000000000000000000000000000';
/**
* Valid values are user-userId, user-email, group-groupId, group-email,
* allUsers, allAuthenticatedUsers
*/
var ENTITY = 'allUsers';
/**
* Valid values are READER, OWNER
*/
var ROLE = 'READER';
/**
* Valid values are READER, OWNER
*/
var ROLE_OBJECT = 'READER';
/**
* A list of example calls to the Google Cloud Storage JavaScript client
* library, as well as associated explanations of each call.
*/
var listApiRequestExplanations = {
'listBuckets': 'This API call queries the Google Cloud Storage API ' +
'for a list of buckets in your project, and returns the result as ' +
'a list of Google Cloud Storage buckets.',
'listObjects': 'This API call queries the Google Cloud Storage API ' +
'for a list of objects in your bucket, and returns the result as ' +
'a list of Google Cloud Storage objects.',
'listBucketsAccessControls': 'This API call queries the Google Cloud ' +
'Storage API for the list of access control lists on buckets in your ' +
'project and returns the result as a list of Google Cloud Storage ' +
'Access Control Lists.',
'listObjectsAccessControls': 'This API call queries the Google Cloud ' +
'Storage API for the list of access control lists on objects in your ' +
'bucket and returns the result as a list of Google Cloud Storage ' +
'Access Control Lists.',
'getBucket': 'This API call queries the Google Cloud Storage API ' +
'for a bucket in your project, and returns the result as a ' +
'Google Cloud Storage bucket.',
'getBucketAccessControls': 'This API call queries the Google Cloud ' +
'Storage API for the access control list on a specific bucket ' +
'and returns the result as a Google Cloud Storage Access Control List.',
'getObjectAccessControls': 'This API call queries the Google Cloud ' +
'Storage API for the access control list on a specific object ' +
'and returns the result as a Google Cloud Storage Access Control List.',
'insertBucket': 'This API call uses the Google Cloud Storage API ' +
'to insert a bucket into your project.',
'insertObject': 'This API call uses the Google Cloud Storage API ' +
'to insert an object into your bucket.',
'insertBucketAccessControls': 'This API uses the Google Cloud ' +
'Storage API to insert an access control list on a specific bucket ' +
'and returns the result as a Google Cloud Storage Access Control List.',
'insertObjectAccessControls': 'This API uses the Google Cloud ' +
'Storage API to insert an access control list on a specific object ' +
'and returns the result as a Google Cloud Storage Access Control List.',
'deleteBucket': 'This API uses the Google Cloud Storage API to delete ' +
'an empty bucket and returns an empty response to indicate success.',
'deleteObject': 'This API uses the Google Cloud Storage API to delete ' +
'an object and returns an empty response to indicate success.'
};
/**
* Google Cloud Storage API request to retrieve the list of buckets in
* your Google Cloud Storage project.
*/
function listBuckets() {
var request = gapi.client.storage.buckets.list({
'projectId': PROJECT
});
executeRequest(request, 'listBuckets');
}
/**
* Google Cloud Storage API request to retrieve the list of objects in
* your Google Cloud Storage project.
*/
function listObjects() {
var request = gapi.client.storage.objects.list({
'bucket': BUCKET
});
executeRequest(request, 'listObjects');
}
/**
* Google Cloud Storage API request to retrieve the access control list on
* a bucket in your Google Cloud Storage project.
*/
function listBucketsAccessControls() {
var request = gapi.client.storage.bucketAccessControls.list({
'bucket': BUCKET
});
executeRequest(request, 'listBucketsAccessControls');
}
/**
* Google Cloud Storage API request to retrieve the access control list on
* an object in your Google Cloud Storage project.
*/
function listObjectsAccessControls() {
var request = gapi.client.storage.objectAccessControls.list({
'bucket': BUCKET,
'object': object
});
executeRequest(request, 'listObjectsAccessControls');
}
/**
* Google Cloud Storage API request to retrieve a bucket in
* your Google Cloud Storage project.
*/
function getBucket() {
var request = gapi.client.storage.buckets.get({
'bucket': BUCKET
});
executeRequest(request, 'getBucket');
}
/**
* Google Cloud Storage API request to retrieve a bucket's Access Control
* List in your Google Cloud Storage project.
*/
function getBucketAccessControls() {
var request = gapi.client.storage.bucketAccessControls.get({
'bucket': BUCKET,
'entity': GROUP
});
executeRequest(request, 'getBucketAccessControls');
}
/**
* Google Cloud Storage API request to retrieve an object's Access Control
* List in your Google Cloud Storage project.
*/
function getObjectAccessControls() {
var request = gapi.client.storage.objectAccessControls.get({
'bucket': BUCKET,
'object': object,
'entity': GROUP
});
executeRequest(request, 'getObjectAccessControls');
}
/**
* Google Cloud Storage API request to insert a bucket into
* your Google Cloud Storage project.
*/
function insertBucket() {
resource = {
'id': BUCKET,
'projectId': PROJECT
};
var request = gapi.client.storage.buckets.insert({
'resource': resource
});
executeRequest(request, 'insertBucket');
}
/**
* Google Cloud Storage API request to insert an object into
* your Google Cloud Storage bucket.
*/
function insertObject(event) {
try{
var fileData = event.target.files[0];
}
catch(e) {
//'Insert Object' selected from the API Commands select list
//Display insert object button and then exit function
filePicker.style.display = 'block';
return;
}
const boundary = '-------314159265358979323846';
const delimiter = "\r\n--" + boundary + "\r\n";
const close_delim = "\r\n--" + boundary + "--";
var reader = new FileReader();
reader.readAsBinaryString(fileData);
reader.onload = function(e) {
var contentType = fileData.type || 'application/octet-stream';
var metadata = {
'name': fileData.name,
'mimeType': contentType
};
var base64Data = btoa(reader.result);
var multipartRequestBody =
delimiter +
'Content-Type: application/json\r\n\r\n' +
JSON.stringify(metadata) +
delimiter +
'Content-Type: ' + contentType + '\r\n' +
'Content-Transfer-Encoding: base64\r\n' +
'\r\n' +
base64Data +
close_delim;
//Note: gapi.client.storage.objects.insert() can only insert
//small objects (under 64k) so to support larger file sizes
//we're using the generic HTTP request method gapi.client.request()
var request = gapi.client.request({
'path': '/upload/storage/v1beta2/b/' + BUCKET + '/o',
'method': 'POST',
'params': {'uploadType': 'multipart'},
'headers': {
'Content-Type': 'multipart/mixed; boundary="' + boundary + '"'
},
'body': multipartRequestBody});
//Remove the current API result entry in the main-content div
listChildren = document.getElementById('main-content').childNodes;
if (listChildren.length > 1) {
listChildren[1].parentNode.removeChild(listChildren[1]);
}
try{
//Execute the insert object request
executeRequest(request, 'insertObject');
//Store the name of the inserted object
object = fileData.name;
}
catch(e) {
alert('An error has occurred: ' + e.message);
}
}
}
/**
* Google Cloud Storage API request to insert an Access Control List into
* your Google Cloud Storage bucket.
*/
function insertBucketAccessControls() {
resource = {
'entity': ENTITY,
'role': ROLE
};
var request = gapi.client.storage.bucketAccessControls.insert({
'bucket': BUCKET,
'resource': resource
});
executeRequest(request, 'insertBucketAccessControls');
}
/**
* Google Cloud Storage API request to insert an Access Control List into
* your Google Cloud Storage object.
*/
function insertObjectAccessControls() {
resource = {
'entity': ENTITY,
'role': ROLE_OBJECT
};
var request = gapi.client.storage.objectAccessControls.insert({
'bucket': BUCKET,
'object': object,
'resource': resource
});
executeRequest(request, 'insertObjectAccessControls');
}
/**
* Google Cloud Storage API request to delete a Google Cloud Storage bucket.
*/
function deleteBucket() {
var request = gapi.client.storage.buckets.delete({
'bucket': BUCKET
});
executeRequest(request, 'deleteBucket');
}
/**
* Google Cloud Storage API request to delete a Google Cloud Storage object.
*/
function deleteObject() {
var request = gapi.client.storage.objects.delete({
'bucket': BUCKET,
'object': object
});
executeRequest(request, 'deleteObject');
}
/**
* Removes the current API result entry in the main-content div, adds the
* results of the entry for your function.
* #param {string} apiRequestName The name of the example API request.
*/
function updateApiResultEntry(apiRequestName) {
listChildren = document.getElementById('main-content')
.childNodes;
if (listChildren.length > 1) {
listChildren[1].parentNode.removeChild(listChildren[1]);
}
if (apiRequestName != 'null') {
window[apiRequestName].apply(this);
}
}
/**
* Determines which API request has been selected, and makes a call to add
* its result entry.
*/
function runSelectedApiRequest() {
var curElement = document.getElementById('api-selection-options');
var apiRequestName = curElement.options[curElement.selectedIndex].value;
updateApiResultEntry(apiRequestName);
}
/**
* Binds event listeners to handle a newly selected API request.
*/
function addSelectionSwitchingListeners() {
document.getElementById('api-selection-options')
.addEventListener('change',
runSelectedApiRequest, false);
}
/**
* Template for getting JavaScript sample code snippets.
* #param {string} method The name of the Google Cloud Storage request
* #param {string} params The parameters passed to method
*/
function getCodeSnippet(method, params) {
var objConstruction = "// Declare your parameter object\n";
objConstruction += "var params = {};";
objConstruction += "\n\n";
var param = "// Initialize your parameters \n";
for (i in params) {
param += "params['" + i + "'] = ";
param += JSON.stringify(params[i], null, '\t');
param += ";";
param += "\n";
}
param += "\n";
var methodCall = "// Make a request to the Google Cloud Storage API \n";
methodCall += "var request = gapi.client." + method + "(params);";
return objConstruction + param + methodCall;
}
/**
* Executes your Google Cloud Storage request object and, subsequently,
* inserts the response into the page.
* #param {string} request A Google Cloud Storage request object issued
* from the Google Cloud Storage JavaScript client library.
* #param {string} apiRequestName The name of the example API request.
*/
function executeRequest(request, apiRequestName) {
request.execute(function(resp) {
console.log(resp);
var apiRequestNode = document.createElement('div');
apiRequestNode.id = apiRequestName;
var apiRequestNodeHeader = document.createElement('h2');
apiRequestNodeHeader.innerHTML = apiRequestName;
var apiRequestExplanationNode = document.createElement('div');
apiRequestExplanationNode.id = apiRequestName + 'RequestExplanation';
var apiRequestExplanationNodeHeader = document.createElement('h3');
apiRequestExplanationNodeHeader.innerHTML = 'API Request Explanation';
apiRequestExplanationNode.appendChild(apiRequestExplanationNodeHeader);
var apiRequestExplanationEntry = document.createElement('p');
apiRequestExplanationEntry.innerHTML =
listApiRequestExplanations[apiRequestName];
apiRequestExplanationNode.appendChild(apiRequestExplanationEntry);
apiRequestNode.appendChild(apiRequestNodeHeader);
apiRequestNode.appendChild(apiRequestExplanationNode);
var apiRequestCodeSnippetNode = document.createElement('div');
apiRequestCodeSnippetNode.id = apiRequestName + 'CodeSnippet';
var apiRequestCodeSnippetHeader = document.createElement('h3');
apiRequestCodeSnippetHeader.innerHTML = 'API Request Code Snippet';
apiRequestCodeSnippetNode.appendChild(apiRequestCodeSnippetHeader);
var apiRequestCodeSnippetEntry = document.createElement('pre');
//If the selected API command is not 'insertObject', pass the request
//paramaters to the getCodeSnippet method call as 'request.B.rpcParams'
//else pass request paramaters as 'request.B'
if (apiRequestName != 'insertObject') {
apiRequestCodeSnippetEntry.innerHTML =
getCodeSnippet(request.B.method, request.B.rpcParams);
//Selected API Command is not 'insertObject'
//hide insert object button
filePicker.style.display = 'none';
} else {
apiRequestCodeSnippetEntry.innerHTML =
getCodeSnippet(request.B.method, request.B);
}
apiRequestCodeSnippetNode.appendChild(apiRequestCodeSnippetEntry);
apiRequestNode.appendChild(apiRequestCodeSnippetNode);
var apiResponseNode = document.createElement('div');
apiResponseNode.id = apiRequestName + 'Response';
var apiResponseHeader = document.createElement('h3');
apiResponseHeader.innerHTML = 'API Response';
apiResponseNode.appendChild(apiResponseHeader);
var apiResponseEntry = document.createElement('pre');
apiResponseEntry.innerHTML = JSON.stringify(resp, null, ' ');
apiResponseNode.appendChild(apiResponseEntry);
apiRequestNode.appendChild(apiResponseNode);
var content = document.getElementById('main-content');
content.appendChild(apiRequestNode);
});
}
/**
* Set required API keys and check authentication status.
*/
function handleClientLoad() {
gapi.client.setApiKey(apiKey);
window.setTimeout(checkAuth, 1);
}
/**
* Authorize Google Cloud Storage API.
*/
function checkAuth() {
gapi.auth.authorize({
client_id: clientId,
scope: scopes,
immediate: true
}, handleAuthResult);
}
/**
* Handle authorization.
*/
function handleAuthResult(authResult) {
var authorizeButton = document.getElementById('authorize-button');
if (authResult && !authResult.error) {
authorizeButton.style.visibility = 'hidden';
initializeApi();
filePicker.onchange = insertObject;
} else {
authorizeButton.style.visibility = '';
authorizeButton.onclick = handleAuthClick;
} console.log(gapi.auth);
}
/**
* Handle authorization click event.
*/
function handleAuthClick(event) {
gapi.auth.authorize({
client_id: clientId,
scope: scopes,
immediate: false
}, handleAuthResult);
return false;
}
/**
* Load Google Cloud Storage API v1beta12.
*/
function initializeApi() {
gapi.client.load('storage', API_VERSION);
}
/**
* Driver for sample application.
*/
$(window)
.bind('load', function() {
gapi.auth.setToken('<?php print $access_token["access_token"]; ?>');
gapi.auth.token= '<?php print $access_token["access_token"]; ?>';
console.log(gapi.auth.getToken());
addSelectionSwitchingListeners();
handleClientLoad();
});
</script>
</head>
<body>
<!--Add a button for the user to click to initiate auth sequence -->
<button id="authorize-button" style="visibility: hidden">Authorize</button>
<header>
<h1>Google Cloud Storage JavaScript Client Library Application</h1>
</header>
<label id="api-label">Try a sample API call!</label>
<select id="api-selection-options">
<option value="null">
Please select an example API call from the dropdown menu
</option>
<option value="listBuckets">
List Buckets
</option>
<option value="listObjects">
List Objects
</option>
<option value="listBucketsAccessControls">
List Buckets Access Control List
</option>
<option value="listObjectsAccessControls">
List Objects Access Control List
</option>
<option value="getBucket">
Get Bucket
</option>
<option value="getBucketAccessControls">
Get Bucket Access Controls
</option>
<option value="getObjectAccessControls">
Get Object Access Controls
</option>
<option value="insertBucket">
Insert Bucket
</option>
<option value="insertObject">
Insert Object
</option>
<option value="insertBucketAccessControls">
Insert Bucket Access Controls
</option>
<option value="insertObjectAccessControls">
Insert Object Access Controls
</option>
<option value="deleteBucket">
Delete Bucket
</option>
<option value="deleteObject">
Delete Object
</option>
</select>
<br/>
<input type="file" id="filePicker" style="display: none" />
<div id="main-content">
</div>
</body>
</html>
Does anyone have any ideas? I'm not being successful because my console prints this out:
as an error loading the page https://accounts.google.com/o/oauth2/auth?client_id=YOUR_CLIENT_ID&scope=ht…ifechurch.tv&response_type=token&state=412841043%7C0.2670569503&authuser=0
While it is possible to retrieve an access token in your server code for a service account, and then include that as part of a web-page or Javascript response to allow a browser direct access to Google Cloud Storage - this is generally a very dangerous approach, as the access token will allow anyone who has it full access to all of your Cloud Storage resources - without opportunity for your trusted server-side code to be able to apply access control restrictions specific to your application (for example to allow a user of your application only to upload/downloads files/object they should have access to).
Direct file upload/download to Cloud Storage can however be achieved a slightly different way. Google Cloud Storage supports a signed URL - this is a URL that you can generate in your server code (using the same private key you used to get an access token) that allows the bearer the ability to upload or download a specific file for a specific period of time.
Documentation for this can be found here:
https://developers.google.com/storage/docs/accesscontrol#Signed-URLs
And an example from PHP here:
https://groups.google.com/forum/#!msg/google-api-php-client/jaRYDWdpteQ/xbNTLfDhUggJ
Once you generate this URL on your server you can pass to the browser, which in turn can then PUT directly to that URL, or GET directly from it without the need to use any special Google Javascript libraries. See for an example: Google Storage REST PUT With Signed URLs
I have recently completed a similar project using Ajax to access my PHP class which controls the access token renewals, connection URls etc. As it a live connection over HTTPS no sensitive information is visible in code and I can then load the relevant data directly into javascript.
Hope this helps
We are working on a greasemonkeyscript to pull data from an express server cross-domain.
(We found code which is working for a normal html site here:
)
Can you get this to work for greasemonkey?
(maybe with unsafeWindow ?)
app.js:
var express = require("express");
var app = express();
var fs=require('fs');
var stringforfirefox = 'hi buddy!'
// in the express app for crossDomainServer.com
app.get('/getJSONPResponse', function(req, res) {
res.writeHead(200, {'Content-Type': 'application/javascript'});
res.end("__parseJSONPResponse(" + JSON.stringify( stringforfirefox) + ");");
});
app.listen(8001)
greasemonkeyscript:
// ==UserScript==
// #name greasemonkeytestscript
// #namespace http://www.example.com/
// #description jQuery test script
// #include *
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js
// ==/UserScript==
function __parseJSONPResponse(data) { alert(data); } // ??????????
document.onkeypress = function keypressed(e){
if (e.keyCode == 112) {
var script = document.createElement('script');
script.src = 'http://localhost:8001/getJSONPResponse';
document.body.appendChild(script); // triggers a GET request
alert(script);
}
}
I've never used Express before, but that app looks to be returning code like:
__parseJSONPResponse("\"hi buddy!\"");
which is placed into a <script> node in the target-page scope.
This means that the Greasemonkey script must also place the __parseJSONPResponse function in the target-page scope.
One way to do that is:
unsafeWindow.__parseJSONPResponse = function (data) {
alert (data);
}
However, it looks like you control the Express app. If that's true, then don't use JSONP for this kind of thing. Use GM_xmlhttpRequest().
app.js might become:
var express = require ("express");
var app = express ();
var fs = require ('fs');
var stringforfirefox = 'hi buddy!'
app.get ('/getJSONPResponse', function (req, res) {
res.send (JSON.stringify (stringforfirefox) );
} );
app.listen (8001)
And the GM script would be something like:
// ==UserScript==
// #name greasemonkeytestscript
// #namespace http://www.example.com/
// #description jQuery test script
// #include *
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// #grant GM_xmlhttpRequest
// ==/UserScript==
document.onkeypress = function keypressed (e){
if (e.keyCode == 112) {
GM_xmlhttpRequest ( {
method: 'GET',
url: 'http://localhost:8001/getJSONPResponse',
onload: function (respDetails) {
alert (respDetails.responseText);
}
} );
}
}