Edited at

1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest

last updated 2019/6/14


この資料について


  • この資料をハンズオンなどに活用してNode.js普及を促進させてもらえたら幸いです。


    • 使うときにコメント欄にコメント貰えると嬉しいです!

    • ハンズオン進めてみた感想などもコメント貰えると嬉しいです!



  • 会の流れとしてはハンズオン -> もくもく会 -> (可能な人は)もくもく会で作ったBOTを発表という流れです。



  • どこまでやるか


    • 手元で確認するだけであればSTEP3まででOK

    • ホスティングしてハンズオン後も使いたいならSTEP4まで



  • アップデート


    • 2018/3/14 ngrokのインストールをnpm経由に変更

    • 2018/8/28 本体のディベロッパー画面が更新されてるので変更

    • 2018/11/24 nowのバージョンアップに伴ってnow.jsonの記述を追加

    • 2019/5/14 LINE@アカウントのLINE公式アカウントへの統合に伴ったフロー変更などを適用、事例に市川市追加、nowのデプロイ方法の更新

    • 2019/6/11 疎通確認でエラーが出るのは問題ないですが、そこで接続できないと問い合わせが多いためserver.jsに疎通確認用のコードを追加。

    • 2019/6/14 nowをv2に対応

    • 2019/7/31 ngrokでのトンネリング箇所をserveoにも対応





はじめに


  • 対象者: Node.js初心者向け

  • 目的: LINE BOTを作ってNode.jsに触れる

  • ゴール目標: LINE BOTを作ってデプロイする

  • 性質上、Node.js以外の話の方が多いかも

  • 1Hしかないのでコード理解よりも動くものを

  • 早く終わった人はもくもくタイム



自己紹介



LINE BOT


  • LINE上で動作するBOT

  • 様々なプログラムと連携させることができる

  • LINE自体のユーザー数が多いことで、追加でアプリインストールがほぼ不要なことが利点

  • LINEがUIになるのでUIを考える手間が少なく、サーバーサイドエンジニア的に嬉しい



事例: みずほ、出前館



事例: ヤマト運輸



行政事例: 市川市

https://linecorp.com/ja/pr/news/ja/2019/2642



LINE Messaging API

LINE BOTを作るためのAPIです。


Messaging APIを利用することで、あなたのサービスをLINEのトークルーム上で提供することができます。

LINEユーザー一人一人に合わせたユーザー体験を提供できます。



スクリーンショット 2017-02-05 9.10.01.png



Push APIとReply API

スクリーンショット 2017-02-05 9.09.22.png

基本的にPushとReplyの二つのAPIがあります。

PushはBotアプリケーション側が起点となってユーザーにアクションします。

Replyはユーザーの発言を起点としてBotアプリケーションを呼び出します。



作ってみよう



1. Botアカウントを作成する

LINEのBotはTwitterなどと違い、通常のユーザーのアカウントをBot化することは出来ず、専用のアカウントを作る必要があります。



LINEディベロッパーサイトへログイン

まずはLINE developersのサイトにアクセスし、ログインしましょう。

スクリーンショット 2019-05-14 15.32.42.png

LINEアカウントでのログインを求められます。メールアドレスとパスワードもしくはQRコードでログインできます。ログインできない場合はLINEのスマートフォンアプリ側で設定を確認しましょう。


設定がまだの方はLINEのスマートフォンアプリ画面から 設定>アカウントでメールアドレスを設定できます。

LINEでメールアドレスを新規登録・確認・変更・登録解除(削除)する方法




プロバイダーの作成

ログインしたらプロバイダーの作成を行います。プロバイダーは自分が作るLINE BOTなどの開発者名やチーム名、企業名になります。初回だけディベロッパー登録で個人情報を聞かれると思うので回答してから進めましょう。


スクリーンショット 2019-05-14 15.38.42.png


新規プロバイダー作成ボタンを押して進み、プロバイダー名を入力して進めましょう。


スクリーンショット 2019-05-14 15.41.04.png




Messaging APIの新規チャンネルを作成

チャンネルを作成します。今回はLINE BOTを作るMessaging APIを選択します。


スクリーンショット 2019-05-14 15.42.03.png


Messaging APIの「チャンネル作成する」を選択しましょう。



BOTの情報入力

BOTの情報を入力していきます。


