FluctとAPI Gateway+Lambdaで、Backlogの更新をChatworkに伝える

## 実現したいこと

Backlogの更新をChatworkに伝たい。
それも、安く。今風に。

（実際、参考に書いた記事の焼き直しです。。先人の知恵に感謝です。）

## 出来たもの

[noboru-i/backlog-to-chatwork](https://github.com/noboru-i/backlog-to-chatwork/tree/1c4b1aad711b83ee51bf5a197b81abf4ffd92ae9)

## 手順

### Fluctを利用して、アプリケーションを生成する。

http://qiita.com/r7kamura/items/80e5e9b2f5c9d1b3497e

```bash
fluct new backlog-to-chatwork
cd backlog-to-chatwork
fluct generate webhook
```

### package.jsonにライブラリを設定する。

`request`モジュールを利用するため、`package.json`に追加しておきます。
（Fluctにバグがある気がします。後述します。）

### Actionの設定を変更する。

```json:package.json
{
  "name": "webhook",
  "private": true,
  "fluct": {
    "contentType": "application/json",
    "httpMethod": "POST",
    "path": "/webhook",
    "statusCode": 200
  }
}
```

`httpMethod`をPOSTに変更し、`path`を任意の値に設定します。

### メインのJSを実装する。

```js:index.js
var request = require('request');

// constants
var CHATWORK_API_KEY = 'XXX';
var ROOM_ID = 'XXX';
var BACKLOG_URL = 'https://XXX.backlog.jp/';

function create_link(event, content) {
  var url = BACKLOG_URL + "view/" + event.project.projectKey + "-" + content.key_id;
  if (content.comment && content.comment.id) {
    url += "#comment-" + content.comment.id;
  }
  return url;
}

function create_links(event, link) {
  var urls = [];
  link.forEach(function(content) {
    urls.push(create_link(event, content));
  });
  return urls;
}

function create_message(event) {
  switch(event.type) {
    case 1:
      return "[info][title]" + event.createdUser.name + "が「" + event.content.summary + "」を追加しました。[/title]" + create_link(event, event.content) + "[/info]";
    case 2:
    case 3:
      return "[info][title]" + event.createdUser.name + "が「" + event.content.summary + "」を更新しました。[/title]" + create_link(event, event.content) + "\n\n" + event.content.comment.content + "[/info]";
    case 14:
      return "[info][title]" + event.createdUser.name + "が課題をまとめて更新しました。[/title]" + create_links(event, event.content.link).join("\n") + "[/info]";
  }
  return "unknown event type: " + event.type;
}

function post_to_chatwork(message, callback) {
  var url = 'https://api.chatwork.com/v1';

  var options = {
    url: url + "/rooms/" + ROOM_ID + "/messages",
    headers : {
      'X-ChatWorkToken': CHATWORK_API_KEY
    },
    form: {
      'body': message
    }
  };
  request.post(options, function (error, response, body) {
    if (!error && response.statusCode == 200) {
      console.log(body);
    }
    callback(error, response, body);
  });

}

exports.handler = function(event, context) {
  console.log('start event');
  var message = create_message(event.requestParameters);
  console.log('send message: ' + message);

  post_to_chatwork(message, function(error, response, body) {
    console.log('response body: ' + body);

    console.log('end event');
    context.done(null, 'ok');
  });
};
```

認証情報などを下記のように設定する必要があります。
`CHATWORK_API_KEY`:Chatworkから取得したAPIトークン
`ROOM_ID`:送信先のroom_id
`BACKLOG_URL`: Backlog登録時のサブドメインを設定したURL

とりあえずということで、課題の追加・更新のみを対象としています。

### デプロイする

```
fluct deploy
```

デプロイが成功すると、URLが返却されます。

> Uploaded function: webhook
> Updated endpoint: POST /webhook
> Deployed: https://XXX.execute-api.us-east-1.amazonaws.com/production

### Backlogのwebhook設定する。

デプロイ時に返却されたURL+パスをBacklogに設定します。

![image](https://qiita-image-store.s3.amazonaws.com/0/8708/7a7fec84-4724-d2f4-9c4d-a261628662fd.png)

### 確認する。

Backlog上で、課題を追加してみる。

Chatworkの指定のチャットルームに、下記のようなメッセージが表示される。

![image](https://qiita-image-store.s3.amazonaws.com/0/8708/68421817-4607-610b-3977-51e068d2d4ee.png)


## 困ったこと

### `event`変数の形式

最初は、Fluct無しで実装していました。
その時は、メインの`handler`内で`event.type`のようにwebhookの内容が取得できていました。
それが、Fluctを使うと取得できなくなって、`event`をそのまま取得してみると、`event.requestParameters.type`のように取得する必要があることがわかりました。

何が違うのか調べたところ、API Gatewayの`Integration Request`にMappingが設定されていました。

ここで、JSONの形式を変換していたようです。

### `request`モジュールが読み込めない

Fluctのサンプルアプリケーションをみると、rootの`package.json`に記載されている`dependencies`は生成されたzipに取り込まれるようでした。
そのため、下記のように必要なモジュールだけを記載しました。

```
  "dependencies": {
    "request": "^2.62.0"
  }
```

すると、zipファイルに取り込まれませんでした。
https://github.com/r7kamura/fluct/blob/3b58f6b876534abc445b15a535d77616b51fcf2d/src/composer.js#L120
ここで、`this.application.getProductionPackageNames()`がArrayじゃないからな気はしてるけど、深追いしてないです。
とりあえず、2つにしたらちゃんと動きました。

## 参考

- [最近の更新の取得 | Backlog API | Nulab Developers](http://developer.nulab-inc.com/ja/docs/backlog/api/2/get-activities)
- [チャットワークAPIドキュメント](http://developer.chatwork.com/ja/index.html)
- [【AWS】API GatewayとLambdaを使ってBacklog Webhookを扱ってみた ｜ Developers.IO](http://dev.classmethod.jp/etc/backlog-webhook-api-gateway/)
- [FluctとAPI Gateway+LambdaでWebアプリをつくる - Qiita](http://qiita.com/r7kamura/items/80e5e9b2f5c9d1b3497e)
- [r7kamura/fluct-example](https://github.com/r7kamura/fluct-example)