TwitterのAccount Activity APIとwebhookでDM自動応答Botを作成する


[前回](https://qiita.com/sbtseiji/items/7957de5db0987d9a6891)まででTwitterのAccount Activity APIおよびwebhookが使用可能になったので、DMに対して自動で返信するBotを作成してみます。あくまでもサンプルということで、ここでは「あいう」などとDMを受信したら「『あいう』は理解できません。」と、ほぼそのまま返信するBotを作成します。前回はwebhook受け取り先として[glitch](https://glitch.com)のWebアプリを登録したので、glitchでのスクリプトの例を示します。

# Botのスクリプト
webhookが使用できるようになるまでの手順が大変だったのに比べて、DMの送受信は拍子抜けするほど簡単です。webhookにはイベントに関するさまざまな情報がJSONで付加されてきますので、そこから必要な情報を取り出すだけです。ここでは、さまざまなイベントのうち（詳細は[公式ドキュメント](https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/guides/account-activity-data-objects)参照）、DMのイベント（`direct_message_events`）のみを処理しています。

なお、`client.js`や`index.html`などのファイルはwebhookの処理とは関係ないので初期状態のまま放置です。`package.json`の`dependencies:`に必要なパッケージを記載し（この例では`request`）、`.env`にコンシューマーキーなどの秘密情報を定義しておきます。下の例では、OAuth用の４つのキー（`CONSUMER_KEY`, `CONSUMER_SECRET`, `ACCESS_TOKEN`, `ACCESS_SECRET`）と、自分自身のtwitter ID（`MYSELF`）を定義しています。webhookでDMを受け取るだけなら認証は必要ありません。認証情報はDMの送信用です。

以下、`server.js`ファイルのサンプルです。


```javascript
// init project
var express = require('express');
var request = require('request');
const crypto = require('crypto');
var bodyParser = require('body-parser');

var app = express();

// OAuth1.0認証に必要なキーを.envから読み込んで設定
var twitter = {};
twitter.oauth = {
  consumer_key: process.env.CONSUMER_KEY,
  consumer_secret: process.env.CONSUMER_SECRET,
  token: process.env.ACCESS_TOKEN,
  token_secret: process.env.ACCESS_SECRET
}

app.use(express.static('public'));

// webhookの処理には関係ないので、ルートの処理は初期状態のまま放置
app.get("/", function (request, response) {
  response.sendFile(__dirname + '/views/index.html');
});

// TwitterのCRCテストにパスするための処理。作成したHMACをJSONで返す
// CRCテストはGETで行われる
app.get("/webhook", function (request,response) {
  var hmac = crypto.createHmac('sha256', process.env.CONSUMER_SECRET).update(request.query.crc_token).digest('base64');
  response.send('{"response_token":"sha256='+hmac+'"}');
});

// POSTされたデータをパースして使用する
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

// Twitterからのwebhookを受け取る
// webhookはPOSTで行われる
app.post("/webhook", function (request, response) {
  response.setHeader('Content-Type', 'text/plain');

  // webhookされたイベントがDMの送受信の場合だけ処理する
  if (request.body.direct_message_events) {
  	// DMの送信者のIDを取得
    var sender = request.body.direct_message_events[0].message_create.sender_id;
	// DMのメッセージ本文を取得
    var message_txt = request.body.direct_message_events[0].message_create.message_data.text;
    
    // 送信者が自分自身でない場合のみ自動返信
    // 自分のユーザーIDは.envで「MYSELF」として定義済
    if (sender !=process.env.MYSELF){
        autoReply(sender, '「'+ message_txt +'」は理解できません。');
      }
  }
  response.sendStatus(200);  
});

// listen for requests :)　← この部分も初期状態のまま
var listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});

// 自動応答
function autoReply(userid, message){
  // まずはDM返信用のオブジェクトを作成
  var message_obj =new Object();
    message_obj = {
      "event": {
        "type": "message_create",
        "message_create": {
          "target": {
            "recipient_id":userid
          },
          "message_data": {
            "text": message
          }
        }
      }
    } 

  // DMをPOSTするための認証情報その他を設定
  var request_options = {
    url: 'https://api.twitter.com/1.1/direct_messages/events/new.json',
    oauth: twitter.oauth,
    json: true,
    headers: {
      'content-type': 'application/json'
    },
    body: message_obj
  }
  // POSTで送信
  request.post(request_options, function (error, response, body) {
  })
}
```