スクリーンショット 2019-05-14 15.48.52.png



  • アプリアイコン画像(任意): BOTのアイコンになる画像を選びましょう。

  • アプリ名(必須): BOTの名前を入力しましょう。LINEという文字列は使えなかった気がします。

  • アプリ説明(必須): BOTの説明を入力しましょう。取り急ぎは適当でも大丈夫。

  • 大業種/小業種(必須): BOTのカテゴリを選択します。取り急ぎは適当でも大丈夫。

  • メールアドレス(必須): BOTの開発者にLINE側からお知らせがあるときに受け取るメールアドレス。

  • プライバシーポリシーURL/サービス利用規約URL(任意):これも取り急ぎはなくても大丈夫です。


※昔はここでプラン設定(Developer Trial or FREE)をしていましたが、公式アカウントへの統合に伴って選択肢がなくなりました。



同意にチェックと確認して作成



同意にチェック/確認して作成





Botの設定確認

作ったBOTを選択しましょう。



こんな感じの基本設定画面になります。



ここで設定を変更していきます。

忘れがちなのがWebhook送信を「利用する」にするところです。

その他は以下の設定にしておくことをオススメします。


  • Webhook送信: 利用する

  • Botのグループトーク参加: 利用する

  • 自動応答メッセージ: 利用しない

  • 友達追加時あいさつ: 利用する


2019年4月以降はLINE公式アカウントマネージャーに遷移して設定する形になっています。




Botと友達になろう

画面下部にあるLINEアプリへのQRコードを確認します。



ここで表示されるQRコードを使って、自分が作成したBotアカウントと友達になりましょう。

ここからはスマートフォン画面のキャプチャになります。

QRコードリーダーを開きBotを友達追加しましょう。



「追加」を選択します。



「同意する」を選択します。



Botが友達に追加されました。





2. Node.jsでBot開発

ここからは手元のターミナルなどでの作業がメインになります。

Node.jsのインストールがまだの方は参考記事などをもとに準備をして下さい。




ちなみに、筆者の環境は以下になります。 (2019/5/14時点)


  • Node.js v12.2.0

  • npm v6.9.0

  • macOS Mojave 10.14



プロジェクトを作成とハローワールド

Node.jsのプロジェクトはpackage.jsonがあるディレクトリが起点となります。

まずはnpm initコマンドpackage.jsonを作成します。


$ mkdir mylinebot
$ cd mylinebot
$ npm init -y

Wrote to /Users/n0bisuke/dotstudio/2_events/20171125_nodefest/linebot/mylinebot/package.json:

{
"name": "mylinebot",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}


次に依存モジュールを追加します。 今回はこちらのSDKを利用します。


ちなみに以前は公式のNode.js SDKが無かったので依存なしでも書いてました。


$ npm i @line/bot-sdk express


次にプログラムのメインとなるserver.jsをmylinebotフォルダ内に作成します。


  • Macだとtouchコマンド

$ touch server.js


  • windowsだとnulコマンド(らしい)

$ type nul > server.js

コマンドじゃなくてもエディタの新規作成などで大丈夫です。

ディレクトリ内は現状こんな感じです。 (Windowsの人はlsが使えないのでdirを使いましょう)

$ ls

server.js node_modules package-lock.json package.json


エディタでserver.jsを編集します。

以下をコピー&ペーストしましょう。


server.js

'use strict';

const express = require('express');
const line = require('@line/bot-sdk');
const PORT = process.env.PORT || 3000;

const config = {
channelSecret: '作成したBOTのチャンネルシークレット',
channelAccessToken: '作成したBOTのチャンネルアクセストークン'
};

const app = express();

app.get('/', (req, res) => res.send('Hello LINE BOT!(GET)')); //ブラウザ確認用(無くても問題ない)
app.post('/webhook', line.middleware(config), (req, res) => {
console.log(req.body.events);

//ここのif分はdeveloper consoleの"接続確認"用なので削除して問題ないです。
if(req.body.events[0].replyToken === '00000000000000000000000000000000' && req.body.events[1].replyToken === 'ffffffffffffffffffffffffffffffff'){
res.send('Hello LINE BOT!(POST)');
console.log('疎通確認用');
return;
}

Promise
.all(req.body.events.map(handleEvent))
.then((result) => res.json(result));
});

const client = new line.Client(config);

function handleEvent(event) {
if (event.type !== 'message' || event.message.type !== 'text') {
return Promise.resolve(null);
}

return client.replyMessage(event.replyToken, {
type: 'text',
text: event.message.text //実際に返信の言葉を入れる箇所
});
}

app.listen(PORT);
console.log(`Server running at ${PORT}`);




Channel Secretとアクセストークンの確認

先ほどの「LINE developers」の画面でChannel SecretChannel Access Tokenを確認します。


  • Channel Secret確認


  • アクセストークン発行


server.jsのソースコードのchannelAccessTokenchannelSecretの部分に値を指定しましょう。

