OAuth, OAuthConfig, & Google Apps Script (Fusion T

2019-04-16 23:55发布

问题:

I am developing a google apps script function that will insert a row into a fusion table. Most of my fusion table interface works fine but this is my first attempt at an sql 'POST' query. Based on the documentation here I should be able to put the sql statement within the POST body. I've reduced myself to the OAuth Playground for troubleshooting and I keep getting the following error. I've been trying to use the sql insert statement sql=INSERT INTO {fusionId} (HeadingName) VALUES (ValueOne) and I have tried various variations of this statement to no avail. Please help me determine the proper syntax or method to do this.

{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "required",
    "message": "Required parameter: sql",
    "locationType": "parameter",
    "location": "sql"
   }
  ],
  "code": 400,
  "message": "Required parameter: sql"
 }
}

Once I figure this out, I then need to duplicate the playground operation within my code, which (I think) will look something like this:

function fusionRequest(methodType, sql, oAuthFields) {
  OAL.googleAuth(oAuthFields);
  var options =
    {
      oAuthUseToken : "always",
      oAuthServiceName : 'fusiontables',
      method : "POST",
      payload : "sql=INSERT INTO {fusionId} (Heading) VALUES (ONE)",
      contentType : "application/json"
    };
Logger.log(options)
  var fetchResult = UrlFetchApp.fetch(oAuthFields.queryUrl, options);
  return JSON.parse(fetchResult.getContentText());  
}

I've been thinking it could also be a problem with the content-type, but I am at a loss. Please help.

Update #1 By using Sanya's advice I was able to get the request working in the OAuth Playground. However, I'm still struggling with the request in the code. I am getting repeated requests for authorization when running the code (or a general OAuth Error when debugged). From my previous experience here, I believe this means that there is still something wrong with my payload. Any advice on this would be much appreciated.

var oAuthFields = {
  'clientId' : '523606257547.apps.googleusercontent.com',
  'scope' : 'https://www.googleapis.com/auth/fusiontables',
  'fetchUrl' : 'https://www.googleapis.com/fusiontables/v1/',
  'clientSecret' : 'L-f8DgwK4rs7Qmw9k5IFL7lZ',
  'fusionId' : '1b4kT_aYRfNBy8ZPtSZqhQUqVSVIYj_QWiBmjXXI',
  'service' : 'fusiontables',
  'queryUrl' : 'https://www.googleapis.com/fusiontables/v1/query/'
};
function fusionRequest(methodType, sql, oAuthFields) {
  OAL.googleAuth(oAuthFields);
  var options =
    {
      oAuthUseToken : "always",
      oAuthServiceName : 'fusiontables',
      method : "POST",
      payload : "sql=INSERT INTO {fusion id} (\'Heading\') VALUES (\'ONE\')",
      contentType : "application/x-www-form-urlencoded"
    };
  var fetchResult = UrlFetchApp.fetch(oAuthFields.queryUrl, options);
  return JSON.parse(fetchResult.getContentText());  
}

For context, the googleAuth() function and overall layout of this function is the same as a function I use to add columns in the fusion table (which works).

回答1:

The documentation is faulty and there are some details missing.

You can use the sql=... parameter in the request url. The ContentType header usually is application/json but the API probably accepts other ContentTypes too. In this case you're limited in 2048 characters URL length.

You can also use sql=... in the POST body. In this case you have to set the ContentType must be application/x-www-form-urlencoded. You are limited to 500 INSERT statements in 1 request.

Another option is to use the importRows method. Here you will use a CSV as the POST body. In this method you're limited by 100MB uploaded data. The ContentType must be "application/octet-stream". Be careful: the url is different than the above: https://www.googleapis.com/upload/fusiontables/v1/tables/tableId/import. Also if you provide non UTF-8 characters in the body you must give an &encoding=... url parameter More details here: importRows reference



回答2:

SUCCESS! After lots of research, I have resolved the problem. It was not a payload or contentType issue (in fact, I found that the .fetch automatically defaulted to the "application/x-www-form-urlencoded" encoding). The issue was with the authorization. I used James Ferreira's Fusion Table Library as a model and inserted Logger.log(UrlFetchApp.getRequest(url, fetchArgs)) before the UrlFetchApp.fetch(url, fetchArgs).getContentText() in both my code and the library's.

//log entry for library
{oAuthServiceName=fusion, useIntranet=false, followRedirects=true, oAuthUseToken=always, payload=sql=INSERT INTO 1b4kT_aYRfNBy8ZPtSZqhQUqVSVIYj_QWiBmjXXI ('Heading', 'Heading 2') VALUES ('NONE','TWO'), method=POST, validateHttpsCertificates=true, contentType=application/x-www-form-urlencoded, url=https://www.google.com/fusiontables/api/query}

//log entry for my code
{oAuthServiceName=fusiontables, useIntranet=false, followRedirects=true, oAuthUseToken=always, payload=sql=INSERT+INTO+1b4kT_aYRfNBy8ZPtSZqhQUqVSVIYj_QWiBmjXXI+('Heading',+'Heading+2')+VALUES+('NONE','TWO'), method=POST, validateHttpsCertificates=true, contentType=application/x-www-form-urlencoded, url=https://www.googleapis.com/fusiontables/v1/query}

I then compared the log of the working library to that of my own and found three differences.

  1. What I think is a difference of encoding for the sql statement ("INSERT INTO" vs. "INSERT+INTO").
  2. The 'service' parameter of the request was different ("fusion" vs. "fusiontables").
  3. The qpi query url was different. ("www.google.com/fusiontables/api/query" vs. "www.googleapis.com/fusiontables/v1/query).

After some experimentation, I determined that ...

  1. The supposed encoding was irrelevant to my error.
  2. The service parameter was also irrelevant. I have seen both in various documentation and either one seems to work.
  3. Frustratingly, this was the issue. It's frustrating because the api documentation says to use the one THAT DOESN'T WORK. Apparently, www.googleapis.com/fusiontables/v1/query is for use with OAuth2.0. OAuthConfig (the bult-in authorization tool that I'm using in GAS) has not been migrated to 2.0 so there was a lapse of documentation. I have submitted a feature request to migrate OAuthConfig here. Please give that thread some love if you also want it to be addressed.