LCL Engineers' Blog

バス比較なび・格安移動・バスとりっぷを運営する LCLの開発者ブログ

ChatWorkのWebhookをRuby/Railsで受信する

先日、ChatworkがWebhookに対応されました。弊社では普段からChatworkを利用しており、早速検証しました。

ビジネスチャット「チャットワーク」がWebhookとOAuthに対応、オープンβ版の提供開始〜2018年春までにクラウドサービス17社18サービスとデータ連携開始予定〜 ~ ChatWorkニュースリリース

Webhook対応でできること

ChatworkがWebhookに対応したことで、「自分宛のメッセージ受信」「特定のルームでの発言」等をトリガーに、任意のURLを呼び出し処理を実行できるようになります。

今までも、APIで特定のルームのメッセージをポーリングすることで、同様のことは実現できました。ただし、APIリクエスト数の「5分あたり100回」という制限もあり、リアルタイム性に課題がありました。

Webhookの利用方法

公式ドキュメントに詳しく記載されていますが、簡単に紹介したいと思います。

Webhook - チャットワークAPIドキュメント

Webhookの受信側の準備

AWS EC2上にRailsアプリケーションを構築し、Webhookから呼び出すコントローラを準備します。

class Chatwork::WebhookController < ApplicationController    
  def test
    # 処理を実装
  end
end

Webhookの作成

Chatworkの設定画面で、Webhookメニューが新しく追加されており、そこからWebhookが作成できます。

  • Webhook名
    • 任意です
  • Webhook URL
    • httpsから始まる必要があります。
  • イベント
    • トリガーとなるイベントを設定します。
    • アカウントに対するイベントか、特定のルームでのイベントのどちらかが選択できます。
    • ルームイベントの場合は、自身が所属するルームIDしか入力できません。

f:id:lcl-engineer:20171104171523p:plain

Webhookの確認

該当のルームでメッセージを投稿すると、指定したWebhook URLが呼び出され、Chatworkから以下のデータがPOSTされます。 ポーリングとは異なり、即座に反応します。

 {"webhook_setting_id"=>"xxxxxxxxxxxx", 
 "webhook_event_type"=>"message_created", 
 "webhook_event_time"=>1509724361, 
 "webhook_event"=>{"message_id"=>"xxxxxxxxxxxx", 
 "room_id"=>xxxxxxxxxxxx, 
 "account_id"=>xxxxxxxxxxxx, 
 "body"=>"テストメッセージ", 
 "send_time"=>1509724361, 
 "update_time"=>0}, 
 "room_id"=>"xxxxxxxxxxxx", 
 "webhook"=>{"webhook_setting_id"=>"xxx", 
 "webhook_event_type"=>"message_created", 
 "webhook_event_time"=>1509724361, 
 "webhook_event"=>{"message_id"=>"xxxxxxxxxxxx", 
 "room_id"=>xxxxxxxxxxxx, 
 "account_id"=>xxxxxxxxxxxx, 
 "body"=>"テストメッセージ", 
 "send_time"=>1509724361, 
 "update_time"=>0}}}

これでWebhookの設定は完了です。あとはパラメータの内容を解析して、任意の処理を実装すれば、Chatworkでの投稿をトリガーとしたBotが作成できます。

リクエストの署名検証

実装上必須ではありませんが、Webhookリクエストの送信元がChatworkであることを、確認する方法が用意されています。

  1. トークンをBASE64デコードしたバイト列を秘密鍵として、HMAC-SHA256アルゴリズムによりリクエストボディのダイジェスト値を得ます
  2. ダイジェスト値をBASE64エンコードした文字列が、リクエストヘッダに付与されたsignature(X-ChatWorkWebhookSignatureヘッダの値)と一致することを確認します

上記の説明だけでは少し複雑ですが、Ruby/Railsでは、以下のように実装しました。

require 'openssl'
require 'base64'

def test
  if chatwork_signature.present? && chatwork_signature == Base64.strict_encode64(digest)
    render text: 'success', status: 200
  else
    render text: 'invalid', status: 403
  end
end

private

def secret_key
  token = '[トークン]'
  Base64.decode64(token)
end

def request_body
  request.body.read
end

def chatwork_signature
  request.headers[:HTTP_X_CHATWORKWEBHOOKSIGNATURE]
end

def digest
  OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), secret_key, request_body)
en

※ トークンは、Webhookの設定画面から確認できます。

f:id:lcl-engineer:20171104171542p:plain

まとめ

Webhookを利用すると、簡単にリアルタイム性の高いやりとりが実現できることが確認できました。

弊社では、既にChatworkとHubot連携してデプロイ等を行っていますが、Webhookを利用して更に自動化を進めていきたいと思います。

techblog.lclco.com

LCLではエンジニア・インターン募集中です。 サービス開発はもちろん、開発プロセスの自動化も積極的に推進しています。 少しでも興味がある方は、ご連絡お願い致します。

https://www.lclco.com/recruit/