アプリケーションを起動してみます。

$ node server.js


起動すると以下がターミナルに表示されることを確認しましょう。

Server running at 3000

ここで問題なければブラウザでhttp://localhost:3000にアクセスすると`Hello LINE BOT!`と表示されると思います。



3. ngrokでトンネリング


LINE Botを作るためにはWebhookURLをLINE developersに登録する必要があります。


この際SSLが必須になるのですが証明書取得などの手間もありますし、PaaSなどにホスティングして試すのはデバッグが大変なので、手元のPCのlocalhostにグローバルからアクセスできるようにするトンネリングツールを利用しましょう。

などが有名です。今回はngrokを利用します。


まずはngrokのサイトにいき、本体をダウンロードして解凍します。


この辺の手順を更新しました。(2018/3/14)


npm経由でngrokをインストールできます。


https://www.npmjs.com/package/ngrok


$ npm i -g ngrok

次にトンネリングサーバーを起動します。 ngrok http ポート名と指定します。

今回はNode.jsアプリケーションを3000番ポートで利用するので3000を指定しましょう。

$ ngrok http 3000


ngrok by @inconshreveable                                    (Ctrl+C to quit)

Session Status online
Account n0bisuke (Plan: Free)
Version 2.1.18
Region United States (us)
Web Interface http://127.0.0.1:4040
Forwarding http://1148cbd9.ngrok.io -> localhost:3000
Forwarding https://1148cbd9.ngrok.io -> localhost:3000

Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00


起動すると表示されるhttps://で始まるアドレスを利用します。

この場合はhttps://1148cbd9.ngrok.ioです。このアドレスは起動の度に変わるため、ngrokは起動し続けて開発を行うことをおススメします。


以下のように、ngrokのプロセスとNode.jsアプリケーションのプロセスを並行して実行しての開発になります。



Webhook URLの更新

https://1148cbd9.ngrok.io/webhookがWebhook URLになります。

LINE developers画面のWebhook URLを更新します。

ここに先ほどのアドレスを指定しましょう。


この状態でBotに話しかけてみて下さい。

Botがおうむ返ししてくれます。


補足: serveoの利用 - ngrokのインストールがうまくいかない場合など

2019年7月頃、ngrokよりserveoがすごい。0秒で localhostを固定URLで公開

の記事がバズってました。

serveoでのやり方も紹介します。そのうちこの記事もngrokから差し替えるかもしれません。


ポリシー的にどうなん?みたいな会話もあるのでとりまこれくらいの追記で......笑


serveoはインストールなど不要です。利用したいドメイン名を指定してngrokを立ち上げるようにNode.jsのプロセスとは別タブや別ウィンドウを新規に立ち上げて以下を実行しましょう。

$ ssh -o ServerAliveInterval=60 -R <利用したいドメイン名>:80:localhost:<Node.jsなどのプログラムを立ち上げてるポート> serveo.net

例えばlocalhost:3000https://n0bisuke.serveo.netで利用したい。とかであれば以下のように実行します。

$ ssh -o ServerAliveInterval=60 -R n0bisuke:80:localhost:3000 serveo.net

Forwarding HTTP traffic from https://n0bisuke.serveo.net

Press g to start a GUI session and ctrl-c to quit.

>

あとは今回のプログラムだとhttps://n0bisuke.serveo.net/webhookをLINEの管理画面に設定すればOKです。



4. nowでデプロイ

nowって?




インストールと初期設定(初回のみ)

まずはコマンドをインストールします。

$ npm i -g now


nowコマンドを入力すると、初回だけメールアドレスの入力を求められます。

$ now

メールアドレスを入力して進みます。

> No existing credentials found. Please log in:

> Enter your email:

> No existing credentials found. Please log in:

> We sent an email to rsksound@gmail.com. Please follow the steps provided
inside it and make sure the security code matches Zealous Balinese.
⠸ Waiting for your confirmation

入力したアドレスに認証リンクが送られてきます。こんな雰囲気のメールです。



VERIFYボタンを押すとターミナルのメッセージが進行してログインできます。

✔ Email confirmed

> Ready! Authentication token and personal details saved in "~/.now"



デプロイ (v1)



  • package.jsonに"start"を追加


package.json




"scripts": {
"start": "node server.js",
"test": "echo \"Error: no test specified\" && exit 1"
},




  • package.jsonと同じ階層にnow.jsonを追加


now.json

{

"version": 1,
"name": "mylinebot"
}

mylinebotの箇所は任意の名前になります。


nowコマンドでデプロイします。

$ now

途中で[y|N]と聞かれるのでyをタイプすれば完了です。



Webhook URLの更新

