JavaScript
Redmine
RedmineDay 7

RedmineのJavaScriptからREST APIを使用する

JavaScriptからでもRedmineのREST APIを実行することはできる。
しかしREST APIの実行にはBASIC認証かログインユーザーのapikeyが必要になる。

この記事では少々トリッキーながらJavaScriptからログインユーザーのapikeyを取得し、実際にREST APIを実行してみる。

動作確認は Redmine 2.6系 で行った。

REST APIを使わず、チケット一覧のコンテキストメニューが使用するbulk_updateを利用する記事はこちら。
RedmineのJavaScriptからbulk_updateを使用する

ログインユーザーのapikeyの取得

apikeyを取得するようなAPIは存在しない。
よってログインユーザーの「個人設定」をスクレイピングして取得する。
(下記コードは、当然ながらRedmineのバージョンアップなどで動かなくなる可能性はある)

// Redmine 3.1以前版。
// 3.1以降のいずれかのバージョンからはajaxでapikeyが埋め込まれるためこの方法だと失敗する。
// REST APIがONになっていなければapikeyには空文字が入る。
let apikey = "";
$.get('/my/account').done(function(data){
     apikey = $("#api-access-key", $(data)).first().text();
});

// Redmine 3.1以降版。専用ページなので読み込み負荷は若干低いはず。
// REST APIのON/OFFに関わらずapikeyにはAPIキーの文字列が入る。
let apikey = "";
$.get('/my/api_key').done(function(data){
    apikey = $('#content > div.box > pre', $(data)).first().text();
});

REST APIの実行

RedmineのAPIリファレンスを参考にしながら、ajax等でREST APIを叩く。

Redmine API

$.ajax({
    type: 'get',
    url: '/issues/7.json',
    data: {include:'relations'},
    headers: {'X-Redmine-API-Key': apikey},
    dataType: 'text',
    contentType: 'application/json',
})
.done((strJson) => console.log(JSON.parse(strJson)))

簡単にapikeyの取得とREST APIを続けて書くなら以下のようになるだろうか。

$.get('/my/account')
.then(
    // マイページをスクレイピングしてapikeyを取得
    (html) => {
        return $("#api-access-key", $(html)).first().text();
    }
)
.then(
    // REST APIでチケット詳細を取得
    (apikey) => {
        return $.ajax({
            type: 'get',
            url: '/issues/15780.json',
            data: {include:'relations'},
            headers: {'X-Redmine-API-Key': apikey},
            dataType: 'text',
            contentType: 'application/json',
        });
    }
)
.then(
    // 取得したチケット情報を表示
    (json) =>  console.log(json)
)

雑感

最初はapikeyを入力させるダイアログを作成し、Web Storage経由でapikeyを各画面で使い回す方法も考えた。
しかしRedmineの内部フックを使っているわけではないため、ログアウトしても前のユーザーのapikeyが残ってしまうのはセキュリティ的にかなりよくない。

(REST APIでアクセスできるデータを調べると分かるが、ユーザーのアクセス権限内ならばほぼ全てのデータを大量に読み書きできてしまう)

そこで多少"黒魔術"的ではあるしアクセス負荷が余計にかかるが、個人設定ページをスクレイピングしてapikeyを取得し使い捨てる方法を考えた。
これならクッキーにもWeb Storageにも残らず、個人ページをブラウザで開いてコピペするのと同じ処理になる。