目的
- 前回の方法だと公開範囲ガバガバなので認証を付けることに・・・
- スプレッドシートが親のケースで任意のタイミングでFilemakerにデータを同期する。
方法
- GoogleのAPIを使ってリフレッシュトークンを取得し、トークンを自動で取得して操作する
(じゃないと1時間でアクセストークンを手動で取得するというね) - この記事の作成に当たっては以下の記事を大いに参考にさせていただきました。この場を借りて感謝いたします。
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
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のコンソールを開き、左メニューのAPIとサービス→ライブラリを開きます。
今回はスプレッドシートを使いたいのでスプレッドシートAPIを有効化します。
OAuth2.0クライアントIDを作成する
- 次にAPIとサービス→認証情報を開きます。
分かりやすい名前を付けて保存します。アプリケーションの種類は参考にした記事ではその他を選択していましたが、無かったのでデスクトップアプリあたりしました。どれでも関係ないとか? - 表示されたクライアントIDとクライアントシークレットを環境変数に設定します。
画面右上の方の「Cloud Shellをアクティブにする」を使うとブラウザだけで全て完結します。
$ export CLIENT_ID=hoge
$ export CLIENT_SECRET=fuga
環境変数に設定しておくとこの記事や参考記事のコマンドをコピペできるので推奨しますぜ。
リダイレクトURIの設定
- cloudshellでもとりあえずリダイレクトURIは固定値の
urn:ietf:wg:oauth:2.0:oob
で良い模様です。
WEBアプリでやる場合とかはすごい人に聞いて下さい。
コピペ用に環境変数に設定しておきます。
$ export REDIRECT_URI=urn:ietf:wg:oauth:2.0:oob
スコープの設定
スコープに設定する値はここから調べます。
https://developers.google.com/identity/protocols/googlescopes
今回のケースではスプレッドシートを操作するのですが、謎のエラーが出たのでとりあえずドライブも一緒に設定しました。
2つ設定したので間を%20
で繋ぎます。例によって環境変数行き。
$ export SCOPE=https://www.googleapis.com/auth/spreadsheets%20https://www.googleapis.com/auth/drive
Authorization Codeの取得
以下のコマンドを実行し、URLを踏みます(ターミナルでやる人はブラウザに貼る)。
$ 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が表示されるのでやはり環境変数に設定します。
$ export AUTHORIZATION_CODE=piyo
Authorization Codeを使ってリフレッシュトークンを取得
以下のcURLコマンドを実行するとリフレッシュトークンを取得出来ます。ここまでがコンソールでの作業になります。
$ 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
に格納します。
変数を設定 [$access_token; 値: JSONGetElement ( $result ; "access_token" )]
ついでに上の方で発行したGASのURLを変数に格納します。
変数を設定 [$url; 値: "https://script.google.com/macros......"]
cURLオプションを書く
変数で入れ替えるために、テキストを挿入
ステップでcURLオプションを$option_temp
に格納します。
__token__
が下のステップでアクセストークンに切り替わります。
(ここは統合できるかもしれませんがテスト時に出来ていちいち変えるのは面倒なのでこのままにします)
テキストを挿入 [選択; ターゲット:$option_temp; "curl -H "Authorization: Bearer __token__" -L @$url"]
cURLオプションを変数に格納
可読性にもつながるのでcURLオプションは$option
に格納します。
ここでアクセストークンがcURLオプションに入りました。
変数を設定 [$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
- スクリプトを仕込んだボタンを置けばワンボタンでレコードがリフレッシュされます。
まとめ
- セキュリティの為にアクセストークンを利用する
- 毎回手動取得等でボタンポチは面倒なのでリフレッシュトークンを使う
- cURLで単に叩かれてもトークンが無いので大丈夫
今回は、スプレッドシートがマスターだったのでこういった感じになりました。チカレタ...