この記事はやや古くなっています。下記の新しいチュートリアルがベターです。
http://qiita.com/nkjm/items/38808bbc97d6927837cd
概要
この記事はLINEで動作する栄養士Botを開発するチュートリアルのPart3です。
前回までの記事はこちら。
- Part1 http://qiita.com/nkjm/items/0e9d24b2f3429bd33c8d
- Part2 http://qiita.com/nkjm/items/daa4e34b26ef937446c6
今回はLINEでBot本体のプログラムを開発していきます。
所要時間
60分
Bot本体を開発する
いよいよBot本体のプログラムを作っていきます。今回はNode.jsおよびExpressフレームワークを使ってこのプログラムを開発します。
まずプログラムを格納するディレクトリを作成します。今回はdietitianというディレクトリ名としています。
$ cd $HOME
$ mkdir dietitian
$ cd dietitian/
次にnpm initでpackage.jsonファイルを対話的に作成します。
$ npm init
name: (dietitian)
version: (1.0.0)
description: dietitian bot for LINE
entry point: (index.js)
test command:
git repository:
keywords:
author: Kazuki Nakajima
license: (ISC) MIT
{
"name": "dietitian",
"version": "1.0.0",
"description": "dietitian bot for LINE",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Kazuki Nakajima",
"license": "MIT"
}
Is this ok? (yes)
expressフレームワークをインストールします。
$ npm install --save express
// 出力省略
ではこのプログラムの核となるindex.jsファイルをまず下記の通り作成します。
// -----------------------------------------------------------------------------
// モジュールのインポート
var express = require('express');
var app = express();
// -----------------------------------------------------------------------------
// Webサーバー設定
var port = (process.env.PORT || 3000);
var server = app.listen(port, function() {
console.log('Node is running on port ' + port);
});
// -----------------------------------------------------------------------------
// ルーター設定
app.get('/', function(req, res, next){
res.send('Node is running on port ' + port);
});
これで一度アプリが起動するかテストします。
$ node index.js
Node is running on port 3000
上記の通りエラーが出ずに「Node is running on port 3000」のメッセージがでればOKです。
ブラウザで http://localhost:3000 にアクセスすると、同じメッセージが表示されるはずです。
プログラムをHerokuにデプロイする
Heroku CLIを使ってHerokuにログインします。
$ heroku login
Enter your Heroku credentials.
Email: あなたのEmail
Password (typing will be hidden):
Logged in as あなたのEmail
続けてHeroku CLIでHeroku上にアプリケーションを作成します。
$ heroku apps:create あなたのアプリ名
Creating ⬢ あなたのアプリ名... done
https://[あなたのアプリ名].herokuapp.com/ | https://git.heroku.com/あなたのアプリ名.git
Gitレポジトリを初期化します。
$ git init
Initialized empty Git repository in /Users/nkjm/dietitian/.git/
リモートレポジトリとしてHerokuを追加します。
$ git remote add heroku https://git.heroku.com/あなたのアプリ名.git
.gitignoreファイルを作成し、Gitの管理対象外にしたいファイルを一行一ファイルで列挙します。
.DS_Store
.gitignore
npm-debug.log
node_modules
Herokuにプログラムの起動方法を教えるための設定ファイル、Procfileを作成します。
web: node index.js
これまでに作成したコードをレポジトリにコミットします。
$ git add .
$ git commit -m "first commit"
Herokuへデプロイします。
$ git push heroku master
// 途中出力省略
remote: Verifying deploy.... done.
To https://git.heroku.com/dietitian-nkjm.git
* [new branch] master -> master
https://あなたのアプリ名.herokuapp.com にアクセスして先ほどと同じく「Node is running on port [ポート番号]」が表示されることを確認します。 *ポート番号は動的に割り当てられます。
これでプログラムを開発し、Herokuへデプロイするまでの流れが確認できました。
Webhookを設定する
WebhookはLINEでBotに関連するイベントが発生した場合に、そのイベントを現在開発しているプログラムに通知してもらうためのアクセスポイントです。
このURLは開発者が指定することができ、そのURLに対してLINEからPOSTリクエストが送信されることになります。今回は下記のURLをWebhookとして設定します。
LINE Developersにアクセスします。LINE DevelopersはまずLINE Business Centerにアクセスし、アカウントリストタブを選択、作成したビジネスアカウントの「LINE Developers」ボタンをクリックすることで遷移できます。
ここで画面下部の「EDIT」ボタンをクリックし、Webhook URLを下記の通り設定します。
これでLINE側の設定は完了です。つづけてBot本体に該当するコードを加えていきます。index.jsファイルを編集してルーター設定のセクションに下記のコードを追加します。
app.post('/webhook', function(req, res, next){
res.status(200).end();
console.log(req.body);
});
これでまたHerokuにコードをデプロイします。
$ git add . && git commit -m "added webhook" && git push heroku master
ログをリアルタイムで出力させます。
$ heroku logs --tail
この状態でスマホのLINEアプリからQRコードでBotを友達に追加します。
友達に追加したら、下記のようなログがHeroku上で出力されているはずです。これはLINEからHerokuで稼働しているNodeアプリに「友達追加イベント」の通知が届いたことを意味しています。
2016-11-28T06:35:42.578258+00:00 heroku[router]: at=info method=POST path="/webhook" host=あなたのアプリ名.herokuapp.com request_id=47b39641-54ea-4cc7-a86f-323b33c601d1 fwd="203.104.146.155" dyno=web.1 connect=1ms service=6ms status=200 bytes=117
2016-11-28T06:35:42.576932+00:00 app[web.1]: undefined
ログの最後に「undefied」となっていますが、これは本来先ほど追加したコードのconsole.log(req.body)が出力されるべき部分です。
これはPOSTリクエストのbody部分を出力させることを意図していますが、req.bodyオブジェクトはデフォルトでは存在していないのでundefinedとなっています。このreq.bodyオブジェクトからbodyデータにアクセスするためにはbody-parserモジュールを使用する必要があります。
下記のように追加でbody-parserモジュールをインストールします。
$ npm install body-parser --save
次にindex.jsを下記のように更新します。
// -----------------------------------------------------------------------------
// モジュールのインポート
var express = require('express');
var bodyParser = require('body-parser'); // 追加
var app = express();
// -----------------------------------------------------------------------------
// ミドルウェア設定
app.use(bodyParser.json()); // 追加
これでリクエストに含まれるbody部分のデータはreq.bodyとしてアクセス可能になりました。
Herokuに更新したコードをデプロイしてもう一度ログを確認してみます。
$ git add . && git commit -m "added body-parser" && git push heroku master
// 出力は省略
$ heroku logs --tail
もうBotは友達に追加されていると思いますので、今度はメッセージを送信してみます。(本来は同じイベントで差異をテストすべきですが、友達に追加・削除を繰り返すのは面倒なのでメッセージイベントでテストします)
2016-11-28T07:29:58.804025+00:00 heroku[router]: at=info method=POST path="/webhook" host=あなたのアプリ名.herokuapp.com request_id=27f54e62-3334-4d5d-8317-32482c7f4007 fwd="203.104.146.155" dyno=web.1 connect=0ms service=40ms status=200 bytes=117
2016-11-28T07:29:58.792131+00:00 app[web.1]: { events:
2016-11-28T07:29:58.792148+00:00 app[web.1]: [ { type: 'message',
2016-11-28T07:29:58.792150+00:00 app[web.1]: replyToken: 'f82d408e5a4c448889f9c301af97fdff',
2016-11-28T07:29:58.792150+00:00 app[web.1]: source: [Object],
2016-11-28T07:29:58.792152+00:00 app[web.1]: timestamp: 1480318198095,
2016-11-28T07:29:58.792153+00:00 app[web.1]: message: [Object] } ] }
今度はreq.bodyが出力されているのがわかります。
あとはイベントに応じてこのreq.bodyの中身を処理すれば、イベントのハンドリングが可能になります。
本来はここで署名検証の処理を入れるのですが、本チュートリアルでは割愛しています。
メッセージを受信する
先ほどまでのステップでメッセージの受信はほぼ完了しています。あとはreq.bodyからメッセージを抜き出すだけです。
index.jsのWebhookのルーター設定を下記のように修正します。
app.post('/webhook', function(req, res, next){
res.status(200).end();
for (var event of req.body.events){
if (event.type == 'message'){
console.log(event.message);
}
}
});
LINEからのイベント通知におけるデータは、eventオブジェクトの配列によって構成されています。したがってこのeventオブジェクトの配列をループ処理し、イベントタイプ(event.type)がmessageだった場合にそのメッセージ(event.message)を出力するようにしました。
このコードをHerokuにデプロイし、ログを見ながらBotに同じメッセージを送ってみます。
$ git add . && git commit -m "added body-parser" && git push heroku master
// 出力は省略
$ heroku logs --tail
すると下記のようにログが出力されるはずです。
2016-11-28T07:42:21.072770+00:00 app[web.1]: { type: 'text', id: '5270345585694', text: 'ハロー' }
これでメッセージを受信することができるようになりました。
ユーザーに返信してみる
LINEにAPIコールを発行するため、requestモジュールをインストールします。
$ npm install request --save
index.jsに下記2点の修正を加えます。
- requestモジュールをインポートする
- LINEへのAPIコールに必要なChannel Access Tokenを定数として設定する
- Webhookのルーター設定にLINE Messaging APIへのコールアウトを追加する。
まず1と2の変更です。
// -----------------------------------------------------------------------------
// 定数の設定
const LINE_CHANNEL_ACCESS_TOKEN = 'あなたのChannl Access Token'; // 追加
// -----------------------------------------------------------------------------
// モジュールのインポート
var express = require('express');
var bodyParser = require('body-parser');
var request = require('request'); // 追加
var app = express();
次に3の変更です。
app.post('/webhook', function(req, res, next){
res.status(200).end();
for (var event of req.body.events){
if (event.type == 'message' && event.message.text == 'ハロー'){
var headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + LINE_CHANNEL_ACCESS_TOKEN
}
var body = {
replyToken: event.replyToken,
messages: [{
type: 'text',
text: 'こんにちはー'
}]
}
var url = 'https://api.line.me/v2/bot/message/reply';
request({
url: url,
method: 'POST',
headers: headers,
body: body,
json: true
});
}
}
});
このコードをHerokuにデプロイし、Botに同じ「ハロー」というメッセージを送ってみます。
$ git add . && git commit -m "added reply" && git push heroku master
するとBotから「こんにちはー」と返信があるはずです。逆に「ハロー」以外のメッセージを送っても返信はありません。
まだまだ原始的な状態ですが、これでBotは受信したメッセージに応じて返信する能力を身につけました。
次のステップ
次回はBotがメッセージの中から食品を特定し、その栄養を取得する機能を追加していきます。