はじめに
今回は通勤時間を有効活用することができる、通勤時にQiitaのトレンド記事が届くLINE Botを開発しながらRailsと外部APIの連携、LINE Messaging API SDKの使い方、LINE Flex Messageの使い方を学んでいきます。
チュートリアル形式で実際にLINE Botの開発をしながら開発方法を解説していきます。
この記事の対象者
- LINE Bot開発に入門したい人
- Railsと外部APIの連携手法を学びたい人
- 個人開発でLINE Botを作ってみたい人
目標成果物
LINE側から「出勤なう」と送られてきたタイミングでQiitaのトレンド記事上位5つを返すLINE Bot。
LINE Botについて
LINE Botとは
LINE BotとはLINE上のメッセージの返答を自動化できるチャットボットです。
チャットボットとはユーザーからのメッセージに、自動で返答するプログラムです。
LINE Botを使うことで、ユーザーに対してカスタマーサポート、商品のクーポン送付、予約機能など様々なアプローチを行うことができますなどをすることができます。
【LINE Botでできること】
- ユーザーからのメッセージに対して自動返信
- 返答の出しわけ
- 選択肢の提示
- クーポンの発行や利用
- Webサイトへの誘導
今回の開発ではユーザーへメッセージを自動送信する機能を開発します。
LINE Botの仕組み
LINE BotはLINEが提供するMessaging APIを利用して開発をすることができます。
このMessaging APIはLINE Developersコンソールという開発者向けの管理上で作成することができるチャネルを通信経路として利用する。
ユーザーがLINE Botに対してメッセージを送信してから返信が返ってくる流れは以下のように表すことができます。
① ユーザーがスマホアプリでメッセージを送信
② 送信されたメッセージはチャネルを経由しLINEプラットフォームへいきRailsアプリへ
③ Railsアプリで受信したメッセージを解析
④ Railsはユーザーへ送信したいメッセージのリクエストをLINEプラットフォームへ
⑤ LINEプラットフォームからユーザーのスマホへメッセージが送信される
簡単なオーム返しアプリを作ってみる
まずは公式ドキュメントの手順に沿って簡易的なオーム返しアプリを開発していきます。
Messaging API のチャネルの作成
まずはじめに先ほど紹介したメッセージの経由を行うチャネルをLINE Developersコンソールを利用して作成していきます。
下記の公式サイトにまずはアクセスします。
まず初めに、自分の使っているLINEアカウントを用いてログインします。
はじめての人はここからLINE Developersに新規のアカウントを登録してください。
登録が完了したらサイドバーよりProvidersを選択しcreateをクリックしてください。
登録が完了すると、作成したプロバイダーが表示されています。
下記より新規チャンネルを作成します。
作成画面に行ったら上から下記の入力を行います。
- チャンネルタイプ - Messaging API
- プロバイダー - 先ほど登録した名前
- 会社または所有の国 - Japan
- チャンネルアイコン - 任意の画像
- チャンネル名 - 任意の名前
- チャンネルの説明 - 任意の説明
- カテゴリー - Webサービス
- サブカテゴリー - Webサービス
登録が完了したら下記のような画面が表示されます。
Messaging APIのタブに切り替えるとQRコードが出てくるのでそこからLINE Botを自分のLINE上で登録することができます(まだ何も動きません)
これでチャネルの作成はできたので、次にRailsアプリ側の準備をして行きます
LINE Messaging API SDKの準備
Railsの環境構築
該当のディレクトリ内で以下のコマンドを実行しRailsアプリを作成します。
rails new . --api
なおRubyおよびRailsの環境構築はできているものとして先に進めます。まだの方は各自環境構築を済ませてください。
LINE Messaging API SDK for Rubyのインストール
次に先程の図の下記の部分を行うためのgem
をインストールします。
LINE Messaging API SDKを利用することで簡単にLINE Botの開発をすることができます。
今回はRuby用に用意されているLINE Messaging API SDK for Rubyを利用します。
gemファイルに下記の記述を行います。
gem 'line-bot-api'
記述ができたら下記のコマンドでインストールを実行します。
bundle install
ルーティングの設定
次にLINEプラットフォームらか送信されるリクエストをRails側で受信できるように設定します。
Rails.application.routes.draw do
post 'callback' => 'line_bot#callback'
end
コントローラーの設定
次にルーターと紐付けられるための処理をコントローラーを作成します。
rails g controller LineBot
下記のファイルが作られます。
app/controllers/line_bot_controller.rb
下記の値を入力します
class LineBotController < ApplicationController
def callback
end
end
これでRails側の準備も完了したので、LINEから送信されたメッセージを受け取る準備を進めて行きます。
ngrokの利用
次にngrokを利用してローカルで作成したアプリを一時的に外部に公開できるように設定します。
Homebrew
でngrok
をインストールします。
brew install ngrok
インストールしたら下記のコマンドでバージョンが出て来れば完了です。
ngrok --version
次にngrokのサイトに行ってアカウントを登録します。
登録が完了したらサイドメニューのYour Authtoken
よりトークンを取得します。
下記のコマンドを実行してPCとngrokアカウントを連携します。
ngrok authtoken 作成したトークン
これでngrokの準備が完了したので実行をして行きます。
下記のコマンドでローカル環境を立ち上げます。
rails s
その上で下記のコマンドを実行しngrok
を実行します。
自分はポート番号が3000なので3000で設定しました。
ngrok http 3000
実行後に表示されているURLが外部からアクセスできるURLになります。
Forwarding https://xxxx -> http://localhost:3000
最初はアクセスをしてもエラーが表示されます。
こちらのエラーはRailsで設定されているサイバー攻撃対策の影響で出てしまっているので設定を変更します。
Rails側のセキュリティー設定
Railsで標準のセキュリティー設定がされているので、セキュリティー対策を無効にする設定を行います。
Railsのセキュリティーについての詳しい内容は公式ドキュメントを参考にしてください。
今回は結論コードだけを記載します。
Rails.application.configure do
# 省略
config.hosts.clear
end
以上でLINEプラットフォームからのPOSTリクエストのRailsで受け取れるようになったので連携を進めて行きます
LINEのチャネルとRailsの連携
次にRailsアプリとLINEチャネルの連携をしメッセージのやりとりをおこなえるように設定します。
LINEのチャネルでトークンを取得
チャネル作成時に発行されるチャネルシークレットとチャネルアクセストークンを取得しRailsアプリと連携をしていきます。
LINE Developersを開き先ほど作成プロバイダーページを確認します。
タブをBasic settingsに切り替えて下の方にスクロールします。
下までスクロールするとChannel secretとAssertion Signing Keyという項目があるので値を確認します。
次にタブをMessaging APIに切り替え下までスクロールさせます。
するとチャネルのアクセストークンを発行する箇所があるのでトークンの発行を行います。
これでチャネルシークレットとチャネルアクセストークンの準備が完了したのでRails側で値を設定していきます。
Railsの設定
Rails側の環境変数に先ほど取得したアクセストークンを設定します。
まずが環境変数を管理するためのgemを入れていきます。
gem 'dotenv-rails'
bundle install
環境変数を定義するファイルを作成
touch .env
先ほど発行したシークレットとトークンを入れます。
LINE_CHANNEL_SECRET='xxxxxxxx'
LINE_CHANNEL_TOKEN='xxxxxxxx'
LINE Messaging API SDKの準備
LINE Messaging API SDK
ではLINE Botの処理を行うためのLine::Bot::Clien
というクラスがあらかじめ用意されているので、このクラスをインスタンス化し、メッセージの解析と返信機能を作成していきます。
記述法についてはこちらを参考に書いてきます。
class LineBotController < ApplicationController
def callback
end
private
def client
@client ||= Line::Bot::Client.new { |config|
config.channel_secret = ENV["LINE_CHANNEL_SECRET"]
config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
}
end
end
この記述によってLine::Bot::Client
クラスがインスタンス化できました。
LINEチャネルにRailsアプリを登録する
環境変数を元にRails側におけるチャネルとの連携は完了したので、次にチャネル側でRailsアプリを連携させていきます。
タブをMessaging APIに変えてWebhook URLに先ほどngrokで取得したURLを入れます。
Use WebhookもONに設定します。
※ なおngrokから取得できるURLは有効期限があるので、ngrokを起動する度にURLの更新をする必要があります。
最後にLINE Botにメッセージを送った際に返信されるオートメッセージを無くす設定をします。
遷移先で下記のように設定をします。
これで準備は完了したのでユーザーが送信したメッセージをそのまま返すオーム返し機能を実装していきます。
LINEからRailsに送られてくるメッセージを確認する
Rails側のコントローラにコードを追加し、LINEから送信されたメッセージをRails側で確認できるようにします。
class LineBotController < ApplicationController
def callback
puts "======="
puts body = request.body.read
puts "======="
end
private
def client
@client ||= Line::Bot::Client.new { |config|
config.channel_secret = ENV["LINE_CHANNEL_SECRET"]
config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
}
end
end
この記述を書いた上でLINEでメッセージを送信してみます。
するとコマンドライン上で下記のようにメッセージを取得できていることを確認できます。
次に実際にLINEから届いたメッセージをそのまま返信するような実装をしていきます。
callbackメソットをGitHubを参考に下記のように書き換えます。
def callback
body = request.body.read
events = client.parse_events_from(body)
end
-
parse_events_from
で引数にbodyを入れることでevents配列を取得できます
実際にevents
配列の中は下記のようなデータが入ってきています。(messageの部分のみ表示)
"{
"events":
[
{
// 省略
"message":
{
"type":"text",
"id":"xxxxxxxxx",
"text":"Hello world"
}
}
],
}"
events
は配列なのでeach
メソットを利用しmessage["text"]
を取得しLINEから送信されてきたメッセージを取得します。
def callback
body = request.body.read
events = client.parse_events_from(body)
events.each do |event|
case event
when Line::Bot::Event::Message
case event.type
when Line::Bot::Event::MessageType::Text
message = {
type: "text",
text: event.message["text"]
}
client.reply_message(event['replyToken'], message)
end
end
end
end
コードを詳しく解説していきます。
まず下記のコードでループされているevent
がLine::Bot::Event::Message
クラスであるかのチェックをしています。
events = client.parse_events_from(body)
events.each do |event|
case event
when Line::Bot::Event::Message
case event.type
when Line::Bot::Event::MessageType::Text
こちらの処理でLINEから受けととったイベントがメッセージイベントかをチェックしています。
なお、メッセージイベント以外については公式ドキュメントに掲載されているので確認してみてください。
次に実際にメッセージだった場合に受信したtextの値をmessage
というハッシュに格納します。
また応答トークンを利用して返信機能を付与しています。
case event.type
when Line::Bot::Event::MessageType::Text
message = {
type: "text",
text: event.message["text"]
}
client.reply_message(event['replyToken'], message)
end
応答トークンの処理については下記を参考にしてみてください。
実際でLINEでメッセージを送信するとデータが返ってきていることを確認できます。
目標物の開発
ここまででLINE Bot開発の基礎を学んできました。
ここからは今回の目標物である「通勤時にQiitaのトレンド記事が届くLINE Bot」の開発を進めていきます。
機能としては下記のようになっています。
- LINE Botに対して「出勤なう」というメッセージを送るとトレンド記事が届く
なおQiitaのトレンド記事はQiita公式APIでは取得できないので、非公式で作られているQiitaトレンドAPIを利用します。
実装方針
目標物は下記の手順で実装していきます
- RailsからLINEへ複数メッセージが送れるように設定
- RailsでQiitaのトレンドAPIを叩いてレスポンスデータを取得
- 「出勤なう」というメッセージが来たタイミングでLINEへレスポンスを返す
さっそく実装の方を進めていきます。
RailsからLINEへ複数メッセージが送れるように設定
まずはRailsからLINEへ複数メッセージを送る記述法を確認します。
先ほど実装していたclient.reply_message
の記述において第二引数で渡すメッセージを配列のオブジェクト形式にすることで複数のメッセージをLINEへ送信することができます。
message = [{type: "text", text: "メッセージ1"}, {type: "text", text: 'メッセージ2'}]
client.reply_message(event['replyToken'], message)
LINEが確認するとメッセージが2つ受信されていることを確認できます。
つまりQiitaトレンドAPIを叩いてトレンド記事のURLを取得し、ハッシュとして格納することで複数のトレンド記事のURLを作成します。
RailsでQiitaのトレンドAPIを叩いてレスポンスデータを取得
次にQiitaトレンドAPIを叩いてURLを取得しLINEアプリへ送信するデータを作成します。
目標の形は下記のようになります。
message = [{type: "text", text: "トレンドURL1"}, {type: "text", text: 'トレンドURL2'}]
client.reply_message(event['replyToken'], message)
Net::HTTP.get_response
を利用してQiitaトレンドAPIを叩いてデータを取得します。
下記の記述を追加しLINEのメッセージが送信されたタイミングでQiitaトレンドAPIからデータが取得されているかを出力してみます。
when Line::Bot::Event::MessageType::Text
uri = URI('https://qiita-api.vercel.app/api/trend')
res = Net::HTTP.get_response(uri)
puts res.body if res.is_a?(Net::HTTPSuccess) # 出力の確認
message = [
{type: "text", text: "メッセージ1"}, {type: "text", text: 'メッセージ2'}
]
client.reply_message(event['replyToken'], message)
end
ターミナルを確認するとQiitaのトレンドAPIのデータが表示されていることを確認できます。
この中からlinkの値だけを取り出します。試しにレスポンスデータの1番目の値のトレンド記事URLを取得します。
uri = URI('https://qiita-api.vercel.app/api/trend')
response = Net::HTTP.get_response(uri)
response = JSON.parse(response.body)
puts "==========="
p response[0]["node"]["linkUrl"] // # 出力
puts "==========="
実際にループしてLINEに返すメッセージを作成します。
uri = URI('https://qiita-api.vercel.app/api/trend')
response = Net::HTTP.get_response(uri)
response = JSON.parse(response.body)
# LINEへ返すレスポンス
message = []
# トレンド上位5記事のみ抽出
5.times {|i|
hash = {}
hash[:type] = "text"
hash[:text] = response[i]["node"]["linkUrl"]
message.push(hash)
}
client.reply_message(event['replyToken'], message)
-
message = []
でLINEに返すデータの初期値を準備しています -
5.times
トレンドの上位5記事を取得するため5回ループさせます -
hash[:text] = response[i]["node"]["linkUrl"]
でトレンドi位のULRを取得 -
message.push(hash)
で取得したデータを配列に追加
実際に確認するとデータが返ってきています。
「出勤なう」というメッセージが来たタイミングでLINEへレスポンスを返す
最後にLINE側から「出勤なう」という文言が送られてきた場合のみレスポンスを返すように条件分岐を付与します。
def callback
body = request.body.read
events = client.parse_events_from(body)
events.each do |event|
case event
when Line::Bot::Event::Message
case event.type
when Line::Bot::Event::MessageType::Text
# ユーザーからのメッセージが「出勤なう」だった場合のみにメッセージを返す
if event.message["text"] == "出勤なう"
uri = URI('https://qiita-api.vercel.app/api/trend')
response = Net::HTTP.get_response(uri)
response = JSON.parse(response.body)
# LINEへ返すレスポンス
message = []
# トレンド上位5記事のみ抽出
5.times {|i|
hash = {}
hash[:type] = "text"
hash[:text] = response[i]["node"]["linkUrl"]
message.push(hash)
}
client.reply_message(event['replyToken'], message)
end
end
end
end
end
実際に挙動を確認してみましょう。
データが返ってきました。
以上で目標物が完成しました。
最後に
いかがだったでしょうか。今回はチュートリアル形式でLINE Botの開発をしました。
今回は返信メッセージにスタイルを当てていないのでそのままURLが表示される形式なっていますが、Flex Message
を利用することでこの辺もカスタマイズできそうなので挑戦したいと思います。
加えて時間設定で自動で出勤時間にメッセージが届く挙動にできるようにアップデート等も加えていけたらなと思っています。
この辺ができた上で一般には公開する予定です。(現状だと公開するのが恥ずかしい笑)
ぜひこの記事を参考にLINE Bot開発や個人開発に挑戦していただけたらなと思います。
他にもいろいろ記事を書いているので読んでいただけると嬉しいです。