使用 Metabase API

Metabase API 簡介。

本文說明如何使用Metabase 的 API自動化任務。我們自己使用該 API 連接前端和後端,因此您可以編寫幾乎所有 Metabase 可以執行的操作的腳本。

API 參考文件

您可以在我們的文件中找到 Metabase API 參考文件。您也可以在您自己執行的 Metabase 中,於 /api/docs 查看即時 OpenAPI 文件。因此,如果您的 Metabase 位於 https://www.your-metabase.com,您可以在 https://www.your-metabase.com/api/docs 存取它們。

警告:Metabase API 可能會變更

  • API 可能會變更。我們很少變更 API 端點,而且幾乎從不移除它們,但如果您編寫的程式碼依賴 API,您未來可能必須更新您的程式碼。
  • API 未版本化。因此,請勿期望停留在特定版本的 Metabase,以便使用「穩定」的 API。

如需 API 變更,請查看開發人員指南的 API 變更記錄

Metabase API 入門

為了簡化,我們將使用歷史悠久的命令列工具 curl 作為我們的 API 呼叫範例;您也可以考慮使用專用工具來開發 API 請求(例如 Postman)。若要跟著操作,您可以在本機主機上啟動新的 Metabase 並試用。

建立 API 金鑰

若要使用 API,請建立 API 金鑰

範例 GET 請求

以下是一個 API 請求範例,它會命中 /api/permissions/group 端點,該端點會傳回您在 Metabase 中設定的權限群組。將 YOUR_API_KEY 替換為您的 API 金鑰

curl \
-H 'x-api-key: YOUR_API_KEY' \
-X GET 'https://127.0.0.1:3000/api/permissions/group'

上述請求會傳回 Metabase 中群組的 JSON 物件陣列(已格式化以提高可讀性)

[
  {
    "id": 2,
    "name": "Administrators",
    "member_count": 2
  },
  {
    "id": 1,
    "name": "All Users",
    "member_count": 3
  }
]

範例 POST 請求

您也可以使用檔案來儲存 POST 請求的 JSON 酬載。這讓您可以輕鬆地擁有一組想要向 API 發出的預定義請求。

curl -H @header_file.txt -d @payload.json https://127.0.0.1/api/card

以下是上述命令中的 header_file.text

x-api-key: YOUR_API_KEY

以下是 JSON 檔案的範例(上述命令中的 @payload.json),它會建立問題

{
  "visualization_settings": {
    "table.pivot_column": "QUANTITY",
    "table.cell_column": "SUBTOTAL"
  },
  "description value": "A card generated by the API",
  "collection_position": null,
  "result_metadata": null,
  "metadata_checksum": null,
  "collection_id": null,
  "name": "API-generated question",
  "dataset_query": {
    "database": 1,
    "query": {
      "source-table": 2
    },
    "type": "query"
  },
  "display": "table"
}

該請求產生了問題

A question in Metabase generated by the API: a list of the Orders table in the Sample Database

查看 Metabase 的請求和回應

在即時 API 文件中實驗

您可以從您執行的 Metabase 中的 /api/docs 查看透過 RapiDoc 提供的即時 OpenAPI 文件。因此,如果您的 Metabase 位於 https://www.your-metabase.com,您可以在 https://www.your-metabase.com/api/docs 存取它們。

在即時文件中,您可以實驗傳送請求並查看範例回應

Example of an API response in live docs

使用開發人員工具

如果自動產生的 API 文件不夠清楚,您可以使用 Firefox、Chrome 和 Edge 等瀏覽器隨附的開發人員工具來查看 Metabase 的請求和回應。

Using Firefox

在 Metabase 應用程式中,執行您想要編寫腳本的動作,例如新增使用者或建立儀表板。然後使用瀏覽器中的開發人員工具來查看您執行該動作時 Metabase 向伺服器發出的請求。

您可以使用 Metabase API 執行的幾件事

佈建 Metabase 執行個體

除了使用環境變數之外,您還可以使用 Metabase API 來設定 Metabase 的執行個體。使用您的慣用方法安裝 Metabase,並啟動並執行 Metabase 伺服器後,您可以透過發佈到特殊端點 /api/setup 來建立第一個使用者(作為管理員)。此 /api/setup 端點

  • 將第一個使用者建立為管理員(超級使用者)。
  • 讓他們登入。
  • 傳回會期 ID。

