Metabase の API を実行する

オープンソースのBIツール [Metabase](https://www.metabase.com/) 使ってますか？
OSS なのでもちろん無料！
無料なのに超イケてるデータ可視化がサクッとできちゃう！
そんな Metabase を API 経由で操作できるようになったら更に活用の幅が広がりそうだと思いませんか？

Metabase そのものについては
[OSSのデータ可視化ツール「Metabase」が超使いやすい - Qiita](https://qiita.com/acro5piano/items/0920550d297651b04387)
のような良いまとめがたくさんあるのでここでは割愛し、 API の実行手順についてだけまとめました。

# 手順要約

Google 連携のアカウントについては後述

1. ログイン可能なアカウントを用意する
2. `metabase-session-id` を発行する
3. API を実行する

第1引数にHTTPメソッド、第2引数にAPIのパスを与えて実行できるシェルスクリプト書きました。
https://gist.github.com/macoril/ef864d5a6a1bef237cc3f7e559568740
`. ./metabase_api_exe.sh GET /api/pulse`
って感じに実行する。有効なセッションがないときはセッション取得し直すとかもする。

（シェル久しぶりすぎて細かいところ忘れてて変なコードになってると思うので指摘欲しいです。
特に、L.61のcurlの実行はL.23のcurlと同じ書き方にしたかったけど、jsonが半角スペースで分けられて不要なクォーテーション付きで展開されてしまってうまく対処できなかったorz
ので解決方法を知りたい）

# 詳細

## 1. ログイン可能なアカウントを用意する

Google 連携のアカウントはちょっと面倒なのでメールアドレスとパスワードによる認証のアカウントを用意する。
この記事においては

- メールアドレス: user@example.com
- パスワード: metapass

とする。

Google 連携のアカウントについては後述

## 2. `metabase-session-id` を発行する

以下のように `curl` を実行すると `metabase-session-id` が発行される。

メールアドレスは `username` の値として渡すので注意。
（以前は `username` ではなく `email` だったらしい[^1]）

[^1]: https://github.com/metabase/metabase/issues/5769

```shell
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"username": "user@example.com", "password": "metapass"}' \
  http://localhost:3000/api/session 

# -> {"id":"38f4939c-ad7f-4cbe-ae54-30946daf8593"}
```

### Postman を使う場合の Tips

Postman を使う場合は Tests に以下のコードを設定しておくと、以下の条件を満たす場合に global 変数 `metabase-session-id` に返ってきた値を設定しておくことができてべんり。

- ステータスコードが 200 
- レスポンスの JSON に `id` というキーがある

```javascript
pm.test("Set Session", function(){
    pm.response.to.be.ok
    pm.response.to.have.jsonBody("id")

    let json = JSON.parse(responseBody)
    pm.globals.set('metabase-session-id', json.id)
})
```

テストとして実行する必要がない場合は以下でも可

```javascript
if(pm.response.to.be.ok && pm.response.to.have.jsonBody("id")){
    let json = JSON.parse(responseBody)
    pm.globals.set('metabase-session-id', json.id)
}
```

※Postman では以前は以下のように判定をしていてこういう書き方のナレッジが結構出てきますが、現在は deprecated なので注意。

```javascript
// ステータスコードが200ならXXX
if(responseCode.code == 200){
  XXX
}
// レスポンスの JSON に id というキーがあればXXX
var data = JSON.parse(responseBody);
if(_.has(data, "id")){
  XXX
}
// グローバル変数を設定する
postman.setGlobalVariable("key", "value");
```

## 3. API を実行する

取得できた `metabase-session-id` を `X-Metabase-Session` の値として設定する。

```shell
curl -X GET \
  -H "Content-Type: application/json" \
  -H "X-Metabase-Session: 38f4939c-ad7f-4cbe-ae54-30946daf8593" \
  http://localhost:3000/api/pulse

# -> [{"archived":false,"collection_position":null,"creator":{"email":"user@example.com","first_name":"user",
```

# Google 連携のアカウントの場合の手順

Google 連携のアカウントを使いたい場合は、 `metabase-session-id` を発行するため Google のアクセストークンが必要となる。

1. Google の OAuth アクセストークンを取得する。
2. `POST /api/session/` ではなく `POST /api/session/google_auth` を使って `metabase-session-id` を発行する。

# 参考

## Metabase 関連

- [README](https://www.metabase.com/docs/latest/)
    - Metabase Documentation のトップ。
- [Api Documentation](https://www.metabase.com/docs/latest/api-documentation.html)
    - README を `API` で検索して見つかったページ。しかし API 一覧ページでしか無くて、実行方法についての解説はない
- [Using the REST API · metabase/metabase Wiki](https://github.com/metabase/metabase/wiki/Using-the-REST-API)
    - この文書を見つけるまでが大変で、見つけてしまえさえすればあっという間だった。ここに API の実行方法が載っている

## Google 連携関連

- [Obtaining a session token from /api/session/google_auth requires an id_token, rather than an access_token · Issue #6594 · metabase/metabase](https://github.com/metabase/metabase/issues/6594)
- [Accessing REST API with Google OAuth - Get Help - Metabase Discussion](https://discourse.metabase.com/t/accessing-rest-api-with-google-oauth/10237)
- [アクセス トークンを取得する  |  Google 検索デベロッパー ガイド  |  Google Developers](https://developers.google.com/search/apis/indexing-api/v3/get-token?hl=ja)

## Postman 関連

- [Test script examples | Postman Learning Center](https://learning.postman.com/docs/writing-scripts/script-references/test-examples/)
- [Postman Sandbox | Postman Learning Center](https://learning.postman.com/docs/writing-scripts/script-references/postman-sandbox-api-reference/)

postmanのナレッジはそのうち切り出したいな