WebhookでQiita:Teamの各種イベントを受け取る


# 概要

Qiita:Teamで発生する様々なイベントはWebhookで受取ることができます。これを利用すれば新規投稿や記事の更新、コメントが投稿されたタイミングで任意の処理を実行できます。この記事はWebhookでQiita:Teamからのイベントを受け取る具体的な方法についてのメモです。

# ドキュメント

[Qiita:DeveloperのWebhooks](https://qiita.com/api/webhook/docs)にWebhookの仕様がまとまっています。ドキュメントより、Qiita:Teamから受け取れるイベントの一覧は以下のようになっています

|イベント名|概要|
|:--|:--|
|ItemCreated|記事が作成されたときに送信|
|ItemDestroyed|記事が削除されたときに送信|
|ItemUpdated|記事が更新されたときに送信|
|CommentCreated|コメントが作成されたときに送信|
|CommentDestroyed|コメントが削除されたときに送信|
|CommentUpdated|コメントが更新されたときに送信|
|MemberAdded|チームメンバーが追加されたときに送信|
|MemberRemoved|チームメンバーが離脱したときに送信|
|PingRequested|Webhookの設定画面からテストを行ったときに送信|
|ProjectCreated|プロジェクトが作成されたときに送信|
|ProjectDestroyed|プロジェクトが削除されたときに送信|
|ProjectUpdated|プロジェクトが更新されたときに送信|


## 設定方法

設定メニューからWebhookの設定をします。通知したいイベントにチェックを付け保存します。URLにはイベントを送信したいURLを指定します。これで設定は完了です。Webhookの設定はチームの管理者のみ設定メニューに表示されます。

![Kobito.6901by.png](https://qiita-image-store.s3.amazonaws.com/0/43438/250d8476-c91d-81a8-b8ca-382aad1cb731.png "Kobito.6901by.png")

## リクエスト

イベントが発生すると指定したURLにPOSTリクエストが送信されます。リクエストボディにJSON形式でエンコードされた文字列が含まれ、これを`Payload`と呼びます。

また、共通リクエストヘッダとして`X-Qiita-Event-Model`に`Payload`の`model`プロパティと同様の値が、`X-Qiita-Token`にWebhookに割り当てられたトークンが含まれます。

## Payload

`Payload`には、必ず`action`プロパティと`model`プロパティが含まれ、`action`プロパティは「どのイベントが発生したか」を表す文字列で、`model`プロパティは「何に対してイベントが発生したか」を表す文字列です。この他に各イベントに関連するデータが含まれます。

例えば記事作成を表すItemCreatedイベントの場合、Payloadは以下の様になります。その他のイベントについては[公式ドキュメント](https://qiita.com/api/webhook/docs)を参照してください。

|プロパティ名|型|説明|
|:--|:--|:--
|action|String|"created"
|model|String|"item"
|item|Item|作成された記事
|user|User|作成したユーザ

`Item`、`User`型がどのようなプロパティを含むかは、[公式ドキュメントのTypes](https://qiita.com/api/webhook/docs#13)から確認できます。

# Webhookの受け取り

今回はHeroku上にホストした[Hubot](https://hubot.github.com/)でWebhookを受け取ります。Qiita:TeamからのWebhookはPOSTリクエストですので、Hubotの[HTTP Listener](https://github.com/github/hubot/blob/master/docs/scripting.md#http-listener)を利用してイベントを受け取ります。

Webhookの設定で指定するURLは`/qiita/webhooks`としました。

## サンプルコード

実際のコードは以下のようになります。このコードをHubotプロジェクトのscriptsディレクトリ以下に配置します。

```javascript
module.exports = (robot) => {
  robot.router.post('/qiita/webhooks', (req, res) => {
    console.log(req.body);
    res.end();
  });
}
```

## 動作例

例として以下のような投稿をQiita:Teamで作成します。

![Kobito.Lhacm0.png](https://qiita-image-store.s3.amazonaws.com/0/43438/46e8f495-671c-e7b5-bd69-4b683fe4d669.png "Kobito.Lhacm0.png")

その結果Qiita:TeamからWebhookのPOSTリクエストが送信され、以下のようなリクエストボディを受け取ることができます。

```js
{ action: 'created',
  item: { 
    body: '<p>test</p>\n',
    coediting: false,
    comment_count: 0,
    created_at_as_seconds: 1492484003,
    created_at_in_words: '1分未満',
    created_at: '2017-04-18 11:53:23 +0900',
    id: 993851,
    lgtm_count: 0,
    raw_body: 'test\n',
    stock_count: 0,
    stock_users: [],
    tags: [],
    title: 'test',
    updated_at: '2017-04-18 11:53:23 +0900',
    updated_at_in_words: '1分未満',
    url: 'https://vasily.qiita.com/Horie1024/items/1234567890abcdefghijk',
    user:
    { id: 43438,
      profile_image_url: 'https://qiita-image-store.s3.amazonaws.com/profile-images/xxxxxx',
      url_name: 'Horie1024' 
    },
    uuid: '1234567890abcdefghijk'
  },
  model: 'item',
  user:{ 
    id: 43438,
    profile_image_url: 'https://qiita-image-store.s3.amazonaws.com/profile-images/xxxxxx',
    url_name: 'Horie1024' 
  }
}
```

リクエストボディの`action`プロパティが`created`、`model`が`item`であることから記事の新規作成であることがわかります。

また、`item`プロパティはItem型で表され、ドキュメントの[Types#Item](https://qiita.com/api/webhook/docs#item)でItem型の各プロパティがどのような意味を持つのか確認できます。例えば、`raw_body`プロパティは記事本文、`body`プロパティは記事本文のHTML表現を表します。

# 応用例

[コードからtextlintを実行する](http://qiita.com/Horie1024/items/a21faa2b129022823dfb)と組み合わせるとQiita:Teamに投稿されたタイミングでtextlintで文章校正を実行することが可能です。

# 参考

- https://qiita.com/api/webhook/docs
- https://github.com/github/hubot/blob/master/docs/scripting.md#http-listener