先ほどの例の場合mylinebot-vqjnolsqqc.now.shにデプロイされています。

mylinebot-vqjnolsqqc.now.sh/webhookをWebhook URLに指定しましょう。

うまくいくと、この状態でLINE BOTにメッセージを送るとおうむ返しが動作します。

一旦ここまでで全体の流れは完了です。



version2への対応とnowでのアドレスの固定 (2019/6/14更新)

先ほどの内容だとnowの古いバージョン(v1)を使う形になります。

今はv2が推奨な様子なのでv2に対応していきましょう。

また、そのままnowコマンドのみでデプロイすると、毎回URLが変わってしまって管理画面のWebhook URLの設定を毎回し直す必要があり手間が大きいです。 アドレスを固定するやり方にもなります。


参考: https://zeit.co/docs/v2/deployments/routes/

参考: https://zeit.co/examples/express




  • now.jsonを更新

先ほど同様にmylinebotの箇所は任意のアルファベットで指定します。

生成されるURLが<name>.<ユーザー名>.now.shとなるのでURLに入れたい文字列にしましょう。


ちなみにaliasのキーに任意の名前を設定し、まだalias名が使われてなければ<alias>.now.shという短いURLも利用できます。



now.json

{

"version": 2,
"name": "mylinebot",
"builds": [{ "src": "server.js", "use": "@now/node" }],
"routes": [
{ "src": "/", "dest": "server.js" },
{ "src": "/webhook", "dest": "server.js" }
]
}

ここの指定の仕方が中々見つからなくて苦労しました。なるほどこう書けるんだなぁ。


指定の仕方はうちのスクールの学生さんから教えてもらいました。


ちなみにYoutubeにこの辺のすごく雑な解説動画をあげておきました笑



  • server.jsを更新


server.js




省略


//app.listen(PORT);
(process.env.NOW_REGION) ? module.exports = app : app.listen(PORT);
console.log(`Server running at ${PORT}`);

server.js最後の辺りのapp.listen(PORT)module.exports = appにすればOKなのですが、ローカル起動が出来なくなってしまうので、nowのサーバー上だと存在するprocess.env.NOW_REGIONの変数があるか無いかで切り替えをするようにしています。



  • デプロイ

$ now --target production

これでデプロイできます。

> WARN! You specified "--target production" but didn't configure a value for the `alias` configuration property.

> Deploying ~/mylinebot under n0bisuke
> Using project MyLINEBOT
> Synced 1 file (45B) [1s]
> https://mylinebot-crxwy0nqa.now.sh [v2] [1s]
┌ ** Ready [865ms]
├── server.js
├── package-lock.json
├── index.html
└── package.json
> Ready! Aliased to https://mylinebot.n0bisuke.now.sh [in clipboard] [7s]

こんな感じでhttps://mylinebot.n0bisuke.now.shにデプロイできました。以降は更新があったらnow --target production

を実行していけば更新が反映されます。最後にこのアドレスをLINE BOTの管理画面のWebhook URLの箇所に設定すればOKです。



補足資料


  • event.message.textがユーザーから送られてきた文字列


  • こんにちはとBOTに送るとこんばんわの時間ですよと言われて、それ以外だとうざと返されるプログラムが以下になります。

  • client.replyMessage()でBOTのリプライになります。


server.js



省略


function handleEvent(event) {
if (event.type !== 'message' || event.message.type !== 'text') {
return Promise.resolve(null);
}

let replyText = '';
if(event.message.text === 'こんにちは'){
replyText = 'こんばんわの時間ですよ';
}else{
replyText = 'うざ';
}

return client.replyMessage(event.replyToken, {
type: 'text',
text: replyText
});
}

省略





補足資料その2

npm i --save axios


server.js

'use strict';

const express = require('express');
const line = require('@line/bot-sdk');
const axios = require('axios');
const PORT = process.env.PORT || 3000;

const config = {
channelAccessToken: '',
channelSecret: ''
};

const app = express();

app.post('/webhook', line.middleware(config), (req, res) => {
console.log(req.body.events);
Promise
.all(req.body.events.map(handleEvent))
.then((result) => res.json(result));
});

const client = new line.Client(config);

function handleEvent(event) {
if (event.type !== 'message' || event.message.type !== 'text') {
return Promise.resolve(null);
}

let mes = ''
if(event.message.text === '天気教えて!'){
mes = 'ちょっとまってね'; //待ってねってメッセージだけ先に処理
getNodeVer(event.source.userId); //スクレイピング処理が終わったらプッシュメッセージ
}else{
mes = event.message.text;
}

return client.replyMessage(event.replyToken, {
type: 'text',
text: mes
});
}

