JavaScript
Node.js
Chatwork
ChatOps

速報! ChatworkAPIでメッセージ取得が出来るようになったので、メッセージに反応するBOT使ってみました。

More than 3 years have passed since last update.

やっと来ましたね! 嬉しさと勢いで記事書きますw


2014年11月27日 待望のメッセージ一覧の取得用のエンドポイントが実装されました

割と長い道のりでしたね笑

twitterなどではこんな感じで切望の声がありました笑

中の人は頑張ってたんでしょうね :)

http://developer.chatwork.com/ja/changelogs.html

今まではメッセージの取得APIが無かったのでHubot+SlackでよくあるBotにリプライを送ると返信してくれるみたいなことが出来なかったんですけど、これでやっとそういった実装も出来そうです。


さっそく使ってみます。

http://developer.chatwork.com/ja/endpoint_rooms.html#GET-rooms-room_id-messages


サンプルリクエスト

とりあえずリクエストを送ってみます。

curl -X GET -H "X-ChatWorkToken: 自分のAPIトークン" "https://api.chatwork.com/v1/rooms/{room_id}/messages?force=0"

いい感じに返って来てくれました。


Node.jsから呼び出してみます。

前に書いた記事(Chatworkの定期連絡を自動化!Chatwork APIを使って業務効率化してみた。)を参考に書いてみます。

とりあえずGETするだけなのでシンプルなコードですね。


cw.js

var request = require('request');

var room_id = '取得するルームのID';

var options = {
url: 'https://api.chatwork.com/v1/rooms/'+room_id+'/messages?force=1',
headers: {
'X-ChatWorkToken': 'APIキー'
},
json: true
};

request.get(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
}else{
console.log('error: '+ response.statusCode);
}
});


実行してみる。

$ npm i request

$ node cw

