Edited at
RedmineDay 7

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

More than 1 year has passed since last update.

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にも残らず、個人ページをブラウザで開いてコピペするのと同じ処理になる。