const getNodeVer = async (userId) => {
const res = await axios.get('http://weather.livedoor.com/forecast/webservice/json/v1?city=400040');
const item = res.data;

await client.pushMessage(userId, {
type: 'text',
text: item.description.text,
});
}

app.listen(PORT);
console.log(`Server running at ${PORT}`);




補足資料その3

花粉ボットと実装サンプル



応用



応用回答例: Node.jsの最新を教えてくれるBOT 答え合わせ



  • Node.jsの最新バージョン教えて!と言われたらとりあえずちょっと待ってねとリプライメッセージ


  • https://nodejs.org/ja/ にスクレイピングしにいって、完了したらプッシュメッセージで教えてくれる

  • async/awaitでaxiosのHTTPリクエストとLINE MASSAGING APIへのリクエストを同期処理的に記述

axiosを追加インストール

npm i --save axios


server.js

'use strict';

const express = require('express');
const line = require('@line/bot-sdk');
const axios = require('axios');
const PORT = process.env.PORT || 3000;

const config = {
channelSecret: '',
channelAccessToken: ''
};

const app = express();

app.post('/webhook', line.middleware(config), (req, res) => {
console.log(req.body.events);
Promise
.all(req.body.events.map(handleEvent))
.then((result) => res.json(result));
});

const client = new line.Client(config);

function handleEvent(event) {
if (event.type !== 'message' || event.message.type !== 'text') {
return Promise.resolve(null);
}

let mes = ''
if(event.message.text === 'Node.jsの最新バージョン教えて!'){
mes = 'ちょっとまってね'; //待ってねってメッセージだけ先に処理
getNodeVer(event.source.userId); //スクレイピング処理が終わったらプッシュメッセージ
}else{
mes = event.message.text;
}

return client.replyMessage(event.replyToken, {
type: 'text',
text: mes
});
}

const getNodeVer = async (userId) => {
const res = await axios.get('https://nodejs.org/ja/');
const item = res.data;
const version = item.match(/最新版" data-version="(.*?)">/)[1]; //正規表現で(無理やり)取得
console.log(version);

await client.pushMessage(userId, {
type: 'text',
text: `今の最新は${version}だよ!`,
});
}

app.listen(PORT);
console.log(`Server running at ${PORT}`);




レポート: 参加者の方々が作ったBOTを紹介(ハンズオン後に追記)

もくもくタイムは20min程度でしたが、皆さんすごいです。


1. Node.jsの最新バージョン+ヤフー検索ができるBOT

応用課題で出していたNode.jsのバージョンを教えてくれる機能もLTSと最新版の両方に対応してくれました。

スクレイピングの勢いでヤフー検索まで繋いでいます。


2. 調べたい単語を入れるとWikipediaの検索結果を返してくれるBOT

これめっちゃ便利です。

Wikipediaまでわざわざ調べに行かなくても色々な言葉の概要を知ることができます。


3. URLを入れると話題のdev.toとどっちが速いかを教えてくれるBOT

話題ですね。


dev.toと阿部寛のホームページについてちゃんと計測させてくれ


dev.toと入力したサイトのどちらが早いか計測してくれます。

トレンドを捉えるアイディアの柔軟性がすごい。


4. 今日のご飯何にするかを絵文字で提案してくれるBOT!

ご飯何にしようか迷いますよね。

絵文字で推薦してくれるのでもう迷わない......!

コード指定すればNode.jsからも絵文字扱えるんだよっていう良い例だと思います。


5. 何でも人に聞く人にググらせるBOT

「調べる前になんでも人に聞く人を駆逐したい」らしいです笑

検索ワードを入れるとググれってことでGoogleに飛ばされます。

ハンズオンで触れていないリッチメニューまで活用してくれました。


6. Polymerと会話?できるBOT

Polymerが好きすぎてPolymerちゃんと会話できるBOTを作ったそうです笑


7.検索ワードを入れるとunsplash.comから画像を取得してくるBOT

画像検索も出て来ました。

画像扱えるとビジュアルが圧倒的に良くなりますね。



まとめと所感

Node.jsとNowを使うと爆速でLINE BOTを作れますし、細かいものを作るときにこの組み合わせはかなり使えます。 (デバッグの際はngrokがおすすめ)

応用してどんどん開発していきましょう。

見て回った限り、大半の人がデプロイまでたどり着くことができて、7人もオリジナルBOTを作って発表までできるのはさすがの学園祭的なレベルの高さを感じます。

時間内に終わらなかった人もこの記事を見直してチャレンジしてもらえたら幸いです。

参加してくださった皆さんありがとうございました!