问题
Hello kind people of the internet, I'm struggling to make an UPDATE to a Google Fusion Table occur via Javascript...and this is a bit of blog, but thought I'd just write it all up in one place rather than piece meal questions (that are all inter-related).
I'm able to do SELECT from Fusion Tables (easy) and I'm also able to retrieve the Auth Token via oauth (bit more work), so it would seem reasonable that an UPDATE of a field value by RowID and field name would be doable.
There are a number of fairly good posts and examples for the google-api-javascript-client, but alas, after reading and reading many of these posts, I have not successfully been able to combine and extrapolate to make them work for my intended purpose:
-I would like users of a web page to be allowed to make a simple update, via javascript, of an already existing record in my Fusion Table (use Fusion Tables as a database), without relying on any server side PHP or Java for the oauth, etc.
Question on the above point: Is this a reasonable thing to attempt via javascript alone?...or should I just abandon the 'client' side strategy?...and instead develop a server side architecture (for handling Fusion Tables as a db).
Some specific Questions for the UPDATE via javascript: A.) Does the UPDATE require the API key on the REST call?
B.)...or does the REST call require just the Auth Token?
C.)...or both the API key and Auth token?
D.) Does the UPDATE require the "&callback=?" on the REST call?
E.) Can the GWT oauth javascript library ( http://code.google.com/p/gwt-oauth2/ ) be combined with the javascript-api-client library ( https://code.google.com/p/google-api-javascript-client/ )? Or is this mixing apples and oranges?
F.) How perhaps would a pure REST call to fusion tables for doing an UPDATE be composed and formatted using just the jQuery library? How would the headers and the POST method be included in the url string?..what about the auth Token?, and how would the call back be done?
F.1) The "gapi.client.request" method of the google-api-javascript-client has a structure for submitting the REST call...I suppose that's why the library exists: but how/where does the "gapi.client.request" explicitly include the auth token?...is it suppose to be part of the URL string?
Here's an example of the URL that is being pushed through the gapi.client.request for the REST call...the real tableID is of course in the string, and of course the access token below has already expired...but the basic SQL is: UPDATE TABLEID SET STATUS COMPLETED WHERE ROWID 2
https://www.googleapis.com/fusiontables/v1/query?sql=UPDATE%20 TABLEID %20SET%20STATUS%20%3D%20COMPLETED%20WHERE%20ROWID%20%3D%20'2'&access_token=ya29.AHES6ZSCxJu4V0kOXN98H3PBKJon6ynewZ4jI4w9iFs3IOs7
The above looks like it should basically work and update the table, but dang darn heck, does not.
Here's my testing code, and it's a bit messy as I've tried many dozens of combinations:
Note that I'm also struggling with the callback...as it's not working (yet) either, and yes, perhaps if I could see the call back I could better troubleshoot the situation (I feel that I must be fairly close to a solution, so don't want to give up just yet and fall back to PHP server side)...so any help on the callback would be much appreciated too.
thanks much in advance for any help/insight you might be able to provide.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%@ Page Language="C#" %>
<html dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled 1</title>
<script type="text/javascript" src="gwt-oauth2.js"></script>
<script src="https://apis.google.com/js/client.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
</head>
<body>
<form id="form1" runat="server">
<div data-role="fieldcontain" id="div-myButton1" >
<p></p>
<input type="button" id="myButton1" value="oAuth & Get Token" />
<p></p>
</div>
<p id="myOutput"><i>token goes here 3...</i></p>
<div data-role="fieldcontain" id="div-myButton2" >
<p></p>
<input type="button" id="myButton2" value="Attempt Fusion Table Update" />
<p></p>
</div>
<p id="myOutput2"><i>transmitted POST url here...</i></p>
<p id="insert-data-output"><i>Fusion table callback status here...</i></p>
<script type="text/javascript">
$( "#myButton1" ).click(function() {
//Using the GWT oauth2 javascript library to get the Auth token
//...as was not able to explicitly retrieve token using the google-api-javascript
//alert("got here");
var GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/auth";
//my client ID
var GOOGLE_CLIENT_ID = "YOURID.apps.googleusercontent.com";
var PLUS_ME_SCOPE = "https://www.googleapis.com/auth/plus.me";
//
var req = {
"authUrl" : GOOGLE_AUTH_URL,
"clientId" : GOOGLE_CLIENT_ID,
//"scopes" : [ PLUS_ME_SCOPE ],
"scopes" : ['https://www.googleapis.com/auth/fusiontables'],
};
oauth2.login(req, function(token) {
//alert("Got an OAuth token:\n" + token + "\n"
// + "Token expires in " + oauth2.expiresIn(req) + " ms\n");
//
myOutput.innerText = token;
//
}, function(error) {
alert("Error:\n" + error);
});
});
</script>
<script type="text/javascript">
$( "#myButton2" ).click(function() {
//Attempting to update a Fusion Table record using gapi, google-api-javascript
//...as was not able to update using the GWT javascript library
//
//TBD???: Where does the auth Token go when composing the REST update string?...tac on to the end?
//??does UPDATE also require the API key?...if so where in the string?
//
//alert("got here");
//myOutput2.innerText = "got here";
//
//my Fusion Table: TABLEID
var query = "UPDATE TABLEID SET STATUS = COMPLETED WHERE ROWID = '2'";
var encodedQuery = encodeURIComponent(query);
// Construct the URL
//the push seems to be putting in extra commas! :-(
//var url = ['https://www.googleapis.com/fusiontables/v1/query'];
var url = 'https://www.googleapis.com/fusiontables/v1/query';
//url.push('?sql=' + encodedQuery);
url = url + '?sql=' + encodedQuery;
//my API key
//url.push('&key=YOURAPIKEY');
//Is the API Key required?
//&access_token=
//another choice might be to drop the API key, and put in the access token
//url.push('&access_token=');
myAccessTokenIs = '&access_token=' + myOutput.innerText;
//url.push(myAccessTokenIs);
url = url + myAccessTokenIs;
//maybe drop the call back stuff too???
//url.push('&callback=?');
//
//alert("my url is: " + url);
myOutput2.innerText = url;
//
var path = '/fusiontables/v1/query';
//
//used for the callback of the gapi.client.request
var callback = function(what) {
alert("got to call back??");
var output = JSON.stringify(what);
insert-data-output.innerText = output;
};
////var callback = function(element) {
// return function(resp) {
// var output = JSON.stringify(resp);
// document.getElementById(element).innerHTML = output;
//};
//
gapi.client.request({
path:path,
body: url,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
method:'POST'},
callback
);
});
</script>
<script>
function helloCallBack(callback) {
//callback('insert-data-output');
};
</script>
</form>
</body>
</html>
回答1:
I try to answer all your questions:
- See the JavaScript API example to see the usage of the gapi-client. You need the API key for all requests and the client_id and the OAuth scope to authorize a user.
- What you want is not exactly possible: if you want a client-side only solution, all you can do is ask a user to authenticate with their account (like the example above). But if you want to access one specific table that you share, you have to have some kind of server-side code.
- I started using the JSONP API first (creating calls with jQuery, like you suggested), but then switched to the gapi-client. It's easier, it can give you meaningful error messages and I had no problem to access my data.
I had very similar requirements: use client-side code as much as possible, access a single table that belongs to my Google-Account (using FT as database). The key is to use a so called Service Account. Instead of asking the user to authorize, you do this on the server with the Service Account:
- Create the account
- Set permission on the table for the Service Account
- Authorize the account (aquire the access token)
- Make authorized requests
Now you have 2 options:
- Route all request to the fusion table via your server (adding the access token)
OR
- Give the acquired token to the client side, and handle all request from there
The second option is dangerous, because this means that the Service Account is public, so you have to check carefully which permissions you give to this account (i.e. it's possible to delete records if you don't pay attention), but aside from that you reduce the amount of server-side code to a minimum.
In my application I choose this second option. But to limit the possibilities of the account I created as read-view and a write-view of my table. And the Service Account only got access to those two views. On the read-view the account has "Viewer" permission and can therefore read the whole table (SELECT statements). On the write-view it has "Editor"-permission, which makes it possible to INSERT / UPDATE / DELETE (although DROP is not possible).
I personally didn't use the GWT library, but I can't see a reason why this should not work. I did the server-side call with the PHP OAuth library. The repository with my code is public, the interesting part for you might be my JavaScript library for FT (GftLib) and the server side code (JSONP interface to get the access token of the Service Account to the client).
I think I answered all of your questions, if I left something, feel free to ask for clarification.
来源:https://stackoverflow.com/questions/11595122/google-fusion-table-api-v1-properly-composed-rest-format-to-post-an-update