然後,您可以使用 /api/settings 端點設定設定,使用 /api/email 端點設定電子郵件,並使用 /api/setup/admin_checklist 端點來驗證您的設定進度。

Admin checklist for setting up Metabase to make the most of your application.

新增資料來源

您可以使用 POST /api/database/ 端點新增資料庫,並使用 /api/setup/validate 端點驗證該資料庫的連線詳細資訊。將資料庫連線到您的 Metabase 執行個體後,您可以重新掃描資料庫並更新結構描述中繼資料。您甚至可以使用 POST /api/database/sample_database 將我們可靠的範例資料庫新增為您執行個體的新資料庫。

以下是 Redshift 資料庫的資料庫建立呼叫範例。

curl -s -X POST \
    -H "Content-type: application/json" \
    -H 'x-api-key: YOUR_API_KEY' \
    https://127.0.0.1:3000/api/database \
    -d '{
        "engine": "redshift",
        "name": "Redshift",
        "details": {
            "host": "redshift.aws.com",
            "port": "5432",
            "db": "dev",
            "user": "root",
            "password": "password"
        }
    }'

設定使用者、群組和權限

您可以使用 /api/user 端點來建立、更新和停用使用者,或使用 /api/permissions 端點來設定群組或將使用者新增至群組。以下是建立使用者的 curl 命令範例

curl -s "https://127.0.0.1:3000/api/user" \
    -H 'Content-Type: application/json' \
    -H 'x-api-key: YOUR_API_KEY' \
    -d '{
    "first_name":"Basic",
    "last_name":"Person",
    "email":"basic@somewhere.com",
    "password":"Sup3rS3cure_:}"
}'

產生報表

在 Metabase 中,「報表」稱為儀表板。您可以使用 /api/dashboard 端點與儀表板互動。您可以使用 POST /api/dashboard/ 建立新的儀表板,並使用 [POST/api/dashboard/:id/cards] 將已儲存的問題新增至儀表板

實用端點

以下「端點」欄中的連結會將您帶到該端點可用的第一個動作,依字母順序通常是 DELETE 動作。您可以在 API 文件中向下捲動,以查看該端點的完整動作和 URL 清單,並查看每個動作的描述。

領域 描述 端點
集合 集合是組織儀表板、已儲存問題和脈衝的好方法。 /api/collection
儀表板 儀表板是由一組問題和文字卡片組成的報表。 /api/dashboard
資料庫 擷取資料庫、欄位、結構描述、主體 (實體) 金鑰、表格清單等。 /api/database
電子郵件 更新電子郵件設定並傳送測試電子郵件。 /api/email
嵌入 使用簽署的 JWT 來擷取嵌入式卡片和儀表板的資訊。 /api/embed
權限 Metabase 使用群組管理資料庫和集合的權限。建立權限群組、將使用者新增至群組和從群組中移除使用者、擷取所有權限群組的圖表等。 /api/permissions
搜尋 搜尋卡片(問題)、儀表板、集合和脈衝的子字串。 /api/search
區隔 區隔是已命名的篩選條件集(例如「活躍使用者」)。建立和更新區隔、還原為先前的版本等等。 /api/segment
會期 使用權杖重設密碼、使用 Google 驗證登入、傳送密碼重設電子郵件等等。 /api/sessions
設定 建立/更新全域應用程式設定。 /api/setting
查詢 使用 API 執行查詢,並以指定的格式傳回其結果。 /api/dataset
問題 問題(在 API 中稱為卡片)是查詢及其視覺化結果。 /api/card

還有其他一些很酷的端點可以查看,例如 api/database/:virtual-db/metadata,它用於「欺騙」前端,使其可以將已儲存的問題視為虛擬資料庫中的表格。Metabase 就是這樣讓您將已儲存的問題當作資料來源使用。

文件包含完整的 API 端點清單以及每個端點的文件,因此請深入研究並查看您可以找到的其他很酷的端點。

端點參考文件會定期使用新版本的 Metabase 進行更新。您也可以透過執行下列命令來產生參考文件

java -jar metabase.jar api

執行自訂查詢

使用查詢產生器撰寫的查詢會儲存在我們的自訂 JSON 型查詢語言 MBQL 中。

若要熟悉 MBQL,我們建議您使用 Metabase 應用程式,使用查詢產生器建立問題),然後使用瀏覽器的開發人員工具來查看 Metabase 如何使用查詢格式化請求主體。

Python、R 和 JavaScript 範例

