はじめての JIRA REST API

# はじめに

この投稿は [Atlassian User Group Tokyo Advent Calendar 2016](http://qiita.com/advent-calendar/2016/augtokyo) の11日目の記事です。

JIRA の REST API を使って課題を追加したりコメントしたりする方法をサンプルコードとともにご紹介します。（はじめて JIRA の API を使う人向け:hatching_chick:）

# 実施環境

今回紹介する内容を実際に試してみた環境は以下のとおりです。

| 項目 | 値 |
|:--|:--|
| JIRA バージョン | JIRA Core 7.2.2 |
| プログラム言語 | Node.js |

訳あって JIRA Core ですが、JIRA Software でも問題ありません。 :bow: 

# REST API を使った実装の紹介

それでは本題に入ります。（と、その前に・・・ JIRA の API についての情報を :tea: ）

## API についての情報

JIRA 7.x になって、SOAP と XML-RPC 形式の API が削除されたようです。代わりに、REST API が台頭し充実してきています。以前は、実装されていた機能が SOAP 形式のほうが多かったため、必然的に SOAP 形式を採用していた人もいると思われますが、比較的実装が容易な REST 形式での API は、JIRA 6.x の頃から Atlassian が推奨している形式でもあるため、これからも機能の拡充などが期待されます！

なお、公式のドキュメントがシッカリしているため、API の仕様について知りたいときは下記をご覧いただくのが良いかと思います。

* 最新のドキュメント（Server 版のため Cloud 版とは異なるかもしれません）
 * https://docs.atlassian.com/jira/REST/server/
* 今回使用したバージョン
 * https://docs.atlassian.com/jira/REST/7.2.2/

さて、以下からはお待ちかねの実装のお話です！

## ログイン

認証する方法はいくつかありますが、今回は Cookie ベースのログイン方式を選択しました。ログインに成功すると、一定期間有効な Cookie が発行されます。
この Cookie 情報をヘッダにつけて API リクエストを発行すれば、認証情報（ユーザ名とパスワード）をリクエストの度に指定する必要がなくなります。

```js:login.js
const request = require('request');

// Request params
const options = {
    uri: 'https://<jira_hostname>/rest/auth/1/session',
    headers: {
        Content-Type: 'application/json',
    },
    body: {
        username: '<your_account>',
        password: '<your_password>',
    },
    method: 'POST',
    json: true
};

// Post request
request(options, function (error, response, data) {
    if (!error && response.statusCode == 200) {
        console.log(data.session.name + ' = ' + data.session.value);
    } else {
        console.log('error: ' + response.statusCode + ': ' + data.errorMessages);
    }
});
```
※ `<jira_hostname>`、`<your_accout>`、`<your_password>` の部分は適宜置き換えてください。

正常に認証をパスすると、以下のような文字列が出力されます。（マスキングしてますが、実際はランダム文字列になります）

```
JSESSIONID = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

## プロジェクトの作成

まずは、プロジェクトから作ってみましょう！
ログイン成功時に取得したセッション情報を変数 `session_name` および `session_value` に代入しているものとしてサンプルコードを記載します。

```js:add_project.js
const options = {
    uri: 'https://<jira_hostname>/rest/api/2/project',
    headers: {
        'Content-Type': 'application/json',
        cookie: session_name + '=' + session_value,
    },
    body: {
        key: 'TESTPJ',
        name: 'Test Project',
        lead: "<project_leader_account>",
        projectTypeKey: 'business',
    },
    method: 'POST',
    json: true,
};

request(options, function (error, response, data) {
    if (!error && response.statusCode == 201) {
        console.log('Created project: ' + data.key); // --> Created project: TESTPJ
    } else {
        console.log('error: ' + response.statusCode + ': ' + data.errorMessages);
    }
});
```

※ `<project_leader_account>` は実在するユーザのアカウントにします。

プロジェクトの作成には、以下の情報などを指定します。

- プロジェクト名
- プロジェクトキー
- プロジェクトリーダー
- プロジェクトタイプ

ココで重要なのが一番下のプロジェクトタイプの指定です。これは、JIRA 7.x からの機能ですが、プロジェクトを `software` と `bussiness` という2タイプに分類するようになっています。JIRA Software ではなく JIRA Core を使っている場合は `business` しか利用できないのですが、API でプロジェクトを作る際は明示的に指定してあげる必要があります。

なお、`projectTemplateKey` という項目でプロジェクトテンプレートを指定してあげれば、プロジェクト作成時の各種スキーム設定を希望のものでプロジェクトを作ることができますので便利かもしれません。

※ プロジェクトテンプレートの説明に関しては[こちら](https://developer.atlassian.com/jiradev/jira-platform/guides/projects/tutorial-creating-a-project-template)のドキュメントを参照ください。
※ テンプレートの開発が :no_good_tone1: という方は、プラグイン [Gaia for JIRA - Project Template Manager](https://marketplace.atlassian.com/plugins/ca.nuum.gaia/server/overview) を導入してみると良いかもしれません。有料プラグインですが便利です。

## 課題の作成

それでは遂に、作成したプロジェクトに新しい課題を追加してみましょう！ヽ(｀▽´)/
課題の作成に必要な情報はプロジェクトのスキーム（プロジェクトタイプ？）によって異なります。不足事項やフォーマットにズレがあると 400 エラーとなってしまいますので、実際に UI から必須項目を確認しておくと良いでしょう。

```js:add_issue.js
const options = {
    uri: 'https://<jira_hostname>/rest/api/2/issue',
    headers: {
        'Content-Type': 'application/json',
        cookie: session_name + '=' + session_value,
    },
    body: {
        fields: {
            project: {
                key: 'TESTPJ'
            },
            summary: 'First issue in TESTPJ',
            description: "Hi Qiita,\nI am yutwatan.",
            issuetype: {
                id: '10200'  // Task
            },
            reporter: {
                name: 'yutwatan'
            },
        }
    },
    method: 'POST',
    json: true,
};

request(options, function (error, response, data) {
    if (!error && response.statusCode == 201) {
        console.log('Created issue: ' + data.key);  // --> Created issue: TESTPJ-2
    } else {
        console.log('error: ' + response.statusCode + ': ' + data.errorMessages);
        console.log(error);
    }
});
```

※ 作成される課題の番号は、現存する課題の最大値がインクリメントされた値です。固有の番号で課題を作ることはできません。

## コメントの追加

今度は、追加した課題にコメントを投稿してみたいと思います。(・∀・)

```js:add_comment.js
const options = {
    uri: 'https://<jira_hostname>/rest/api/2/issue/TESTPJ-2/comment',
    headers: {
        'Content-Type': 'application/json',
        cookie: session_name + '=' + session_value,
    },
    body: {
        body: "I'm hungry"
    },
    method: 'POST',
    json: true,
};

request(options, function (error, response, data) {
    if (!error && response.statusCode == 201) {
        console.log('Added date of comment:' + data.created);
    } else {
        console.log('error: ' + response.statusCode + ': ' + data.errorMessages);
    }
});
```

とある JIRA インスタンスでの話ですが、コメントが 10,000 を超えている課題を見たときは思わず絶句しました　Σ(・∀・；)

## 課題情報の取得

最後は、一番単純な GET メソッドです。（こちらの機能を一番最初に紹介したほうが良かったのですが、作られている課題がゼロの場合は使えないので、最後に持ってきました）
REST 形式の使いやすさの一つでもありますが、ブラウザから URL を叩くだけで簡単に動作を確認（データを取得）することができます。仕様に応じたパラメータを指定するのも容易です。

```js:get_issue.js
const options = {
    uri: 'https://<jira_hostname>/rest/api/2/issue/TESTPJ-2',
    headers: {
        'Content-Type': 'application/json',
        cookie: session_name + '=' + session_value,
    },
    method: 'GET',
    json: true,
};

request(options, function (error, response, data) {
    if (!error && response.statusCode == 200) {
        console.log('Get issue: ' + data.fields.summary); // --> Get issue: First issue in TESTPJ
    } else {
        console.log('error: ' + response.statusCode + ': ' + data.errorMessages);
    }
});
```

上のサンプルでは Summary しか出力していませんが、実際に返ってくるデータにはいろいろな情報が詰め込まれています。ブラウザからも確認できますので、ホント便利です。

# おわりに

以上で、REST API の基本的な使い方の説明は終わりです。:hotsprings: いかがでしたでしょうか？

REST API を使えば、様々なツールからの連携も思いのままです！
もし、実際に試してみたくなった人がいましたら、[Atlassian の SDK](https://developer.atlassian.com/docs/getting-started) を使うと、簡単にローカル PC に JIRA をたてることができますので是非お試しください！
（もう少しちゃんとした検証環境がほしいときは [Docker Image](https://hub.docker.com/search/?isAutomated=0&isOfficial=0&page=1&pullCount=0&q=jira&starCount=0) も公開されているようなのでそちらを使っても良いかもしれません）

----
明日は、@ohnuki さんの ~~Addon 開発~~ Design Sprint のお話です:exclamation::exclamation: