以前TableauOnlineまたはTableauServer上のワークブックやデータソースを管理できるツールを作りたいなと思い、Tableauが提供するREST APIを用いて実装しようとしました。
欲しい情報を取得するためにいろいろなREST APIのエンドポイントにリクエストを投げる必要があり、なかなか利用するのに苦労しました。
Metadata APIはエンドポイント1つに対し、GraphQLを使うことでエンドポイント1つでもいろいろ情報が取れるとのことです。
GraphQL自体使ったことがなかったので、どんな風に実装できるのか調査しました。
本記事ではPythonでMetadata APIでGraphQLのクエリを発行できるようになるまでを記事にしたいと思います。
- Tableau OnlineからAPI使用するためのトークンを取得する
- Metadata APIのエンドポイントへクエリ発行を行い、結果を取得する
Tableau Onlineバージョン:2021.4.0
※Tableau OnlineはDevelopper Programに登録することで利用できる環境を使用しています。
https://www.tableau.com/ja-jp/developer
Metadata APIはREST APIと同じ認証プロセスとトークンを使用します。
以下のREST APIのリファレンスサイトを参考に実装していきます。
https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_auth.htm
この項目にサインインリクエストのURIが書いてあります。<server-name>の部分は自身の接続先に置き換えます。
| http://<server-name>/api/3.13/auth/signin |
ボディに含める内容が書いてあります。
JSON形式では以下の形式で作成します。
※今回はユーザー名、パスワードでのサインイン処理で進めます。
以下はリファレンスサイトの例です。
| { |
| "credentials": { |
| "name": "admin", |
| "password": "p@ssword", |
| "site": { |
| "contentUrl": "MarketingTeam" |
| } |
| } |
| } |
本文中にJSONで送るときはヘッダに”Content-Type” : “application/json”つけてねとあるので、以下をヘッダに含めます。
| { |
| "accept": "application/json", |
| "Content-Type": "application/json" |
| } |
サインイン処理に成功したときのレスポンスの内容が書いてあります。
ヘルプの例にあるように、token部分(以下の例では12ab34cd56ef78ab90cd12ef34ab56cd)を使うことでAPIを使うことができます。
以下はリファレンスサイトの例です。
| { |
| "credentials": { |
| "site": { |
| "id": "9a8b7c6d5-e4f3-a2b1-c0d9-e8f7a6b5c4d", |
| "contentUrl": "" |
| }, |
| "user": { |
| "id": "9f9e9d9c-8b8a-8f8e-7d7c-7b7a6f6d6e6d" |
| }, |
| "token": "12ab34cd56ef78ab90cd12ef34ab56cd" |
| } |
| } |
ここまでで一旦トークン取得するまでをPythonで作ります。
| import requests |
| import json |
| def get_token(server, username, password, site): |
| # URLの構築(APIのバージョンが変わったら3.13の部分を変更する) |
| url = server + "/api/3.13/auth/signin" |
| # ヘッダ |
| headers = { |
| "accept": "application/json", |
| "content-type": "application/json" |
| } |
| # ボディ |
| body = {"credentials": {"name": username, "password": password, "site": {"contentUrl": site}}} |
| # POST |
| pst = requests.post(url, json=body, headers=headers) |
| # 結果取得 |
| response = pst.json() |
| token = response["credentials"]["token"] |
| return token |
| def main(): |
| server = <Tableau OnlineのURL> |
| username = <ユーザー名> |
| password = <パスワード> |
| site = <サイト名> |
| token = get_token(server, username, password, site) |
| print(token) |
| if __name__ == "__main__": |
| main() |
トークンを取得できるようになったら、それを利用してMetadata APIを使っていきます。
トークンの渡し方が書いてあります。
ヘッダにX-Tableau-Authの値で含めて渡します。
| "X-Tableau-Auth" : <トークン> |
JSON形式でやり取りするので以下のようになります。
| { |
| "accept": "application/json", |
| "Content-Type": "application/json", |
| "X-Tableau-Auth": <トークン> |
| } |
ここからMetadata APIの内容になっていきます。
以下のリファレンスサイトを参考に進めます。
https://help.tableau.com/current/api/metadata_api/en-us/docs/meta_api_start.html
エンドポイントは以下となります。<server-name>の部分は自身の接続先に置き換えます。
| http://<server-name>/api/metadata/graphql |
クエリの例があります。
| query <query-name>{ |
| <object> (<arguments>){ |
| <attribute> |
| <attribute>{ |
| <attribute> |
| } |
| } |
| } |
ブラウザツールを使ってクエリをテストする環境のことが書かれています。
いろいろ書いてありますが、ログインした端末から以下のURLをブラウザで表示させればツールが使えるとのことです。
| http://<server-name>/metadata/graphiql/ |
・・・クエリ言語名はGraphQLだけどこっちはGraphiQLなんですね。GUIの名前でしょうか。
アクセスすると以下のような画面が表示されます。左側にクエリを書いて実行します。左側にリファレンスがあるのでそれを参考に組み立てられそうです。
とりあえず”WB01″という名前のワークブックの情報を取るクエリを作りました。
作ったクエリをリクエストボディに含めていきます。
リファレンスサイトでは見つけられませんでしたが、一般的に以下となります(JSON形式の場合)。
| { "query": <クエリ本文>} |
今回は以下のように作成しました。
| "query": |
| ''' |
| query getworkbook{ |
| workbooks(filter: {name: "WB01"}) { |
| id |
| name |
| projectName |
| createdAt |
| updatedAt |
| sheets { |
| name |
| } |
| } |
| } |
| ''' |
レスポンスの構造が書いてあります。
“data”の項目をひとまず取得すれば大丈夫そうです。
以下はリファレンスサイトの例です。
| { |
| "data": { |
| "databases": [ |
| { |
| "name": "adventureworks", |
| "tables": [ |
| { |
| "name": "AWBuildVersion" |
| } |
| ] |
| }, |
| (省略) |
| ] |
| } |
| } |
ここまでの内容をPythonで作成します。
| import requests |
| import json |
| # トークンの取得 |
| def get_token(server, username, password, site): |
| # URLの構築(APIのバージョンが変わったら3.13の部分を変更する) |
| url = server + "/api/3.13/auth/signin" |
| # ヘッダ |
| headers = { |
| "accept": "application/json", |
| "content-type": "application/json" |
| } |
| # ボディ |
| body = {"credentials": {"name": username, |
| "password": password, "site": {"contentUrl": site}}} |
| # POST |
| pst = requests.post(url, json=body, headers=headers) |
| # 結果取得 |
| response = pst.json() |
| token = response["credentials"]["token"] |
| return token |
| # MetaData APIの実行 |
| def executeMetaDataAPI(server, token): |
| # URLの構築 |
| url = server + "/api/metadata/graphql" |
| # ヘッダ |
| headers = { |
| "accept": "application/json", |
| "content-type": "application/json", |
| "X-tableau-auth": token |
| } |
| # ボディ(クエリ) |
| body = { |
| "query": |
| ''' |
| query getworkbook{ |
| workbooks(filter: {name: "WB01"}) { |
| id |
| name |
| projectName |
| createdAt |
| updatedAt |
| sheets { |
| name |
| } |
| } |
| } |
| ''' |
| } |
| # POST |
| pst = requests.post(url, json=body, headers=headers) |
| response = pst.json() |
| # 結果取得 |
| data = response["data"] |
| print(data) |
| def main(): |
| server = <Tableau OnlineのURL> |
| username = <ユーザー名> |
| password = <パスワード> |
| site = <サイト名> |
| token = get_token(server, username, password, site) |
| data = executeMetaDataAPI(server, token) |
| if __name__ == "__main__": |
| main() |
| { |
| 'workbooks': [ |
| { |
| 'id': 'xxxxxx', |
| 'name': 'WB01', |
| 'projectName': 'Test01', |
| 'createdAt': '2021-05-30T12: 20: 23Z', |
| 'updatedAt': '2021-05-30T12: 20: 23Z', |
| 'sheets': [ |
| { |
| 'name': 'シート 1' |
| } |
| ] |
| } |
| ] |
| } |
Metadata APIを使って情報取得できるようになりました。
今回GraphQLの書き方がわかっていない部分が多かったので静的なクエリでの実装を行いましたが、
クエリ内に変数を組み込んで動的なクエリに発展させていくこともできそうでした。
使い勝手としてはエンドポイントが1つなのは嬉しいですが、GraphiQLでの記述が使いこなせるかといった具合になりそうです。
最後までお読みいただきありがとうございました。


