简体   繁体   中英

Google Sheets AddOn - AppScript & BigQuery Integration via Service Account

I have a Google Sheets workspace addon and recently did some work to integrate BigQuery. Essentially BigQuery hold a record of books each of which has an author, title etc and my Addon allows people to pull the books that they have read into their sheet. The first column in the sheet allows people to choose from all the authors in the DB, based on that selection the second column is populated with data from BigQuery with all books by that author etc etc. There is no need for my AddOn to access a user's BigQuery, they only access 'my' BgQuery.

This all works fine, but when I submitted my addon for approval I was told

Unfortunately, we cannot approve your request for the use of the following scopes 

https://www.googleapis.com/auth/bigquery

We recommend using service accounts for this type of information exchange. 

This seems fair and reading up on Service Accounts it seems a much better fit for my use case. I've gone through the process of creating the service accounts and downloaded my security details json file, however I just can't figure out how to actually query BigQuery from AppScript.

In my non-service account method I have the BigQuery Library installed in AppScript and basically run

var queryResults = BigQuery.Jobs.query(request, projectId);

I've been trying to work from an example at https://developers.google.com/datastudio/solution/blocks/using-service-accounts

function getOauthService() {
var serviceAccountKey = getServiceAccountCreds('SERVICE_ACCOUNT_KEY');// from private_key not private_key_id of JSON file
var serviceAccountEmail = getServiceAccountCreds('SERVICE_ACCOUNT_EMAIL');
return OAuth2.createService('RowLevelSecurity')
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setPrivateKey(serviceAccountKey)
.setIssuer(serviceAccountEmail)
.setPropertyStore(scriptProperties)
.setCache(CacheService.getScriptCache())
.setScope(['https://www.googleapis.com/auth/bigquery.readonly']);
}
function getData(request) {
var accessToken = getOauthService().getAccessToken();
var billingProjectId = getServiceAccountCreds('BILLING_PROJECT_ID');
// var email = Session.getEffectiveUser().getEmail();
// return cc
// .newBigQueryConfig()
// .setAccessToken(accessToken)
// .setBillingProjectId(billingProjectId)
// .setUseStandardSql(true)
// .setQuery(BASE_SQL)
// .addQueryParameter('email', bqTypes.STRING, email)
// .build();
}

I've commented out the code in the above which relates to

var cc = DataStudioApp.createCommunityConnector();

in the above tutorial since I'm not using DataStudio but I'm really not sure what to replace it with so I can query BigQuery with AppScript via a Service Account. Can anyone offer any advice?

Based on the advice from @TheAddonDepot in the comments above my revised code now looks like:

function getBigQueryService() {
  return (
    OAuth2.createService('BigQuery')
      // Set the endpoint URL.
      .setTokenUrl('https://accounts.google.com/o/oauth2/token')

      // Set the private key and issuer.
      .setPrivateKey(JSON_CREDS.private_key) // from the json file downloaded when you create service account
      .setIssuer(JSON_CREDS.client_email). // from the json file downloaded when you create service account

      // Set the property store where authorized tokens should be persisted.
      .setPropertyStore(PropertiesService.getScriptProperties())

      // Caching
      .setCache(CacheService.getUserCache())

      // Locking
      .setLock(LockService.getUserLock())

      // Set the scopes.
      .setScope(['https://www.googleapis.com/auth/bigquery.readonly'])
     // .setScope('https://www.googleapis.com/auth/bigquery')
  )
}


 function queryData(){
  const bigQueryService = getBigQueryService()
  if (!bigQueryService.hasAccess()) {
    Logger.log("BQ ERROR IS "+ bigQueryService.getLastError())
  }

  //const projectId = bigqueryCredentials.project_id
  var projectId = "<yourprojectid>"

  let url = 'https://bigquery.googleapis.com/bigquery/v2/projects/<yourprojectid>/queries'; //projectID is taken from the security json file for the service account, although it doesn't seem to matter if you use the project code
  
  const headers = {
    Authorization: `Bearer ${bigQueryService.getAccessToken()}`,
    'Content-Type': 'application/json',
  }


 var data = {query:"<your query>",useLegacySql:false};
  const options = {
    method: 'post',
    headers,
    //contentType: 'application/json',
    payload: JSON.stringify(data),
   muteHttpExceptions: true // on for debugging
  }

  try {
    const response = UrlFetchApp.fetch(url, options)
    const result = JSON.parse(response.getContentText())
    Logger.log("here is result "+ JSON.stringify(result))

  } catch (err) {
    console.error(err)
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM