Backlog APIを使ってみた

## このメモの説明

[BacklogのAPI](https://developer.nulab.com/ja/docs/backlog/)を利用してプロジェクト管理を楽にできないかなと試行錯誤しています。
既に使い方の記事は他の方も書いていますが、自分自身の備忘録がてらメモを残すことにしました。

環境はGASです。

## API keyを発行

「個人設定」の「API」のページで新しいAPI keyを発行できます。

↓の{スペースの名前}を変更すると、APIのページになるかと思います。
`https://{スペースの名前}.backlog.jp/EditApiSettings.action`

↓こういうページです。
![APIkeyのページ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54830/2c1b3349-2a33-d4bd-9bc7-f3cd8087213c.png)

## プロジェクトIDの取り方（その他IDも）

プロジェクトのIDは、「プロジェクト設定」ページに移動した際のURLを見ると書いてあります。
`https://{スペースの名前}.backlog.jp/EditProject.action?project.id=xxxxxxxx`

これは他のIDについても同様で、それぞれの設定ページに移動すると、URLにIDが書いてあります。

マイルストーンならこんな感じ。
`https://{スペースの名前}.backlog.jp/EditVersion.action?version.id=xxxxxxxx`

種別ならこんな感じ。
`https://{スペースの名前}.backlog.jp/EditIssueType.action?issueType.id=xxxxxxxx&issueType.projectId=xxxxxxxx`
（issueType.idの方です。issueType.projectIdはproject.idと同じ）

## チケット一覧を取得してみる

取得する場合は`GET`です。
条件等はクエリパラメータで指定します。

例えば、スペースの名前がhogefugaで、API keyが'1234567890'、プロジェクトと課題の種別を固定し、状態が完了以外のチケットを取得したいとなると、↓のようになります。

```javascript
function getTickets(apiKey, baseUrl, projectId, issueTypeId) {
  var url = baseUrl + '/api/v2/issues'
    + '?' + 'apiKey=' + apiKey
    + '&' + 'projectId[]=' + projectId
    + '&' + 'issueTypeId[]=' + issueTypeId
    + '&' + 'statusId[]=' + '1'
    + '&' + 'statusId[]=' + '2'
    + '&' + 'statusId[]=' + '3'
    ;
  return JSON.parse(UrlFetchApp.fetch(url).getContentText());
}
function main() {
  var json = getTickets('1234567890', 'https://hogefuga.backlog.jp', '123', '456');
}
```
チケットに限らず、取得系は大体同じです。

## チケットを追加してみる

追加する場合は`POST`です。
条件等はオプションに入れます。

例えば、スペースの名前がhogefugaで、API keyが'1234567890'、プロジェクトと課題の種別をマイルストーン固定した「たいとる」という題名のチケットを作成したい場合、↓のようになります。

```javascript
function createTicket(apiKey, baseUrl, projectId, issueTypeId, milestoneId, summary) {
  var payload = {
    "projectId" : projectId,
    "summary" : summary,
    "issueTypeId" : issueTypeId,
    "priorityId" : '3',
    "description" : '',
    "milestoneId[]" : milestoneId,
  }
  var options = {
    "method" : "POST",
    "payload" : payload
  }
  var url = baseUrl + '/api/v2/issues'
    + '?' + 'apiKey=' + apiKey
    ;
  return JSON.parse(UrlFetchApp.fetch(url, options).getContentText("UTF-8"));
}
function main() {
  var json = createTicket('1234567890', 'https://hogefuga.backlog.jp', '123', '456', '789', 'たいとる');
}
```

追加するうえで気を付けることですが、テストコードとして↑のmain()のようなコードを複数回実行すると、その回数分同じチケットができあがります。
↑の場合は「たいとる」というチケットが実行する度に作成されます。

## チケットを更新してみる

追加する場合は`PATCH`です。
条件等はオプションに入れます。

基本的には追加と同じです。
例えば、チケットの「詳細」だけを更新する場合は↓のようになります。

```javascript
function updateTicket(apiKey, baseUrl, ticketId, description) {
  var payload = {
    "description" : description,
  }
  var options = {
    "method" : "PATCH",
    "payload" : payload
  }
  var url = baseUrl + '/api/v2/issues'
    + '/' + ticketId
    + '?' + 'apiKey=' + PARAMS.apiKey
    ;
  return JSON.parse(UrlFetchApp.fetch(url, options).getContentText("UTF-8"));
}
function main() {
  var create = createTicket('1234567890', 'https://hogefuga.backlog.jp', '123', '456', '789', 'たいとる');
  var update = updateTicket('1234567890', 'https://hogefuga.backlog.jp', create.id, '詳細はこんな感じ');
}
```

## カスタム属性の扱いに困る

Backlogのチケットにはカスタム属性を付けることができますが、このカスタム属性をAPIから操作しようとすると、とてもめんどくさいです。

取得する時は、`customFields[n].id`がカスタム属性のIDと一致したところに入ってます。
この要素nは恐らく登録順ですが、実際に取得してみないと分かりません。（何か方法あるのだろうか？）

例えば、yes/noの選択肢を持つカスタム属性の値を取得したい場合は、予め手打ちで取得して、何番目の要素か（今回は20）を調べておきます。
そして↓のように取得します。
（直に使ってしまってますが、変数なり定数なりにして使用します）

```javascript
  var tickets = getTickets('1234567890', 'https://hogefuga.backlog.jp', '123', '456');
  tickets .forEach(function (t) {
    if (t.customFields[20].value.id == '1') {
      // yes
    } else {
      // no
    }
  });
```

追加する時は、`customField_${カスタム属性のID}`を指定します。
これも意外と面倒で、カスタム属性のIDを予め調べておいて、↓のように追加します。

```javascript
  var payload = {
    "projectId" : projectId,
    "summary" : summary,
    "issueTypeId" : issueTypeId,
    "priorityId" : '3',
    "description" : '',
    "milestoneId[]" : milestoneId,
  }
  payload["customField_" + customId] = '1';  // ← これカスタム属性
```

## 汎用的にしたいけど・・・

ある程度汎用的にして、ソース公開できればと思ってはいますが・・・
大小様々な規模のプロジェクトがあり、汎用的に作ったとしてもどうしてもカスタマイズが必要になります。
カスタム属性の扱いもあるので。

その為、なんだか格好悪いソースコードなのは分かりつつ、その場その場で必要なものを作ってます。

部分的に役に立ちそうなものがあれば、Qiitaに残していこうかな。