node cw
[ { message_id: 455021086,
account:
{ account_id: 933649,
name: '菅原 のびすけ',
avatar_image_url: 'https://tky-chat-work-appdata.s3.amazonaws.com/avatar/381/381489.rsz.png' },
body: '[info][title][dtext:chatroom_groupchat_created][/title][dtext:chatroom_chatname_is]マシュマロ王国[dtext:chatroom_set]\n\n[dtext:chatroom_member_is][piconname:768003],[piconname:933649],[piconname:1090960][dtext:chatroom_added][/info]',
send_time: 1415621317,
update_time: 0 },
{ message_id: 455021936,
account:
{ account_id: 1090960,
name: '中村 大騎(まろC)',
avatar_image_url: 'https://tky-chat-work-appdata.s3.amazonaws.com/avatar/509/509281.rsz.jpg' },
body: '外部向けにあなただけのカメラアプリ講座を開いてみたい',
send_time: 1415621378,
update_time: 1415621476 },
{ message_id: 455023372,
account:
{ account_id: 933649,
name: '菅原 のびすけ',




おおお。取得出来ましたね!


データを少しみてみる

このメッセージやり取りのjsonデータはこんな感じです↓

{ message_id: 472495511,

account:
{ account_id: 768003,
name: '榎本 麗',
avatar_image_url: 'https://tky-chat-work-appdata.s3.amazonaws.com/avatar/563/563430.rsz.jpg' },
body: 'hoge hoge,',
send_time: 1417109200,
update_time: 0 },
{ message_id: 472495614,
account:
{ account_id: 768003,
name: '榎本 麗',
avatar_image_url: 'https://tky-chat-work-appdata.s3.amazonaws.com/avatar/563/563430.rsz.jpg' },
body: '[To:933649] 菅原 のびすけさん\n\nのびすけさん\nリスと表示を横並びにするcssがうまく反映されないのですが何故でしょう…',
send_time: 1417109244,
update_time: 0 },
{ message_id: 472495664,
account:
{ account_id: 933649,
name: '菅原 のびすけ',
avatar_image_url: 'https://tky-chat-work-appdata.s3.amazonaws.com/avatar/381/381489.rsz.png' },
body: 'リス',
send_time: 1417109271,
update_time: 0 },
{ message_id: 4724956

個人的な感想ですけど、 誰か宛の投稿[To:xxxx]の場合を識別するフラグがあると嬉しいですね。


せっかくなのでカンタンなオウム返しBOTを作ってみた

chatworkのメッセージを監視する必要があるので5秒に一回チェックする感じにしてみます。

APIの利用制限は現時点で5分あたり100回までらしいので5秒1回くらいな大丈夫かな。

http://developer.chatwork.com/ja/endpoints.html


force=0で差分を取得出来ます。

messageのAPIはリクエストパラメータのforceの値を0にすれば差分だけ取れます。

1だと最新100件らしいです。


まずは監視部分を作ります


cw.js

var request = require('request');

var room_id = '取得するルームのID';

var options = {
url: 'https://api.chatwork.com/v1/rooms/'+room_id+'/messages?force=0', //forceの値を変更
headers: {
'X-ChatWorkToken': 'APIキー'
},
json: true
};

function getMes(cb){
request.get(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
cb(body);
}else{
console.log('error: '+ response.statusCode);
cb(false);
}
});
}

//5秒に一回実行
setInterval(function(){
getMes(function(data){
if(!data)return;
console.log('check:',data);
});
},5000);


実行してみます。

$ node cw

error: 204
error: 204
check: [ { message_id: 472495344,
account:
{ account_id: 933649,
name: '菅原 のびすけ',
avatar_image_url: 'https://tky-chat-work-appdata.s3.amazonaws.com/avatar/381/381489.rsz.png' },
body: 'てすと',
send_time: 1417109111,
update_time: 0 } ]

未読のメッセージが無いときは error: 204を返しますが、メッセージを投稿するとメッセージを取得してくれます。


投稿部分を追加で実装してみます。


自分宛かどうか

例えば[To:1138752] LIG子(ligco)さん\nこんばんわ'このメッセージだと

data.bodyのテキストを見て自分(BOT)宛かどうかを判定する必要がありそうだったので、[To:xxxxxxxx]の部分で判定しようとしましたが、特定のメッセージに対する返信だと[rp aid=1138752 to=25970759-472498006]といった形になり複雑そうだったので〇〇さんという部分を利用しました。


まとめるとこんな感じです。

※急いで書いたので割と雑(コールバック多いとか抽象化してないとか)ですがお許し下さい

オウム返しにしようと思ったんですけど、分かり易いように文字列反転くらいしようと思ったので文字列反転をして返しています笑


cw.js

var request = require('request');

var room_id = '取得するルームのID';
var options = {
headers: {
'X-ChatWorkToken': 'APIキー'
},
from: [],
json: true
};

function getMes(cb){
options.url = 'https://api.chatwork.com/v1/rooms/'+room_id+'/messages?force=0';
request.get(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
cb(body);
}else{
console.log('error: '+ response.statusCode);
cb(false);
}
});
}

function postMes(message, cb){
options.url = 'https://api.chatwork.com/v1/rooms/'+room_id+'/messages';
options.form = { body: message };
request.post(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
cb(body);
}else{
console.log('error: '+ response.statusCode);
cb(false);
}
});
}

//var TO = '[To:1138752]';
var TO = 'LIG子(ligco)さん'; //名前の部分の方が使えるかも

setInterval(function(){
//メッセージ取得
getMes(function(data){
if(!data)return;
console.log('check:',data);

//未読メッセージ分繰り返し
for(var i = 0, len = data.length; i < len; i++){
//BOTのアカウント宛の場合処理をする
if(data[i].body.indexOf(TO) != -1){

var tmp = data[i].body.split(TO);
var mes = tmp[1]; //[To:xxxx]の部分以外の本文
mes = mes.split("").reverse().join(""); //本文反転
//メッセージ投稿
postMes(mes, function(data){
if(!data)return;
console.log(data);
});
}
}
});
},5000);


実行するとこんな感じです。

まだまだ改良すべき点はありますが、とりあえずそれっぽいものが出来ました。

最近はSlackでChatOpsが人気ですが、ChatWorkでも同じ様なことが出来そうですね。

今後APIの改良に期待ですね :)

それでは。