やってみる

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

Fusion Tables APIに触ってみた

Google Fusion Tables APIについて調べてみた。select文の発行はできたが、insert文は失敗した。

目標

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

対象環境

資料をみてみる

資料は英語のため、読むのに苦労しそう。

  1. 開発者用のFusionTablesページへアクセスする。
  2. ガイドをクリックする
  3. Use the APIをクリックする

認証など基本的なことはUse the APIページに書いてありそう。

認証方法

認証方法 説明
OAuth 2.0 許可が必要な場合(プライベートデータ)
API key 承認が不要な場合(公開データ)

二種類を使い分けることができるらしい。 翻訳したが、"許可"と"承認"は同じことをいっているという認識でいいのだろうか。

おそらく、GoogleDocumentでの公開や共有の設定で、自分だけ全員のようなことをプライベート/公開データと言っているのだろう。全員に公開すれば、API keyを渡して承認不要で実行できるということでいいのだろうか。

認証の流れ

OAuth2.0認証のみ対応しているらしい。 気になったのはOAuth2.0認証が以下のような流れであると書いてあること。

  1. scopeを指定してリクエストする
  2. ユーザへの同意画面が表示される
  3. 承認した場合、アクセストークンを提供する
  4. アクセストークンを使ってAPIをリクエストする

すべてのアプリケーションタイプに適用されるらしい。 API keyを使っても、承認画面が必要ということだろうか?

Google Sign-inを使っている場合、認可の一部が自動化されるらしいが。Google Sign-inとやらが何なのか知らない。

サンプルコード

こちらにサンプルコードがあるらしい。

試してみる

https://www.googleapis.com/fusiontables/v2/tables/{DocumentId}/columns?key={API key}をGETする。テーブルのカラム情報をとるAPIらしい。とりいそぎブラウザのロケールバーで叩く。

項目 内容
{DocumentId} 以前作成したFusionTableファイルのURLパラメータキーdocidの値。
{API key} 前回作成したAPIKey。

Login Required

しかし、以下のエラーになった。

{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "required",
    "message": "Login Required",
    "locationType": "header",
    "location": "Authorization"
   }
  ],
  "code": 401,
  "message": "Login Required"
 }
}

エラー内容をみると、HTTPヘッダにAuthorization情報を設定しろといっているように見える。 たしかOAuth認証では、ログインするとAccessTokenが配布される。それをHTTPヘッダに設定しろということだろう。たぶん。

やなこった。認証なんてしたくない。サクっと実行したいんじゃ。

公開範囲

FusionTablesの公開範囲を変更してみる。公開範囲を広げると認証不要になると思う。

リンクの共有

概要 説明
ウェブ上で一般公開 インターネット上の誰でも検索、アクセスできます。ログインは不要です。
リンクを知っている全員 リンクを知っている全員がアクセスできます。ログインは不要です。
特定のユーザ 特定のユーザと共有しています。

とりあえず、リンクを知っている全員にしてみる。

f:id:ytyaru:20161126211451p:plain f:id:ytyaru:20161126211513p:plain f:id:ytyaru:20161126211527p:plain f:id:ytyaru:20161126211534p:plain

成功

{
 "kind": "fusiontables#columnList",
 "totalItems": 2,
 "items": [
  {
   "kind": "fusiontables#column",
   "columnId": 3,
   "name": "Timestamp",
   "type": "DATETIME",
   "description": "CPU温度の取得日時。",
   "formatPattern": "DT_ISO_YEAR_MONTH_DAY_TIME",
   "validateData": true
  },
  {
   "kind": "fusiontables#column",
   "columnId": 1,
   "name": "CpuTemperature",
   "type": "NUMBER",
   "description": "CPU摂氏温度(1000倍値)。cat /sys/class/thermal/thermal_zone0/temp 取得値。",
   "formatPattern": "NONE",
   "validateData": false
  }
 ]
}

無事、カラム情報が取得できた。

SQL (select)

SQL文を発行してテーブルを操作したい。まずはselect文。

https://www.googleapis.com/fusiontables/v2/query?sql={SQL}&key={APIKey}の書式。keyは先述のと同じ。SQLはselect文を書く。SELECT * FROM {docid}の書式。テーブル名の代わりにdocidを使う。 https://www.googleapis.com/fusiontables/v2/query?sql=SELECT * FROM {docid}&key={APIKey}をブラウザのロケールバーに入力して叩く。

{
 "kind": "fusiontables#sqlresponse",
 "columns": [
  "Timestamp",
  "CpuTemperature"
 ],
 "rows": [
  [
   "2000/01-01 00:00:05",
   "36000"
  ],
  [
   "2005/01-01 00:00:08",
   "38000"
  ]
 ]
}

成功。テストデータとして入力した値が返ってきた。

SQL (insert)

いよいよ目的のinsert文。

select文のときと同じ。sql部分をinsert文に変更する。INSERT INTO {docid} (Timestamp,CpuTemperature) VALUES ('2016-01-02 03:04:05',3900)のようにする。

