なんで R & metabase なの?
以前「 metabase 」使ってて、データベースを変更した時、更新ボタンクリックすれば大体は反映されるんだけど、反映されない時は「設定」 > 「管理者」 > 「データベース」タブ > データベースを選択 > 「今すぐデータベーススキーマと同期する」ってするのが面倒だなって思ったのを思い出したので。
でもって、その時は R で集計した結果を SQLite に書き出して metabase で表示させてってな事してた時だったので。
さぁはじめよう!
全く深くない理由で R & metabase なわけなんですが、さぁはじめてみようかなっと。
まずは metabase の API の使い方なんですが、使い方は「 Working with the Metabase API 」に書いてあって、 curl を使ったサンプルも紹介されているので、今回はそれを参考にしていこうと思います。
ちなみに API に関するドキュメントは「 API Documentation for Metabase 」で参照できます。
RCurl じゃなくて httr かな
R でも curl 使うための RCurl あるのでそれ使えばサンプルに近い形で書けるかも…、なーんて思ったりしたんですが、やっぱ慣れている httr パッケージを使うことにしました。
認証してトークンを取得
ドキュメントに沿ってまずは認証してトークンを取得します。欲しいのは結果(トークン)だけなので content() で結果だけ取り出します。メッセージがうっとしい場合は verbose() のところを削除すると静かになります。
ちなみに httr は POST する際に encode に json を指定すれば、 list を JSON に変換してくれるっぽいので、かなり楽な感じです。
library(dplyr)
library(httr)
session <- "localhost:3000/api/session" %>%
POST(body = list(username = "person@metabase.com", password = "fakepassword1")
,encode = "json", verbose()
) %>% content
認証に成功するとトークンがゲットできます。
session
$id
[1] "a30987cb-8982-43f7-985c-072af8004a10"
ちなみに content() 使わないと、 rawToChar() で文字にして、 fromJSON() でパースしてってする必要があります。 content()、なかなか便利です。
session <- "localhost:3000/api/session" %>%
POST(body = list(username = "person@metabase.com", password = "fakepassword1")
,encode = "json", verbose()
)
session$content
[1] 7b 22 69 64 22 3a 22 63 37 32 38 61 36 66 36 2d 33 37 37 66 2d 34 30 35 63
[26] 2d 62 36 39 65 2d 36 36 62 32 34 31 33 39 65 36 62 61 22 7d
session$content %>% rawToChar
[1] "{\"id\":\"c728a6f6-377f-405c-b69e-66b24139e6ba\"}"
session$content %>% rawToChar %>% jsonlite::fromJSON()
$id
[1] "c728a6f6-377f-405c-b69e-66b24139e6ba"
GETの例です
ドキュメントに沿って GET を試してみます。あっけなく実行できたっぽいです。
"localhost:3000/api/user/current" %>%
GET(add_headers("X-Metabase-Session" = session$id)
,verbose()
) %>% content %>% str
List of 17
$ email : chr "person@metabase.com"
$ ldap_auth : logi FALSE
$ first_name : chr "Human"
...(以下省略)
POSTの例です
でもって今度は POST です。よくわからないですがエラーじゃないからうまくいったのかなと心配になったりしますが、ま、このまま進めていって何か問題があったら考えるということでこの場は OK ということにしようと思います。よしよし。
"localhost:3000/api/card" %>%
POST(add_headers("X-Metabase-Session" = session$id)
,body = list(
"visualization_settings" = list(
"table.pivot_column" = "QUANTITY",
"table.cell_column" = "SUBTOTAL"
),
"description value" = "A card generated by the API",
"collection_position" = NA,
"result_metadata" = NA,
"metadata_checksum" = NA,
"collection_id" = NA,
"name" = "API-generated question",
"dataset_query" = list(
"database" = 1,
"query" = list(
"source-table" = 2
),
"type" = "query"
),
"display" = "table"
)
,encode = "json", verbose()
) %>% content %>% str
List of 25
$ description : NULL
$ archived : logi FALSE
$ collection_position : NULL
...(以下省略)
で同期は?
で、同期なんですが、同期したいときは sync とか sync_schema を呼びだせば良いみたいなので以下みたいな感じかなと思います。
"localhost:3000/api/database/1/sync" %>%
POST(add_headers("X-Metabase-Session" = session$id)
,encode = "json" ,verbose()
) %>% content %>% str
"localhost:3000/api/database/1/sync_schema" %>%
POST(add_headers("X-Metabase-Session" = session$id)
,encode = "json" ,verbose()
) %>% content %>% str
めでたしめでたしです。
うん?Cookie使えるみたい
よく見てみると metabase はトークンを Cookie に設定するようなレスポンスを返しているみたいです。試してみたところ Cookie が設定されていれば X-Metabase-Session 指定しなくてもよさそうで、でもって httr は Cookie を処理してくれるぽいので以下のように書けそうです。まぁなんということでしょう。
library(dplyr)
library(httr)
"localhost:3000/api/session" %>%
POST(body = list(username = "person@metabase.com", password = "fakepassword1")
,encode = "json"
)
"localhost:3000/api/database/1/sync" %>% POST
"localhost:3000/api/database/1/sync_schema" %>% POST
想像を超えて簡単&シンプル&綺麗に書けたので、なかなか良い感じじゃないって思う今日このごろです。めでたしめでたしです。