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

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

# spreadsheet側の処理

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

```js
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時間後...

もう一回やろう

```
$ 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"
  }
}
```

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

１時間ごとに`access_token`が変わってしまうようだ。
困った。１時間ごとに手動で`access_token`を取得してこないといけないのか。。。
いや、`refresh_token`というものがあり、それは勝手に変わったりしないようで`resresh_token`で`access_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仕様になっていない。
まあ、それはさておき

```js
"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にしていてハマった。
クエリみたいに`&`じゃないといけないみたい