Curl 是探索 API 的便利工具,但如果您要將 Metabase 整合到大型資料生態系統中,您可能會使用其他工具。為了展示如何使用 Python、R 和 Node.js 存取 API,讓我們建立兩個問題。第一個問題是找出超過 100 美元的訂單依類別分組的平均稅前價值。它是公開分享的—本教學課程說明如何執行此操作。

The notebook of a public question calculating the average value of orders over $100 by product category.

第二個問題是計算資料庫中的人數。它是分享的:我們包含它是為了展示如何區分分享和未分享的問題。

The notebook of a non-public question calculating the number of people in the database.

Python

我們的第一個範例以 Python 撰寫。與大多數資料科學程式一樣,它使用 requests 程式庫傳送 HTTP 請求,並使用 Pandas 管理表格資料,因此我們先匯入這些程式庫。

讓我們詢問 Metabase 哪些問題具有公開 ID,也就是哪些問題已分享,以便我們可以遠端調用它們。當我們要求所有卡片時,我們會取得包含所有問題相關資訊的清單;只有具有 public_uuid 欄位的卡片才是可呼叫的

import requests
import pandas as pd
# Avoid committing your API KEY to the repository
headers = {'x-api-key': YOUR_API_KEY}
response = requests.get('https://127.0.0.1:3000/api/card',
                         headers=headers).json()
questions = [q for q in response if q['public_uuid']]
print(f'{len(questions)} public of {len(response)} questions')

在我們的案例中,輸出結果告訴我們有兩個問題,但只有一個是公開的

1 public of 2 questions

讓我們取得有關該公開問題的一些資訊,並列印其標題

uuid = questions[0]['public_uuid']
response = requests.get(f'https://127.0.0.1:3000/api/public/card/{uuid}',
                        headers=headers)
print(f'First title: {response.json()["name"]}')
First title: Average value of orders over $100 grouped by category

最後,我們可以從清單中的第一個問題中提取資料。'data' JSON 回應中的金鑰包含大量資訊;我們最感興趣的是子金鑰 'rows' 下的值,它以常見的清單清單形式儲存結果表格。讓我們將其轉換為 Pandas 資料框架並列印出來

response = requests.get(f'https://127.0.0.1:3000/api/public/card/{uuid}/query',
                        headers=headers)
rows = response.json()['data']['rows']
data = pd.DataFrame(rows, columns=['Category', 'Average'])
print('First data')
print(data)
First data
    Category     Average
0  Doohickey  114.679742
1     Gadget  123.530916
2      Gizmo  120.897286
3     Widget  122.078721

具有 Tidyverse 的 R

我們的範例 R 版本具有與 Python 版本相同的結構。與大多數資料科學家一樣,我們使用 tidyverse 程式庫系列,因此讓我們載入這些程式庫以及 httr(用於管理 HTTP 請求)、jsonlite(用於剖析 JSON)和 glue(用於字串格式化)

library(tidyverse)
library(httr)
library(jsonlite)
library(glue)

我們將 API 金鑰放在標頭中。

headers <- add_headers('x-api-key' = YOUR_API_KEY)

然後,我們取得有關所有問題的資訊,並詢問哪些問題是公開的

data <- GET('https://127.0.0.1:3000/api/card', headers) %>%
  content(as = 'text', encoding = 'UTF-8') %>%
  fromJSON()
num_questions <- data %>%
  nrow()
num_public <- data %>%
  pull(public_uuid) %>%
  discard(is.na) %>%
  length()
glue('{num_public} public of {num_questions} questions')
1 public of 2 questions

顯示第一個公開卡片的標題會產生與 Python 相同的結果,這令人放心

uuid <- data %>%
  pull(public_uuid) %>%
  discard(is.na) %>%
  first()
data <- glue('https://127.0.0.1:3000/api/public/card/{uuid}') %>%
  GET(headers) %>%
  content(as = 'text', encoding = 'UTF-8') %>%
  fromJSON()
glue('First title: {data$name}')
First title: Average value of orders over $100 grouped by category

一旦我們將與該卡片關聯的資料轉換為 tibble,資料也相同,儘管 R 的預設顯示不會為我們提供那麼多小數位數

data <- glue('https://127.0.0.1:3000/api/public/card/{uuid}/query') %>%
  GET(headers) %>%
  content(as = 'text', encoding = 'UTF-8') %>%
  fromJSON()
