読者です 読者をやめる 読者になる 読者になる

ホワイトプログラマー

40歳からSEを辞めてプログラマになりました

github→SlackへのWebhookを解析する

 背景

Javaを使って開発したSlack用のBotを運用している。
githubからメンションをすると特定のチャンネルに送信されるようになっているが、当社のSlackIDはgithubでは使用できないアンダースコアを採用しており、IDが不一致となるため、Slackではメンションとして有効にならない。

 対応

Githubからwebhookで送信される投稿を監視して、@Firsrtname-Lastnameの形式の文字列を @Firsrtname_Lastnameに書き換えて再投稿するBotを開発する。

監視して、再投稿すること自体は大した問題ではないが、最初にうまく投稿データが取得できずに困った。

 Githubから投稿されるjson

通常の投稿ではattachmentsは存在せず、オブジェクトのトップレベルの要素のtextに値が格納される。 しかし、Githubからポストされる値は、textが空欄なのである。 そこで、attachmentsキーに設定されているオブジェクト配列からデータを取得するように変更する。

{
    "attachments":[
        {
            "color":"C4E8B4",
            "mrkdwn_in":["text","pretext"],
            "pretext":"[aaa-bbb\/SandBox] New comment by ccc-ddd pull request<http:\/\/172.16.100.100\/aaa-bbb\/SandBox\/pull\/9#issuecomment-73|#9: hoge>",
            "text":"test @aaa-bbb",
            "id":1,
            "fallback":"[aaa-bbb\/SandBox] New comment by ccc-ddd pull request <http:\/\/172.16.100.100\/aaa-bbb\/SandBox\/pull\/9#issuecomment-73|#9: hoge>"
        }
        ],
    "subtype" :"bot_message",
    "source_team":"RRRTTTGG",
    "channel":"CWSADJ98K",
    "text":""
    ,"team":"T768HJUN",
    "type":"message",
    "user_team":"T768HJUN",
    "bot_id":"UJHDJK14",
    "ts":"1483007034.000140"
}

 変更後のjsonのパース部分のJavaソース

もともと、当該アプリではwssで取得したjsonのパースに org.json.JSONObjectライブラリを使用している。
attachementsオブジェクトは上記の通り、オブジェクト配列で回答されているが、このライブラリにはgetメソッドしか存在しない。
修正を始めた最初はどうやって、オブジェクト配列を取得するのか悩んだが、getメソッドをattachementsに対して実行するとJSONArray型を回答するということがわかった。
JSONArrayはArrayListなので、あとは取得したJSONArrayから内部のJSONObjectにアクセスし、textを取得することができた。  

念のため以下にソースを貼り付けておく

//bot(github)からのデータ取得
//attachmentsで取得するとJSONArrayが取得できる。その中にはJSONObejctが入っている。
//このJSONObjectからtextを取得するればよい。
JSONArray attachmentsArray = (JSONArray)obj.get("attachments");
JSONObject attachment = (JSONObject) attachmentsArray.get(0);      
//以下のtextはほかと異なり、Attachmentsの中のtextとなる
String text = (String) attachment.get("text");

この部分はパース前のjson次第で、上記ロジックがエラーになりかねないので業務でこのようなものを書く場合は、API仕様を決めて例外を許さないか、パースの際にチェックを行っておくことが大事かと思う。