素人が2020年までの1ヶ月でLINE BOTに挑戦する毎日note. 【Day 17:開発環境を整える part 3】
こんにちは!
12月1日から2019年残り1ヶ月でスケジュール調整BOTの開発に挑戦している"くろ"です。
BOTの概要:Day 2の記事
BOTの仕様:機能一覧やフローチャート Day 10の記事
今日は、開発環境を整えるpart 3、BOTサーバの開発からスタートです。
今日で下記の記事内容は終わらせます。
では早速見ていきます。
ボットサーバとして使うサーバは、Node.jsとHerokuの準備で準備したHerokuのインスタンスを使用します。
これをボットサーバとして機能するように修正していきます。
必要なことは、LINE Developersからチャネルの開設してChannel Secretとアクセストークンを取得
Heroku上のREST APIをLINE BOTのWebhookに反応できるように修正
LINE DevelopersでREST APIのURLをWebhookとして設定
です。Webhookとは、LINEプラットフォームからボットサーバへ送信されるリクエストとそれに対するレスポンスをさします。ボットサーバのURLをWebhook URLとしてLINE Developersで設定することで、接続が可能となります。
LINE Developersからチャネルの開設してChannel Secretとアクセストークンを取得。
手順にしたがって、下記サイトから取得しておきました。
次は、Heroku上のREST APIをLINE BOTのWebhookに反応できるように修正です。
手順に従ってやってみると。
いきなりエラー。
どうやらexpressが無いって言われているようです。
確かにexpressまだこれには入れてなかったので、入れてみます。
いけました!!
Expressここで入れられて逆に良かったです。
そして、ここまでできました!
LINE DevelopersでWebhookを設定
できました!モザイクの中はherokuアプリケーションのURLです。
受信する内容
だんだんサイトに飛んで戻ってくるのが読者的にめんどくさそうだなとおもってきたので、引用してきます。
ここは読み物ですね。
メッセージが送られてきたり、友だち追加されるとwebhookとして上記のような配列と呼ばれる形のテキストが送られてきて、それには型があるので、そこをいい感じに抑えれば返信とか色々できるよってことだと思います。
返信する
Herokuの環境変数にトークン情報をセットする
環境変数の設定はクリア!
シークレットキーはdevelopersのここにあるやつですね。
チャネルアクセストークンも同じくdevelopersのここです。
次は署名を検証する
line-bot-sdkは問題なく入りました!
上段部分のconfig云々の所はこれですね。飛んできたwebhookが対象のBOTからのものなのか?を認証してくれるようです。
ちゃんとエラーメッセージが返ってくる所までできました!
※ちなみに、
また、heroku logsを実行すると、コンソールにpassが表示されていることが分かるはずです。
この記述の所がエラーになってのですが
» Error: Missing required flag:
» -a, --app APP app to run command against
» See more help with --help
こういうやつ。
heroku open --app herokuアプリケーション名ってやればいけました。
ただ、毎回やるのめんどくさすぎる、、、
さっと200番を返す
できた
応答メッセージを送る
const express = require("express");
const path = require("path");
const PORT = process.env.PORT || 5000;
const line = require("@line/bot-sdk");
const config = {
channelAccessToken: process.env.ACCESS_TOKEN,
channelSecret: process.env.SECRET_KEY
};
const client = new line.Client(config); // 追加
express()
.use(express.static(path.join(__dirname, "public")))
.set("views", path.join(__dirname, "views"))
.set("view engine", "ejs")
.get("/", (req, res) => res.render("pages/index"))
.get("/g/", (req, res) => res.json({ method: "こんにちは、getさん" }))
.post("/p/", (req, res) => res.json({ method: "こんにちは、postさん" }))
.post("/hook/", line.middleware(config), (req, res) => lineBot(req, res))
.listen(PORT, () => console.log(`Listening on ${PORT}`));
function lineBot(req, res) {
res.status(200).end();
// ここから追加
const events = req.body.events;
const promises = [];
for (let i = 0, l = events.length; i < l; i++) {
const ev = events[i];
promises.push(
echoman(ev)
);
}
Promise.all(promises).then(console.log("pass"));
}
// 追加
async function echoman(ev) {
const pro = await client.getProfile(ev.source.userId);
return client.replyMessage(ev.replyToken, {
type: "text",
text: `${pro.displayName}さん、今「${ev.message.text}」って言いました?`
})
}
解説していきます。大まかな流れとしては、
受信したbodyからeventを解析
client.getProfile()を使ってユーザー名を取得
client.replyMessage()を使って返事を送信
一通り終わったらログだけ出しておく
です。
受信したbodyからeventを解析
まずreq.bodyですが、すでにline.middlewareがパースしてくれているので普通に使えます。ありがたい。逆に、自前でbody-parser使ったりしてると注意が必要です。以下公式のmiddleware Usageより抜粋です。
You do not need to use body-parser to parse webhook events, as middleware() embeds body-parser and parses them to objects. Please keep in mind that it will not process requests without X-Line-Signature header. If you have a reason to use body-parser for other routes, please do not use it before the LINE middleware. body-parser parses the request body up and the LINE middleware cannot parse it afterwards.
bodyの内容は受信する内容で述べた通りです。
ここではclient.getProfile()で使うevent.source.userIdと、client.replyMessage()で使うevent.message.textを使います。
client.getProfile()を使ってユーザー名を取得
ユーザー情報を取得します。
LINEプラットフォームから非同期通信でデータを取得しています。その情報を後続の処理で利用するので、async/awaitを使って同期化します。
index.js(echoman()より抜粋)
const pro = await client.getProfile(ev.source.userId);
client.replyMessage()を使って返事を送信
ここでメッセージを返します。
先ほど取得したユーザー情報から名前と、ユーザーが送信したtextを返信bodyに詰め込んで返信を送ります。
client.replyMessageは非同期通信で、Promiseを返します。これをechoman()の呼び出し元で取得して、完了後の処理を行います。
index.js(echoman()より抜粋)
return client.replyMessage(ev.replyToken, {
type: "text",
text: `${pro.displayName}さん、今「${ev.message.text}」って言いました?`
})
一通り終わったらログだけ出しておく
最後に、処理の完了だけ検知してログを出しておきます。これはついでなので、別にやる必要はないですが。
echoman()で返却されるPromiseを配列に格納して、全部の完了をPromise.all()で検知し、then()の中でconsole.log()を呼び出してログを表示します。
Promise周りの仕様を確認したい方は、NDMをご参照ください。
さて、長くなりましたがここで本記事で作るものは完成しました。
index.js
const events = req.body.events;
const promises = [];
for (let i = 0, l = events.length; i < l; i++) {
const ev = events[i];
promises.push(
echoman(ev)
);
}
Promise.all(promises).then(console.log("pass"));
全部やってみます。
できました!!
これで、下記記事の内容は終わりです!お世話になりました。
明日以降は下記3つを進めていきます。
・DBスキーマの定義の続き。
・Expressやnode.jsの勉強を本格的に。
・BOTアプリケーションだけでなく、WEBアプリケーション(LIFF)も必要になるので、そこのチュートリアル的なものをしていく。
以上。
いつも読んでいただいている方ありがとうございます!!
この記事が参加している募集
よろしければサポートお願いします! 頂いたサポートはクリエイター活動に活用させて頂きます。