読者です 読者をやめる 読者になる 読者になる

やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

GASのdoGet関数でFusionTablesAPIを叩く

ワークフロー プログラミング

GASのdoGet(e){...}関数でFusionTablesAPIを実行した。

目標

ラズパイのCPU温度を定期的にロギングしてアップロードしたい

前回

GASを実行する(HTTP GET)

今回

doGet(e)関数にてFusion Tables APIを実行する。

認証などGUIによる手入力を一切せずに実行できるか確かめる。

結論

ブラウザでの実行なら、個人認証なしでinsert文が実行できた。

ただし、初回のみファイルアクセスへの認証が必要。また、curlなどからの実行は未確認。

対象環境

Fusion Tables

FusionTablesでテーブルを作成したファイルを作成する。

docid

後でこのファイルのURLパラメータdocidキーの値をテーブル名として使う。

共有

なお、Fusion Tablesファイルの共有状態はリンクを知っている全員が閲覧できます状態である。

Google Apps Script

ファイル作成

  1. Google Driveにアクセスする
  2. Google Apps Scriptを新規作成する
  3. 任意のファイル名をつけて保存する

こまかい手順は過去記事を参照。

Googleの拡張サービス

  1. メニュー→リソースGoogleの拡張サービス...をクリックする

Fusion Tables APIを有効にする。こまかい手順はGASでFusionTablesAPIを叩いてみたを参照。

うっかり忘れて実行すると、以下のようにReferenceError: 「FusionTables」が定義されていません。と怒られる。

f:id:ytyaru:20161128103814p:plain

コーディング

  1. 以下のソースコードを入力する
function doGet(e) {
  var docId = "01234567890123456789012345678901234567890";
  var sql = "INSERT INTO "
  + docId
  + " (Timestamp,CpuTemperature)"
  + " VALUES"
  + " ('" + e.parameter.TimeStamp.replace(/-/,"/") + "'," + e.parameter.CpuTemperature + ");";
  FusionTables.Query.sql(sql);
}

公開と実行

    1. メニュー→公開ウェブアプリケーションとして導入を選択する f:id:ytyaru:20161127150349p:plain
  1. アクセスできるユーザを自分だけに設定する
  2. 最新のコードリンクをクリックして実行する

こまかい手順はGASを実行する(HTTP GET)を参照。

実行結果(1回目)

f:id:ytyaru:20161128103748p:plain

エラー。その操作を実行するには承認が必要です。とのこと。

やはり出た。承認問題。これをどうにかするのが本題。

承認を要求される条件は何か

GASのdoGet(e)からFusion Tables APIを使うとその操作を実行するには承認が必要です。エラーになった。

でも、GASでFusionTablesAPIを叩いてみたときは承認を要求されずに実行できた。select文もinsert文も。このときはmyFunction関数で実行していた。今回はdoGet(e)関数で実行した。

doGet(e)関数だけでは承認を要求されることはない。GASを実行する(HTTP GET)のとき、doGet(e)関数を実行したが、承認を要求されずに実行できた。今回はFusion Tables APIを使っている。

上記のことから、doGet(e)関数を使い、なおかつFusion Tables APIを使うとき、承認が必要になるのかもしれない。

回避案

  • Apps Scriptのアプリケーションにアクセスできるユーザー全員にしてみる

誰でもアクセスできるようにしてしまえば、承認なんて不要になるのでは?

結論から言うと、承認は初回のみ必要だった。

公開と実行(2回目)

    1. メニュー→公開ウェブアプリケーションとして導入を選択する f:id:ytyaru:20161127150349p:plain
  1. アクセスできるユーザを自分だけから全員に変更する
  2. 更新をクリックする f:id:ytyaru:20161128085313p:plain
  3. 承認が必要ですダイアログが表示される
  4. 許可を確認をクリックする f:id:ytyaru:20161128085540p:plain
  5. {AppsScriptファイル名}が次の許可をリクエストしていますウインドウが表示される
  6. 許可をクリックする f:id:ytyaru:20161128090454p:plain
  7. ウェブアプリケーションとして導入ダイアログが表示される
  8. 最新のコードリンクをクリックして実行する f:id:ytyaru:20161128090754p:plain

実行結果(2回目)

f:id:ytyaru:20161128090931p:plain

Invalid query: Parse error near 'undefined' (line 1, position 101).(行 8、ファイル「コード」)