https://www.googleapis.com/fusiontables/v2/query?sql=INSERT INTO {docid} (Timestamp,CpuTemperature) VALUES ('2016-01-02 03:04:05',3900)&key={APIKey}をブラウザのロケールバーで叩く。

The operation is not supported for GET requests

しかし、以下のようなエラーになった。

{
 "error": {
  "errors": [
   {
    "domain": "fusiontables",
    "reason": "cannotWriteDataOnGetRequests",
    "message": "The operation is not supported for GET requests.  Please try again using POST."
   }
  ],
  "code": 501,
  "message": "The operation is not supported for GET requests.  Please try again using POST."
 }
}

GETではinsertできない。insertするときはPOSTしろ。ということか。

curl

ブラウザのロケールバーではGETしかできない。仕方ないのでcurlを使ってPOSTする。

set CURL_PEM="C:\Program Files\Git\ssl\certs\cacert.pem"
set RESPONSE="GitHub.%USER_NAME%.Authorizations.json"
curl --cacert "%CURL_PEM%" -o %RESPONSE% -X POST -F "sql=INSERT INTO {docid} (Timestamp,CpuTemperature) VALUES ('2016-01-02 03:04:05',3900)" -F "key={APIKey}" https://api.github.com/authorizations

SSL certificate problem

例によってCURLSSL証明書エラー。恒例となりつつある。たまにcurlを使うとこうなる。

rl: (60) SSL certificate problem, verify that the CA cert is OK. Details:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
More details here: http://curl.haxx.se/docs/sslcerts.html

こちらからダウンロードする。しかし、同様のエラーで改善しなかった。なぜだ。仕方ないので-kオプションを追加。チェックしないようにする。

curl -k --cacert "%CURL_PEM%" -o %RESPONSE% -X POST -F "sql=INSERT INTO {docid} (Timestamp,CpuTemperature) VALUES ('2016-01-02 03:04:05',3900)" -F "key={APIKey}" https://api.github.com/authorizations

Unsupported content with type

{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "badContent",
    "message": "Unsupported content with type: multipart/form-data; boundary=----------------------------418b17b53a26"
   }
  ],
  "code": 400,
  "message": "Unsupported content with type: multipart/form-data; boundary=----------------------------418b17b53a26"
 }
}

POST内容にケチをつけられたようだ。curlでPOSTの仕方を間違えたっぽい。

こちらを真似た結果失敗した。こちらをよくみてみるとわかりそう。こちらのほうが詳しいか。POSTむずかしい。

curl -k --cacert "%CURL_PEM%" -o %RESPONSE% -XPOST --data-urlencode "sql=INSERT INTO {docid} (Timestamp,CpuTemperature) VALUES ('2016-01-02 03:04:05',3900)" --data-urlencode "key={APIKey}" https://www.googleapis.com/fusiontables/v2/query

Login Required

{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "required",
    "message": "Login Required",
    "locationType": "header",
    "location": "Authorization"
   }
  ],
  "code": 401,
  "message": "Login Required"
 }
}

またしてもログイン必須エラー。もしやinsertは認証が必須なのだろうか。

Daily Limit for Unauthenticated Use Exceeded

パラメータを1つにまとめて送信してみた。

curl -k --cacert "%CURL_PEM%" -o %RESPONSE% -XPOST --data-urlencode "sql=INSERT INTO {docid} (Timestamp,CpuTemperature) VALUES ('2016-01-02 03:04:05',3900)&key={APIKey}" https://www.googleapis.com/fusiontables/v2/query
{
 "error": {
  "errors": [
   {
    "domain": "usageLimits",
    "reason": "dailyLimitExceededUnreg",
    "message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.",
    "extendedHelp": "https://code.google.com/apis/console"
   }
  ],
  "code": 403,
  "message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup."
 }
}

なんと、もはやリクエスト上限らしい。たぶん10回もやっていない。使えなさすぎ。 まだinsert成功していないのに。

こちらによるとFusion Tables APIの上限は1日あたり25,000リクエストらしい。2万5千回もリクエストしていない。25回もしていないはず。

こちらによると、1日2万5千リクエストが上限らしい。Query.sqlは1回あたり5リクエスト消費するらしく、1日あたり5千件になるとか。さらに1テーブル1分あたり30件の書き込みが上限らしい。

1日に5000回もリクエストしてないし、1分あたり30件以内のはず。

所感

結局、insert文の成功までできなかった。insertの場合は認証が必要なのかもしれない。しかしそうなると自動化できなくなってしまうだろう。何らかの手動操作が必要になりそう。それではバッチ処理ができない。

リクエスト上限は当てにならない。GitHubでもそういう印象。認証といいリクエスト上限といい、GoogleAPIは想像以上に使えないのかもしれない。私がわかっていないだけかもしれないが。

どうでもいいが、今年からブログの予約投稿日時を10:00から00:00に変更する。