LINE Messaging API を使用して、会話の「くっころ」という言葉に反応して「くっころ」してしまうBOTを作成する方法

# 始めに

Node.js の勉強のために、LINE Messaging API を使用したBOTを作成しました。
Qiitaには LINE BOT API についての記事は多かったのですが、LINE Messaging API についての記事は少なかったため、共有します。

# 作ったもの

LINEの会話の「くっころ」という言葉に反応して、「くっころ」してしまうBOTです。
1対1の会話と、トークルームでの会話に対応しています。
ソースは以下で公開しています。
https://github.com/k-nakayama-pg/kukkoro-bot

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/117949/cbf44c45-84b4-497b-c784-31b584fb246d.png)

# 作成方法

## 1.LINE Messaging API の登録

[Messaging APIのご紹介 | LINE Business Center](https://business.line.me/ja/services/bot) から登録できるので、必要な情報を入力して登録してください。

## 2.LINE@ MANAGER でWebhook送信を利用するに設定

登録が終わるとLINE@ MANAGER という画面に移ると思います。
ここで [アカウント設定]>[BOT設定]>[リクエスト設定]のWebhook送信を「利用する」にチェックを入れてください。
これを忘れると、後で設定するWebhook URLを設定してもリクエストがBOTに送信されません（実体験）

![キャプチャ2.PNG](https://qiita-image-store.s3.amazonaws.com/0/117949/031f25bb-939a-29a7-9cfe-5683200006f7.png)

## 3.LINE Developers でChannel SecretとChannel Access Tokenを確認

LINE@ MANAGERの[アカウント設定]>[BOT設定]>[ステータス]の「LINE Developersで設定する」というリンクからLINE Developersの画面に行きます。そこで、Messaging APIに必要な以下の2つの値を確認してください。
　- Channel Secret : リクエストがLINE Platformから送られてきたか署名検証する際に必要になります
　- Channel Access Token : Messaging APIの認証に必要になります

![キャプチャ3.PNG](https://qiita-image-store.s3.amazonaws.com/0/117949/b998b33e-b68f-fa22-8ddd-cd6a943c5d60.png)

![キャプチャ4.PNG](https://qiita-image-store.s3.amazonaws.com/0/117949/d7901435-7eb8-e4a5-e809-24bdbef0d715.png)

## 4.LINE Platformからリクエストを受け取って、Messaging APIに返事のテキストを送信するBOTの作成

以下がソースです。
[Nodejs+LINE BOTでレストラン検索 - Qiita](http://qiita.com/Enta/items/45d5295e023e24e9ff0b) を参考にして作成しました。
Messaging APIから受け取るレスポンスやリクエストの方法は、[LINE Developers API Document](https://devdocs.line.me/ja/) に詳しく説明されていたため、それを参考にしました。

```Javascript
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var request = require('request');
var crypto = require("crypto");
var async = require('async');

app.set('port', (process.env.PORT || 8000));
// JSONの送信を許可
app.use(bodyParser.urlencoded({
    extended: true
}));
// JSONのパースを楽に（受信時）
app.use(bodyParser.json());

app.post('/callback', function(req, res) {
    async.waterfall([
            function(callback) {
                // リクエストがLINE Platformから送られてきたか確認する
                if (!validate_signature(req.headers['x-line-signature'], req.body)) {
                    return;
                }
                // テキストが送られてきた場合のみ返事をする
                if ((req.body['events'][0]['type'] != 'message') || (req.body['events'][0]['message']['type'] != 'text')) {
                    return;
                }
                // 「くっころ」という単語がテキストに含まれている場合のみ返事をする
                if (req.body['events'][0]['message']['text'].indexOf('くっころ') == -1) {
                    return;
                }

                // 1対1のチャットの場合は相手のユーザ名で返事をする
                // グループチャットの場合はユーザ名が分からないので、「貴様ら」で返事をする
                if (req.body['events'][0]['source']['type'] == 'user') {
                    // ユーザIDでLINEのプロファイルを検索して、ユーザ名を取得する
                    var user_id = req.body['events'][0]['source']['userId'];
                    var get_profile_options = {
                        url: 'https://api.line.me/v2/bot/profile/' + user_id,
                        proxy: process.env.FIXIE_URL,
                        json: true,
                        headers: {
                            'Authorization': 'Bearer {' + process.env.LINE_CHANNEL_ACCESS_TOKEN + '}'
                        }
                    };
                    request.get(get_profile_options, function(error, response, body) {
                        if (!error && response.statusCode == 200) {
                            callback(body['displayName']);
                        }
                    });
                } else if ('room' == req.body['events'][0]['source']['type']) {
                    callback('貴様ら');
                }
            },
        ],
        function(displayName) {
            //ヘッダーを定義
            var headers = {
                'Content-Type': 'application/json',
                'Authorization': 'Bearer {' + process.env.LINE_CHANNEL_ACCESS_TOKEN + '}',
            };

            // 送信データ作成
            var data = {
                'replyToken': req.body['events'][0]['replyToken'],
                "messages": [{
                    "type": "text",
                    "text": displayName + 'にこんな辱めを受けるとは...！\nくっ...殺せ！'
                }]
            };

            //オプションを定義
            var options = {
                url: 'https://api.line.me/v2/bot/message/reply',
                proxy: process.env.FIXIE_URL,
                headers: headers,
                json: true,
                body: data
            };

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

app.listen(app.get('port'), function() {
    console.log('Node app is running');
});

// 署名検証
function validate_signature(signature, body) {
    return signature == crypto.createHmac('sha256', process.env.LINE_CHANNEL_SECRET).update(new Buffer(JSON.stringify(body), 'utf8')).digest('base64');
}
```

### 気をつけたところ

#### 1.リクエストがLINE Platformから送られてきたか確認
　
[LINE Developers API Document](https://devdocs.line.me/ja/) で以下のような記述がありました。

> X-Line-Signature Request Headerに入っているSignatureを検証することによって、
> リクエストがLINE Platformから送信されたものであることを確認する必要があります。
> 
> 検証は以下の手順で行います。
> 
> 1. Channel Secretを秘密鍵として、HMAC-SHA256アルゴリズムによりRequest Bodyのダイジェスト値を得る。
> 2. ダイジェスト値をBASE64エンコードした文字列が、Request Headerに付与されたSignatureと一致することを確認する。

検証には3.で確認したChannel Secretが必要になります。
ソース内の validate_signature(signature, body) メソッドが検証をしているメソッドになります。
[LINE Messaging APIでX-Line-Signatureの署名検証を行う - Qiita](http://qiita.com/yorifuji/items/71e31baf896adb69f567) を参考にしました。

#### 2.Messaging API にリクエストする時のパラメータ

Messaging APIは、それまでのBOT APIと違って、リクエスト時に必要なパラメータが違いました。
BOT APIの時に必要だったMIDはなくなりました。
Messaging APIには以下のパラメータが必要です。

 - Request Headers
  - Authorization : Bearer {Channel Access Token}（3.で確認したChannel Access Token）
 - Request Body
  - replyToken : Webhookで受信したreplyToken（webhookからのリクエストのbody内に入っています）

詳しくは[LINE Developers API Document](https://devdocs.line.me/ja/)を参考にしてください。

## 5.herokuにソースをデプロイ

herokuへのデプロイはたくさん記事があるのでここでは書きません。
Channel SecretとChannel Access Tokenを忘れずに環境変数に追加してください。


## 6.Webhook URLの設定

最後の設定です。デプロイしたソースのアクセスURLをWebhook URLに設定します。
LINE BOT の参加しているトークルームや友達から会話があると、ここに設定したURLにリクエストが送られるようになります。
LINE Developersから設定できます。

![キャプチャ5.PNG](https://qiita-image-store.s3.amazonaws.com/0/117949/fe24c28f-1122-a44a-c3e7-36b318a2f602.png)

## 7.動作確認

作成したLINE BOT を友達に追加して、話しかけることで確認できます。

![キャプチャ6.PNG](https://qiita-image-store.s3.amazonaws.com/0/117949/bc0d4660-94cf-5924-5a1b-798fb44fc148.png)

## まとめ

LINE Messaging APIはドキュメントが丁寧に書かれていたため、特につまづくことなく作成することができました。
特に[LINE Developers API Document](https://devdocs.line.me/ja/)には、APIの説明だけでなく、各言語別の実装サンプルコードまで書いてあったため、すごく助かりました。
皆さんも、LINE Messaging APIを使ってLINE BOTを作ってみてください。