LoginSignup
11
8

More than 3 years have passed since last update.

Redash APIで動的に結果を取得する

Last updated at Posted at 2020-01-15

前提

  • Redash 2.0.0+b2990

記事中の記法

  • <host>はRedashのホストを意味します。たとえば、あなたの環境のRedashのGUIにアクセスする際、 https://www.example.com/redash/ にアクセスしているのなら、これがホストです。<host>/api と記載した場合、https://www.example.com/redash/apiを意味します。
  • その他、<>で囲った文字は適宜変数を意味します。<query_id>

User API Keyを取得

メニュー>ユーザー名>API Key
redash01.png

クエリを実行

以下のURIをPOSTすると、クエリを実行できます。

<host>/api/queries/<query_id>/refresh?api_key=<user_api_key>

クエリ中にパラメータがある場合

クエリ中のパラメータはp_<parameter_name>=<value>の形式でURLクエリパラメータとして渡します。
たとえば、

select
  *
from
  users
where
  user_id = {{user_id}}

というクエリを、user_id=12345で実行する場合、POSTするURIは、以下のようになります。

<host>/api/queries/<query_id>/refresh?p_user_id=12345&api_key=<user_api_key>

応答

以下のようなJSONが返ってきます。

{
  "job": {
    "status": 2,
    "error": "",
    "id": "XXXXXXXXXXX",
    "query_result_id": null,
    "updated_at": 0
  }
}

※以降、上記のJSONのjob.idの値を<job_id>として扱います。

ジョブの状態を取得

以下のURIをGETするとジョブの状態を取得できます。

<host>/api/jobs/<job_id>?api_key=<user_api_key>

応答は/api/queries/<query_id>/refreshと同じ形式です。
ジョブが終了していれば、query_result_idに値が設定されます。
query_result_idの値がnullの場合は、ジョブの終了を待つ必要があります。

ジョブの結果を取得

以下のURIをGETすると、ジョブの結果が取得できます。

<host>/api/queries/<query_id>/results/<query_result_id>.json?api_key=<user_api_key>

ファイルの拡張子は.jsonのほかに.csvがあります。

スニペット(GAS用)

…を踏まえたコードをGAS用に書くとこうなります。

/**
 * 
 * @param {String} host https://redash.example.com 的なもの。末尾にスラッシュはつけないでください。
 * @param {String} queryId 123等
 * @param {String} apiKey 
 * @param {any[]} param クエリのパラメータの連想配列
 */
function callRedash(host, queryId, apiKey, param) {
    let queryParams = [`api_key=${apiKey}`]
    if (param) {
        for (let key in param) {
            const queryParam = `p_${key}=${param[key]}`;
            queryParams.push(queryParam);
        }
    }
    const refreshUri = `${host}/api/queries/${queryId}/refresh?${queryParams.join('&')}`;
    const refreshResult = UrlFetchApp.fetch(refreshUri, { "method": "POST" });
    const jobId = JSON.parse(refreshResult).job.id;

    const jobStatusUri = `${host}/api/jobs/${jobId}?api_key=${apiKey}`;
    let queryResultId = null;
    const startMills = new Date().getTime();
    while (true) {
        const endMills = new Date().getTime();
        if (endMills - startMills > (4 * 60 * 1000)) {
            // GASの実行時間上限は5分なので、4分経過した時点で中断します。
            throw new Error("Redashへの問い合わせ開始から4分以上経過したため、中断します。");
        }
        const jobStatus = JSON.parse(UrlFetchApp.fetch(jobStatusUri)).job;
        const status = jobStatus.status;
        if (status === 3 || status === 4) {
            queryResultId = jobStatus.query_result_id;
            break; // 結果を取得できたのでbreak
        }
        Utilities.sleep(5000); //  5秒待機
    }

    const jobResultUri = `${host}/api/queries/${queryId}/results/${queryResultId}.json?api_key=${apiKey}`;
    const result = JSON.parse(UrlFetchApp.fetch(jobResultUri));
    return result.query_result.data.rows;
}
11
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
8