ついに成功した。前回のエラーはURLパラメータで引数を渡すことで解決した。(POSTなのに)
目標
ラズパイのCPU温度を定期的にロギングしてアップロードしたい。
小目標
PythonからFusionTablesAPIを使ってinsertする。
前回
POSTデータにパラメータを付与したつもりが、付与されていないエラー。
今回
小目標を達成した。
前回のエラーはGETと同じ方法のURLパラメータにて与することで解決した。POSTデータで与える方法は不明のまま。
対象環境
- Firefox 50.0
- Google Account
- Google Developers Console
- Google Drive
- Google Fusion Tables
- Google Apps Script
- Python 2.7
原因調査
printで確認
前回のコードのPOSTデータが不正だったのかもしれない。
print
で表示してみると以下の通り。
{ "sql": "INSERT INTO {TableId} (Timestamp, CpuTemperature) values('2011-11-11 11:11:11',11111)" }
sql
パラメータはある。問題なさそう。
名前付きパラメータで名前指定して渡す
関数定義はdef runRequest(self, method, url, data=None, headers=None):
になっている。でも、呼出は以下のようになっている。
response = self.runRequest( "POST", "/fusiontables/v2/query%s" % \ (self.params), data, headers={'Content-Type':'application/json'})
data=data,
にすべきなのかも?python2の名前付きパラメータの作法とか知らないけど。
response = self.runRequest( "POST", "/fusiontables/v2/query%s" % \ (self.params), data=data, headers={'Content-Type':'application/json'})
上記のように修正して、再度実行。
同様のエラーになった。
copy and paste the url below into browser address bar and hit enter https://accounts.google.com/o/oauth2/auth?client_id={*.apps.googleusercontent.com}&redirect_uri=http://localhost:8000&scope=https://www.googleapis.com/auth/fusiontables&response_type=code Enter code (parameter of URL): 4/2Oa9_jXlIQ1IwOl3-lQOfKH_yXGEv53nxgHLZucZIqA v2 Query.sql insert 400 Bad Request { "error": { "errors": [ { "domain": "global", "reason": "required", "message": "Required parameter: sql", "locationType": "parameter", "location": "sql" } ], "code": 400, "message": "Required parameter: sql" } } {u'error': {u'code': 400, u'message': u'Required parameter: sql', u'errors': [{u'locationType': u'parameter', u'domain': u'global', u'message': u'Required parameter: sql', u'reason': u'required', u'location': u'sql'}]}}
GETのように渡す
もういっそ、GETのようにURLパラメータで渡してしまおう。できるかどうか知らないけど。POSTの意味ないけど。
ソースコード修正
def testInsertV2(self): print "v2 Query.sql insert" sql = "INSERT INTO %s (Timestamp, CpuTemperature) values('%s',%s)" % (tableid, '2011-11-11 11:11:11',11111) data = '''{ "sql": "%s" }''' % (sql) print(data) response = self.runRequest( "POST", "/fusiontables/v2/query%s&sql=%s" % \ (self.params, urllib.quote(sql)), data=data, headers={'Content-Type':'application/json'}) json_response = simplejson.loads(response) print(json_response) return json_response
実行
成功!!!
$ python SimpleSample.py copy and paste the url below into browser address bar and hit enter https://accounts.google.com/o/oauth2/auth?client_id={*.apps.googleusercontent.com}&redirect_uri=http://localhost:8000&scope=https://www.googleapis.com/auth/fusiontables&response_type=code Enter code (parameter of URL): 4/4HgD872blsIW5MR_Frqkz173hkVK92ZXSwHzGNPp9j4 v2 Query.sql insert 200 OK { "kind": "fusiontables#sqlresponse", "columns": [ "rowid" ], "rows": [ [ "41" ] ] } {u'kind': u'fusiontables#sqlresponse', u'rows': [[u'41']], u'columns': [u'rowid']}
たぶんPOSTでデータを渡せていなかったのだろう。URLパラメータでも渡せるものだったのか。それともQuery.sql
だけの仕様なのか。
テーブル確認
本当にデータが追加されているか確認する。
Google Driveにアクセスして、該当のFusion Tablesファイルを開く。追加されていた!
課題
- セキュリティ的にせめてAPIKey, AccessTokenだけでもPOSTデータに含めるべき
- 再現できるように手順をまとめたい
- ソースコードの完全版を用意したい
- 手入力のところの
許可
を押下するところは、自動化すべきでないのだろう。でも、どうにか自動化できないか
結論
自動化できない。Fusion Tablesへのinsertをcronで実行することはできない。OAuth2.0の手続きがあるかぎり。
所感
ついにできた!
長かった。Fusion Tables APIに触ってみたときの失敗にはじまり、GASのdoGet関数をPythonで叩くからの妥協。失敗の連続。
私、本当にお疲れ様でした。Fusion Tables APIを使うのにどれだけ苦労させられたことか。しかも自動化できないなんて…。手入力が想像以上に面倒。ローカルサーバを立てる必要まである。おまけにリクエスト上限や時間あたりの登録件数上限、ファイルサイズ上限など各種の制限もある。一体どこまで使えるのか。それを考えるのも大変そう。