GASを使ってGoogleスプレッドシートからFilemakerにデータを持ってくる方法（認証付き）

# 目的
* [前回の方法](https://qiita.com/unkonow/items/60fab55aac218155dde5)だと公開範囲ガバガバなので認証を付けることに・・・
* スプレッドシートが親のケースで任意のタイミングでFilemakerにデータを同期する。

## 方法
* GoogleのAPIを使ってリフレッシュトークンを取得し、トークンを自動で取得して操作する<br>（じゃないと1時間でアクセストークンを手動で取得するというね）
* この記事の作成に当たっては以下の記事を大いに参考にさせていただきました。この場を借りて感謝いたします。<br>https://qiita.com/sikkim/items/7002e9a1551fc347dab4

### GAS
前記事とGASのスクリプトは変わりません。公開範囲を狭くします。
ソースは以下からお借りし、元ネタはJSONP向けのようでそのままでは使えないっぽかったので改変しました。
具体的にはjsondataあたりを消してMimeTypeをJSONにしました(これいる？)(素人)。
> 元ネタ：https://www.koreyome.com/web/make-spreadsheet-to-json-at-google-apps-script/
> 引用記事：https://qiita.com/taichi0514/items/ee6dedff45f9d9e58ef4

#### Script
~~~javascript
    function getData(id, sheetName) {
      var sheet = SpreadsheetApp.openById(id).getSheetByName(sheetName);
      var rows = sheet.getDataRange().getValues();
      var keys = rows.splice(0, 1)[0];
      return rows.map(function(row) {
        var obj = {}
        row.map(function(item, index) {
          obj[keys[index]] = item;
        });
        return obj;
      });
    }
    
    function doGet(request) {
      var data = getData('～ここにスプレッドシートのID～', '～シート名～');
      return ContentService.createTextOutput( JSON.stringify(data, null, 2) )
      .setMimeType(ContentService.MimeType.JSON);
    }
~~~

#### 設定

公開＞Webアプリケーションとして導入
公開範囲は`Anyone, even anonymous`にする(cURLでアクセスするため)。

公開範囲は`only me`ですぜ。
お次はgoogle側での操作よー

### Google側のあれこれ
#### APIの有効化
* GCPの[コンソール](https://console.cloud.google.com/)を開き、左メニューのAPIとサービス→ライブラリを開きます。<br>今回はスプレッドシートを使いたいのでスプレッドシートAPIを有効化します。

#### OAuth2.0クライアントIDを作成する
* 次にAPIとサービス→認証情報を開きます。<br>分かりやすい名前を付けて保存します。アプリケーションの種類は参考にした記事ではその他を選択していましたが、無かったのでデスクトップアプリあたりしました。どれでも関係ないとか？
* 表示されたクライアントIDとクライアントシークレットを環境変数に設定します。<br>画面右上の方の「Cloud Shellをアクティブにする」を使うとブラウザだけで全て完結します。

~~~Console
$ export CLIENT_ID=hoge
$ export CLIENT_SECRET=fuga
~~~
環境変数に設定しておくとこの記事や参考記事のコマンドをコピペできるので推奨しますぜ。

#### リダイレクトURIの設定
* cloudshellでもとりあえずリダイレクトURIは固定値の<br>`urn:ietf:wg:oauth:2.0:oob`で良い模様です。<br>WEBアプリでやる場合とかはすごい人に聞いて下さい。<br>コピペ用に環境変数に設定しておきます。

~~~Console
$ export REDIRECT_URI=urn:ietf:wg:oauth:2.0:oob
~~~

#### スコープの設定
スコープに設定する値はここから調べます。
https://developers.google.com/identity/protocols/googlescopes
今回のケースではスプレッドシートを操作するのですが、謎のエラーが出たのでとりあえずドライブも一緒に設定しました。
2つ設定したので間を`%20`で繋ぎます。例によって環境変数行き。

~~~Console
$ export SCOPE=https://www.googleapis.com/auth/spreadsheets%20https://www.googleapis.com/auth/drive
~~~

#### Authorization Codeの取得
以下のコマンドを実行し、URLを踏みます（ターミナルでやる人はブラウザに貼る）。

~~~Console
$ echo "https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&scope=$SCOPE&access_type=offline"
~~~

ユーザーを指定して許可するとAuthorization Codeが表示されるのでやはり環境変数に設定します。

~~~Console
$ export AUTHORIZATION_CODE=piyo
~~~

#### Authorization Codeを使ってリフレッシュトークンを取得
以下のcURLコマンドを実行するとリフレッシュトークンを取得出来ます。ここまでがコンソールでの作業になります。

~~~Console
$ curl --data "code=$AUTHORIZATION_CODE" \
--data "client_id=$CLIENT_ID" \
--data "client_secret=$CLIENT_SECRET" \
--data "redirect_uri=$REDIRECT_URI" \
--data "grant_type=authorization_code" \
--data "access_type=offline" \
https://www.googleapis.com/oauth2/v4/token
~~~

### Filemakerのスクリプト設定
黒い所は全部一つのスクリプトに順次記述するやつです。
#### リフレッシュトークンを使ってアクセストークンを取得
Filemakerのスクリプトステップ、`URLから挿入`を使用します。
* ターゲット：変数`$result`に格納します。
* URLを指定：`https://www.googleapis.com/oauth2/v4/token`
* cURLオプション：クッソめんどいのでコピペ推奨です。全体をダブルクォートでくくり、中身のダブルクォートはバクスラでエスケープします。
* hoge兄弟は各自取得した値で書き換えてくださいね。

~~~
"--data \"refresh_token=hage\"
 --data \"client_id=hoge\"
 --data \"client_secret=fuga\"
 --data \"grant_type=refresh_token\""
~~~

受信した結果はJSONで返ってきますが必要なのはアクセストークンだけです。
これも変数`$access_token`に格納します。

~~~console
変数を設定 [$access_token; 値: JSONGetElement ( $result ; "access_token" )]
~~~

ついでに上の方で発行したGASのURLを変数に格納します。

~~~console
変数を設定 [$url; 値: "https://script.google.com/macros......"]
~~~

#### cURLオプションを書く
変数で入れ替えるために、`テキストを挿入`ステップでcURLオプションを`$option_temp`に格納します。
`__token__`が下のステップでアクセストークンに切り替わります。
（ここは統合できるかもしれませんがテスト時に出来ていちいち変えるのは面倒なのでこのままにします）

~~~
テキストを挿入 [選択; ターゲット:$option_temp; "curl -H "Authorization: Bearer __token__" -L @$url"]
~~~

#### cURLオプションを変数に格納
可読性にもつながるのでcURLオプションは`$option`に格納します。
ここでアクセストークンがcURLオプションに入りました。

~~~console
変数を設定 [$option; 値: Substitute ( $option_temp ; "__token__" ; $access_token )]]
~~~

#### データを取得する
~~~
URLから挿入 [選択; ダイアログあり:オフ; ターゲット:$result; $url; cURL オプション: $option
~~~
* ターゲットは変数の`$result`に上書き。どうせ起動の度に上からスクリプトが動くので問題無し。
* URLの指定は`$url`です。上で格納したやつですね。
* cURLオプションは`$option`です。前回よりは洗練したでしょ？

レコードの更新は公式のここを参考にしました。`[" & $i & "]`の後に半角スペースあると泣くので詰めよう。
> https://fmhelp.filemaker.com/help/17/fmp/ja/index.html#page/FMP_Help%2Fjson-functions.html%23

    変数を設定 [$ProductCount ; 値: 
       ValueCount ( 
          JSONListKeys ($result ; "") //←例のようにオブジェクトは無いので""にした 
       )] 
    変数を設定 [$i ; 値: 0]
    If [$ProductCount > 0]
       全レコードを表示
       対象レコード削除 [ダイアログあり:オフ] //←消さないと同じレコードがどんどん増えるよ
       Loop
          新規レコード/検索条件
          フィールド設定 [製品::ID ; 
             JSONGetElement ($result ; "JSONGetElement ( $result ; "[" & $i & "]ID" )")] 
       //↑この部分、例では[" & $i & "]の後に半角スペースあるけど、オブジェクトが無い場合？詰めないとnullが出力される(なんで？)
          フィールド設定 [製品::価格 ; 
             JSONGetElement ($result ; "JSONGetElement ( $result ; "[" & $i & "]品名" )")] 
          フィールド設定 [製品::在庫 ; 
             JSONGetElement ($result ; "JSONGetElement ( $result ; "[" & $i & "]価格" )")]
          レコード/検索条件確定 [ダイアログあり: オフ]
          変数を設定 [$i ; 値 : $i + 1] 
          Exit Loop If [$i ≥ $ProductCount]
       End Loop
    End If

* スクリプトを仕込んだボタンを置けばワンボタンでレコードがリフレッシュされます。

## まとめ
1. セキュリティの為にアクセストークンを利用する
1. 毎回手動取得等でボタンポチは面倒なのでリフレッシュトークンを使う
1. cURLで単に叩かれてもトークンが無いので大丈夫

今回は、スプレッドシートがマスターだったのでこういった感じになりました。ﾁｶﾚﾀ...