おそらく、最新のコードリンクにはURLパラメータがないからエラーになったのだろう。 最新のコードリンクを右クリックしてリンクのURLをコピーする。 f:id:ytyaru:20161128091356p:plain https://script.google.com/macros/s/{scriptDocId}/devの書式だと思う。

そのURLに、ソースコードで定義したURLパラメータを付与する。

https://script.google.com/macros/s/{scriptDocId}/dev?TimeStamp=2000-01-01 23:59:59&CpuTemperature=43210とする。

  • パラメータキーは大文字小文字の区別もするのでソースコードと完全一致させること
  • 日付の書式はyyyy-MM-dd HH:mm:ddとする(Fusion Tablesのカラム設定と一致させる)

公開と実行(3回目)

    1. メニュー→公開ウェブアプリケーションとして導入を選択する
  1. 最新のコードリンクをクリックして実行する

実行結果(3回目)

f:id:ytyaru:20161128092443p:plain

doGet(e)で何もreturnしないとスクリプトが完了しましたが、何も返されませんでした。というエラーになるらしい。今回は何もreturnしていないので別にいい。

f:id:ytyaru:20161128092457p:plain

対象のFusionTablesファイルを開いてみる。末尾にデータが挿入されていた!成功!

分析

承認

初回のみ承認画面が必要だったらしい。自分のAppsScriptファイルに全員がアクセス可能であることを、自分で承認することが必要だったということか。

  • Fusion Tablesファイルの共有はリンクを知っている全員が閲覧できます
  • Apps Scriptファイルの公開は全員

ポイント

GAS経由でFunction Tables APIを使い、insertするまでの要点。

ファイル 要点
Fusion Tables メニュー→shareリンクを知っている全員が閲覧できます
Fusion Tables SQL文で使うテーブル名はFusion TablesファイルURL内にあるdocidパラメータキー値である
Apps Script メニュー→公開ウェブアプリケーションとして導入。アプリケーションにアクセスできるユーザー:全員
Apps Script メニュー→リソースGoogleの拡張サービス...→Fusion TablesをONDeveloper ConsoleでFusion Tablesを有効にする
Apps Script FusionTables.Query.sql("insert into ...");でFusion Tablesに対してSQL文を発行する
Apps Script function doGet(e) {...}でHTTPのGETに応答する
Apps Script e.parameter.{任意のキー名}doGet(e)が受け取るURLパラメータを参照する
Apps Script return ContentService.createTextOutput("")doGet(e)が返すテキストを設定する

これを把握すれば、自分で任意のWebAPIを作れる上、データベースでデータを管理できる。

課題

GAS経由と直叩きの違いが謎

ただ、Fusion Tables APIに触ってみたときは失敗した。GASを経由せずにAPIKeyを渡したが、insert文はLogin Requiredエラーが返ってきた。エラーになったのはGASを経由していないせいか、ブラウザでなくcurlからアクセスしたせいか。

ブラウザ以外から実行できるか

  • curlなどブラウザ以外で実行すると承認を求められる?
  • curlなどブラウザ以外で実行するとリクエスト上限にひっかかりやすい?

本番はブラウザでなく、curlpythonjavascriptなどから実行する予定。その環境でも同じように実行できるか確認する必要がある。

リクエスト上限の詳細が不明

また、勝手な憶測だが、HTTPヘッダのUserAgent次第でリクエスト上限に違いを設けていたりしないだろうか。そんな仕様は見つけていないが、Fusion Tables APIに触ってみたときはすぐにリクエスト上限になってしまった。対して今回はリクエスト上限になっていない。たぶん私の勘違いなり操作ミスなり何なりが原因だと思うが、はっきりさせたい。

こちらによると、1日2万5千リクエストが上限らしい。Query.sqlは1回あたり5リクエスト消費するらしく、1日あたり5千件になるとか。さらに1テーブル1分あたり30件の書き込みが上限らしい。Table.importRows()で解消できる可能性もあるが、そっちはそっちで内部エラーが出る場合もあるらしい。

公式文書をみてみると、2016/11/28時点でも上記と同じだった。ファイルサイズの上限もあるらしい。1テーブル250MBまで。1アカウントあたり全テーブル1GBまで。

こまかい制限がたくさん出てきた。どうやって運用するかを考える必要がありそう。

所感

ブラウザのロケールバーからGASのdoGet(e)関数を実行して、Fusion Tables APIを使ってinsert文を発行した。

今回のを自作のプログラムコードから実行できれば目標に近づく。ログインや認証などの手入力なしで可能かどうかが重要。