chatworkのwebhookを利用したBot的なものをNode.jsで実装する

PHPとかGASとかはあるけどNode.jsがなかったのでまとめた。
TypeScriptで記述してるので適宜読み替えが必要。




Webhookを作成する




まずAPIが使用できるように設定する。フリーアカウントの場合は特にやることはない?
http://developer.chatwork.com/ja/index.html

チャットワーク右上のアカウント名 → API設定 → WebhookよりWebhookを作成する。
あるいは以下のURLからWebhookへ
https://www.chatwork.com/service/packages/chatwork/subpackages/api/token.php

chatwork webhook

Webhook名 は識別用の名前。なんでもいい。

Webhook URLはイベント発生時にPostされるURL。
アカウントイベントの場合は自分に対するメンションをトリガにWebhook URL にhookされる。
ルームイベントの場合は該当ルームに書き込みがある度にhookされる。ルームイベントを拾って同じルームにPostするような作りにすると自動Postされたメッセージをhookして無限ループに入る可能性があるので注意すること。というか一回やらかした。

ルームIDはchatwarkのURL https://www.chatwork.com/#!ridXXXXXXXX のXXXXXXXXのこと




実装サンプル




Webhook URLをhttps::/[hostname]/api/chatwork
のようにした場合

router.post("api/chatwork", (req, res, { }) => {
  // 処理
})
でメッセージを受け取れるようになる。

またjsonでPostされるので受け取れるように設定しておく必要がある。
app.use(bodyParser.json())

色々手を加えていて以下のようにしていた時はbodyに正しく値が入ってこなかった(多分やらないと思うが一応)
app.use(bodyParser.json({ type: 'application/*+json' }))

req.body.webhook_event.body
にメッセージが入ってくるようになる。
これを利用していろいろやって見る。

以下はチャットワークへポストしたときに文章中の
<bot call>
に反応してメッセージをおうむ返しするような処理にしている。
上にも書いたが"<bot call>"を消し忘れると無限ループする。しかも結構早い速度でメッセージが投稿され続ける。

import * as request from "request"

router.post("api/chatwork", (req, res, { }) => {
  if (req.body.webhook_event.body.indexOf("<bot call>") !== -1) {
    let msg: string = req.body.webhook_event.body
    msg = msg.replace(/<bot call>/g, "")
    // msg = msg.replace(/\n/g, " ")
  
    // 以下はチャットワークへの投稿処理
    // チャットワークのトークン
    const TOKEN = "xxxxxxxxxxxxxxxxxxxxxx"
    // ルームID
    const roomId = "XXXXXXXX"
    const options = {
      url: `https://api.chatwork.com/v2/rooms/${roomId}/messages`,
      headers: {
        "X-ChatWorkToken": TOKEN,
      },
      form: { body: msg },
      json: true,
    }    
    // setTimeoutがないとうまく動作しなかった気がする
    setTimeout(() => {
      request.post(options, (error: string, response, body: string) => {
        if (!error && response.statusCode === 200) {
          console.log(body)
        } else {
          console.log("error: " + response.statusCode)
        }
      })
    }, 10)
  
  }
  res.sendStatus(200)
})


ドキュメントにはステータスコード200を返せとあるが返さなくても一応動く。
またエラーが起きたとしても再送されない(出来ない)


これでボットの基本機能は完成。


参考


Webhookについての公式ドキュメント
http://developer.chatwork.com/ja/webhook.html
署名処理
http://creators-note.chatwork.com/entry/2017/11/22/165516

2018年5月11日金曜日