GASを使ったwrikeのwebhook


はじめに

私の担当するプロジェクトでは、現在タスク管理にwrike、コミュニケーションツールにslackを利用しています。
wrikeには

  • 柔軟なタスク設定
  • ガントチャート機能
  • 外部連携機能
  • 外部API

などが用意されています。

標準で利用できるSlack対応Wrikeアプリを利用すれば

  • タスクの追加
  • タスクへのコメント

などをslackのチャンネルに投稿することは可能ですが、slack上のメンションとしてユーザーを紐づけることは現在できません。
そこで、

  • wrikeからのwebhookリクエストをGoogleAppsScript(GAS)で受け取る
  • 受け取ったリクエストから欲しい情報を抜き出す
  • 加工した情報をslackに投稿する

の手順でslackユーザー宛にメンションできるようにしました。
今回wrikeからのwebhookリクエストをGoogleAppsScript(GAS)で受け取るまでにハマりどころがあったので、その辺りまで書いていこうと思います。

wrikeからのwebhookリクエストをGoogleAppsScript(GAS)で受け取る

やること

  • GASにWebhookを用意する
  • wrikeにwebhookを登録する
  • GASで受け取ったwebhookを処理する

GASにwebhookを用意する

詳しくわかりやすく書いてくださっている方がいらっしゃるので、

Google Spreadsheet を簡易 Webサーバーとして動かして、手軽にWebHookを受け取る方法

を参考にGASのwebhookUrlを発行します

wrikeにwebhookを登録する

wrikeのAPIドキュメントを参考にしながら、更新を検知したいプロジェクト(フォルダ)へのwebhookを設定していきます

まずはアクセストークンの発行

今回はoath2での認証をせずwrikeの設定ページからアクセスキーを発行します。
wrikeからアプリ&統合 -> APIアプリ を開いて、適当にアプリを登録。
すると画面最下部に永久アクセス・トークンの項目が表示されるので、そちらからアクセストークンを発行します
発行したトークンをAuthorizationのBearerTokenに乗せることでwrikeAPIが利用可能になります。

APIリクエストを送信してみる

APIを送信する場合は、取得したアクセストークンをAuthorizationのBearerTokenに指定します。
curlで送信する場合はこんな感じ

curl -X GET -H "Authorization: bearer [アクセストークン]" https://www.wrike.com/api/v4/folders

https://www.wrike.com/api/v4/foldersのGETリクエスト送信に成功した場合、wrike上のデータのjson配列が返却されます

例
[
 ...
    {
      "id": "HOGEHOGE", <- このIDがwebhook登録時に必要になる
      "title": "android",
      "childIds": [],
      "scope": "WsFolder",
      "project": {
        "authorId": "HOGEHOGE",
        "ownerIds": [],
        "customStatusId": "HOGEHOGE",
        "createdDate": "2020-11-09T08:09:27Z"
      }
    },
 ...
]

wrikeのwebhookに登録する場合、フォルダごとに設定されているidが必要になりますので、監視対象のフォルダのIDをメモしておきましょう。

webhookUrlを登録する

wrikeにwebhookを登録するで用意したGASのwebhookUrlをwrikeに登録していきます。
wrikeのwebhookに関するドキュメントはこちら
今回はフォルダ(プロジェクト)を指定して情報更新を取得したいので、
[POST] /folders/{folderId}/webhooksでwebhookを登録します。
登録前に指定可能なパラメータをざっと確認します。

  • hookUrl
    • Webhookの対象URL
      今回はここにGASで発行したwebhookUrlを指定します
  • secret (optional)
    • 検証用パラメータ
      今回は利用しません
  • events (optional)
    • wrike上でwebhookのトリガーになるイベント
      Event TypesでTaskCreatedCommentAddedなど様々なイベントが定義されているので、必要なものを指定します。
      特に指定がない場合は指定したフォルダに関する全てのEventでwebhookUrlが起動されます。
      今回の私の用途ではCommentAddedのみを指定しました
      このパラメータは配列で指定するのでevents=[hogehoge,hogehoge]のフォーマットになります
  • recursive (optional)
    • フォルダ以下の変更を再帰的に検知するか
      デフォルトはfalseなので、フォルダ以下全体を検知する場合はrecursive = trueを指定して送信する必要があります。

といったような感じになっています。
私の場合のcurlコマンドはこんなかんじ

curl -X POST -H "Authorization: bearer [アクセストークン]" https://www.wrike.com/api/v4/folders/[監視対象のFolderId]/webhooks?hookUrl=[GASで発行したwebhoolUrl]&recursive=true&events=[CommentAdded]

リクエストに成功すると、登録したwebhookの情報が返却されます

{
    "kind": "webhooks",
    "data": [
        {
            "id": "IEAD74YSHOGEHOGE",
            "accountId": "HOGEHOGE",
            "folderId": "監視対象のFolderId",
            "hookUrl": "GASで発行したwebhoolUrl",
            "events": [
                "CommentAdded"
            ],
            "recursive": true,
            "status": "Active"
        }
    ]
}

これでwrikeへのwebhookの登録は完了です。

GASで受け取ったwebhookを処理する

指定したFolderに変更が入ると、webhookUrlが呼び出されますが、webhookUrl側で適切な処理をする必要があります。

GASでのwrikeからのリクエスト受け取り

wrikeからのリクエストは、POSTの形式で送信されるため、GAS側もdoPost()のメソッドを定義して受け取る必要があります。

function doPost(e){
  // この関数で受け取る
  // 処理をお好みで
  // Eventに応じて中身が変わるので、eventTypeをチェックして、それぞれ処理を行うのが良さそう
 return HtmlService.createHtmlOutput('200') // この値をreturnしないとwebhookが自動停止される
}

受け取る際やGASスクリプトの更新の際は以下に注意してください

  • wrikeから送られてくるイベントはjson配列
    基本的にはイベントごとにwebhookが呼ばれますが、渡されるデータは配列型で渡されます。
    配列に対して処理を行う実装にしておかないと、データの取得に失敗したり取得漏れが発生したりします。
  • doPostの処理成功時はHtmlService.createHtmlOutput('200')を返却する
    GASのwebhook呼び出しに対するレスポンスはhttpレスポンス的には200で返却されますが、wrikeで期待している返却値はGAS的にはHtmlService.createHtmlOutput('200')です。
    これが返却されなかった場合、wrikeからwebhookUrlが3回呼び出された後webhookが停止されます。
    停止された場合、メールで停止された旨がwrikeから送られてくるので、webhookを再開したい場合はPUTリクエストを送信して手動で再開する必要があります。
    webhookの生死確認はGET https://www.wrike.com/api/v4/webhooksのリクエストで可能です。
    止まっていたら"status": "Suspended"になります

  • GASの更新を行なった場合は、新しいProject versionでの公開が必要
    GASのwebhookはProjectVersiondで管理されているため、スクリプトを更新しただけでは更新内容が呼び出されたWebhookに対して反映されません。
    webhookの処理に対して更新内容を適用したい場合は、Project versionを更新する必要があります。

これでGASでwrikeの更新を受け取って任意の処理を行うことができるようになりました!
データの加工などについては受け取ったイベントの情報からGET /folders/{folderId}/tasksなどを利用して必要な情報を揃えていくことになります。
こちらについてはまた別の機会に。

振り返り

WrikeはWebhookのエンドポイントに到達できず、中断されました。と、言われながらの試行錯誤でしたが、最終的にはwebhookを継続して利用できるようになりました。
外部APIが提供されているサービスだと自分好みに色々できて楽しいですね。