rows <- data$data$rows
colnames(rows) <- c('Category', 'Average')
rows <- rows %>% as_tibble()
rows$Average <- as.numeric(rows$Average)
glue('First data')
rows
First data
# A tibble: 4 x 2
  Category  Average
  <chr>       <dbl>
1 Doohickey    115.
2 Gadget       124.
3 Gizmo        121.
4 Widget       122.

Node.js 上的 JavaScript

JavaScript 是一種日益普及的伺服器端腳本語言,但與 Python 和 R 不同,JavaScript 缺乏一個用於資料表格的單一主要函式庫。對於大型專案,我們偏好使用 data-forge,但對於小型範例,我們堅持使用 Dataframe-js。我們也使用 got 來發送 HTTP 請求,而不是較舊的 request 套件,因為後者現在已被棄用。最後,由於我們發現 async/await 語法比 promise 或 callbacks 更容易閱讀,因此我們將所有程式碼都放在一個 async 函式中,然後立即呼叫它

const got = require("got");
const DataFrame = require("dataframe-js").DataFrame;

const main = async () => {
  // ...program goes here...
};

main();

再次從驗證身分開始

headers = { "x-api-key": YOUR_API_KEY };

然後,我們要求取得完整的問題列表,並篩選它們以選取公開的問題

response = await got.get("https://127.0.0.1:3000/api/card", {
  responseType: "json",
  headers: headers,
});
// filter for public questions
questions = response.body.filter((q) => q.public_uuid);
console.log(`${questions.length} public of ${response.body.length} questions`);
1 public of 2 questions

第一個公開卡片仍然具有我們之前看過的標題

const uuid = questions[0].public_uuid;
response = await got.get(`https://127.0.0.1:3000/api/public/card/${uuid}`, {
  responseType: "json",
  headers: headers,
});
console.log(`First title: ${response.body.name}`);
First title: Average value of orders over $100 grouped by category

當我們拉取其資料時,我們得到相同的數值,儘管數字以另一種稍微不同的方式顯示

response = await got.get(
  `https://127.0.0.1:3000/api/public/card/${uuid}/query`,
  {
    responseType: "json",
    headers: headers,
  },
);
const rows = response.body.data.rows;
const df = new DataFrame(rows, ["Category", "Average"]);
df.show();
| Category  | Average   |
------------------------
| Doohickey | 114.67... |
| Gadget    | 123.53... |
| Gizmo     | 120.89... |
| Widget    | 122.07... |

使用工作階段令牌驗證您的請求

您應該改用 API 金鑰。包含以下資訊只是為了以防萬一您需要因任何原因使用工作階段令牌。

您也可以使用工作階段令牌來驗證您的請求。若要取得工作階段令牌,請向 /api/session 端點提交包含您的使用者名稱和密碼的請求

curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"username": "person@metabase.com", "password": "fakepassword"}' \
  https://127.0.0.1:3000/api/session

如果您正在使用遠端伺服器,則需要將 localhost:3000 替換為您的伺服器位址。此請求將傳回一個 JSON 物件,其中包含一個名為 id 的鍵,以及作為該鍵值的令牌,例如

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

然後,您可以像這樣將該工作階段令牌包含在後續請求的標頭中

"X-Metabase-Session": "38f4939c-ad7f-4cbe-ae54-30946daf8593"

關於工作階段的一些注意事項

  • 預設情況下,工作階段有效期為 14 天。您可以透過設定環境變數 MB_SESSION_AGE(值以分鐘為單位)來設定此工作階段持續時間。
  • 您應該快取憑證以重複使用它們直到過期,因為為了安全起見,登入會受到速率限制。
  • 無效和過期的工作階段令牌會傳回 401(未經授權)狀態碼。
  • 優雅地處理 401 狀態碼。我們建議編寫您的程式碼以取得新的工作階段令牌,並在 API 傳回 401 狀態碼時自動重試請求。
  • 某些端點要求使用者是管理員,也稱為超級使用者。需要管理員或超級使用者狀態(管理員 = 超級使用者)的端點通常會在其文件中說明。如果目前使用者不是管理員,它們將傳回 403(禁止)狀態碼

簡而言之:改用 API 金鑰

玩得開心

如果您覺得本教學課程有趣,您可以啟動 Metabase 的本機執行個體、試驗 API,並玩得開心!如果您遇到困難,請查看我們的論壇,看看是否有人遇到類似的問題,或發布新問題。