LoginSignup
5
6

More than 5 years have passed since last update.

Alexaのスキルを使ってスプレッドシートに書き込む

Last updated at Posted at 2018-04-23

アレクサからspreadsheetに書き込むってことをやろうとした。
意外とハマったので備忘録ように書いておこう。

spreadsheet側の処理

とりあえず、コードを書く。
パラメーターを受け取り、spreadsheetにそれを書き込むっていう簡単なやつ。

function hoge(val){
  // idよりスプレッドシート取得
  var spreadsheet = SpreadsheetApp.openById(id);

  // シート取得
  var sheet = spreadsheet.getSheetByName("hoge");

  // 値を書き込む
  sheet.getRange("A1").setValue(val);
}

doget関数とか使ってgetでgasに投げてあげる方法とかもできるのかもしれないが、以下の記事を参考にExecution APIを使った。
https://qiita.com/soundTricker/items/1bcfc5c9e80d29a7ae4b

とりあえず、access_tokenまで取得したとする。

$ curl https://script.googleapis.com/v1/scripts/...:run -X POST -H "Content-Type: application/json" -H "Authorization: Bearer access_token" -d '{"function": "hoge", "parameters": "これがパラメータ", "devMode": true}'

{
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.apps.script.v1.ExecutionResponse"
  }
}

うまく行った。
疲れた。1時間休憩しよう。

...1時間後...

もう一回やろう

$ curl https://script.googleapis.com/v1/scripts/...:run -X POST -H "Content-Type: application/json" -H "Authorization: Bearer access_token" -d '{"function": "hoge", "parameters": "これがパラメータ", "devMode": true}' 

{
  "error": {
    "code": 401,
    "message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
    "status": "UNAUTHENTICATED"
  }
}

あ、れ、うまくいかない。

1時間ごとにaccess_tokenが変わってしまうようだ。
困った。1時間ごとに手動でaccess_tokenを取得してこないといけないのか。。。
いや、refresh_tokenというものがあり、それは勝手に変わったりしないようでresresh_tokenaccess_tokenを取得できるようだ。

$ curl --data "refresh_token={りふれっしゅとーくん}" --data "client_id={くらいあんとあいでぃ}" --data "client_secret={くらいあんとしーくれっと}" --data "grant_type=refresh_token" https://www.googleapis.com/oauth2/v4/token

{
 "access_token": "あくせすとーくんくん",
 "token_type": "Bearer",
 "expires_in": 3600
}

おーーーとれた。

てことで、node.js(lambda側)をかこう
と見せかけて、長くなるのでask仕様になっていない。
まあ、それはさておき

"use strict";
var rp = require('request-promise');

// --------------------------request設定----------------------------------
var accessOptions = function(accessURL, params){
  var result = {
    uri: accessURL,
    method: "POST",
    port: 443,
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    body: params,
  }
  return result;
};

// gasに送信するデータ
var gasPostData = function(parameter){
  var result = {
    "function": "hoge", // 起動する関数名
    "parameters": parameter, // パラメータ(配列)
    "devMode": true
  }
  return result;
};

var gasOptions = function(gasURL, accessToken, gasPostData){
  var result = {
    uri: gasURL,
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      "Authorization": "Bearer " + accessToken // ここは、access_tokenを取得したら書き換える
    },
    body: gasPostData,
    json: true
  };
  return result;
};
// --------------------------request設定----------------------------------


// インテント
const comeOutIntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && handlerInput.requestEnvelope.request.intent.name === 'comeOutIntent';
  },
  handle(handlerInput) {
    // lambdaの環境変数から取得
    var code = process.env["code"]; // Authorize code
    var gasURL = process.env["gasURL"]; //gasのurl。...の部分はAPP ID

    var refreshToken = process.env["refreshToken"]; // refresh_token
    var clientId = process.env["clientId"]; // client_id
    var clientSecret = process.env["clientSecret"]; // client_secret
    var grantType = "refresh_token";
    var accessURL = process.env["accessURL"];
    var params = `refresh_token=${refreshToken}&client_id=${clientId}&client_secret=${clientSecret}&grant_type=${grantType}` // access_token取得する時に必要なパラメータ。jsonだとうまくいかない

    var msg = "おはようございます";
    var val = []; // なんか送りたいデータを入れる

    return new Promise((resolve, reject) => {
      rp(accessOptions(accessURL, params)).then((accessResponse) => {
        var accessToken = JSON.parse(accessResponse).access_token;
        var gasPost = gasPostData(val);
        rp(gasOptions(gasURL, accessToken, gasPost)).then((response) => {

          resolve(handlerInput.responseBuilder
            .speak(msg)
            .reprompt(msg)
            .withSimpleCard('カードを表示します', msg)
            .getResponse());
        });
      });
    });

  }
};

jsonで送ってもうまくいかなかった。

最初、paramをjsonにしていてハマった。
クエリみたいに&じゃないといけないみたい

5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6