こんちにちは、ForSchool事業部の島田です。
今回はStudyplus for School(以下FS)のLINE連携について紹介させていただきます。
LINE連携とは?
LINEの「FS公式アカウント」と生徒の保護者が友だちになることで保護者と塾(講師)が連絡をとれたり、生徒(子供)の塾への入退室情報や勉強の状況を共有できる機能です。
LINE連携でできること
- 保護者が
- 塾とメッセージのやりとりが出来る
- 生徒の塾の入室・退室のお知らせを受信できる
- 塾が保護者へ
- 指導報告や面談報告を送信できる
- 生徒の学習記録を送信できる
LINE連携のフロー概要
LINEとのメッセージの送受信には、Messaging APIを使っています。
LINE連携でのメッセージをやりとりするフローの概要は以下のようになります。
- LINEと連携するためのステップ(最初の1度のみ)
- 保護者へのメッセージの送受信
- 保護者からのメッセージの送信
システム構成について
FSとLINEとのやりとりをする実装には AWS Lambda + API Gateway を利用しています。 外部に公開するURLはできるだけFSシステムと疎結合にしておき、LINEとのやりとりはLambdaに責任を持たせて、FSのシステムではなるべく関知しないようにしたいという意図があります。
Lambda関数について
Lambdaに2つの関数を実装しました。説明の便宜上/webhook
、/messages
と記載します。
/webhook
:LINEからのwebhookを受けるエンドポイント。LINE上でFS公式アカウントに対してイベントが起きたときにこのエンドポイントでPOSTリクエストを受けます。/messages
:FSからメッセージを送信する際に受けるエンドポイント。
関数の実装について
Lambdaは、FSがRuby on Railsを利用している観点から「Ruby 2.5」を利用しています。
LINE APIとのやりとりにはLINE Messaging API SDK for Rubyを利用しています。
以下は実装のイメージを掴んでいただくための概略したコードです。
それぞれpost_handler
がLambdaのハンドラー関数になります。
webhook.rb
require 'json' require 'line/bot' require 'net/https' require 'uri' # LINEにメッセージがあった場合にwebhookから呼び出される関数 def post_handler(event:, context:) signature = event["headers"].fetch("X-Line-Signature") body = event["body"] raise "LINEの署名が不正です" unless client.validate_signature(body, signature) 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_user_id = event["source"]["userId"] # 初めて連携をする場合にFSから発行した連携コードをメッセージしてもらう if line_code?(event.message["text"]) line_code = event.message["text"] # FS側に連携コードとLINE UserIDを渡して、FSの生徒と保護者のLINEを紐づける connect(line_code, line_user_id, reply_token: event["replyToken"]) else # LINEメッセージの受信。保護者から来たメッセージをFSに渡し塾が確認できるようにする message = event.message["text"] send_fs_message(message, line_user_id) end when Line::Bot::Event::Unfollow # FS公式アカウントをブロックした場合 disconnect(event["source"]["userId"]) when Line::Bot::Event::Postback # FlexMessageを利用して場合に利用 ... end end { statusCode: 200, body: JSON.generate('ok') } rescue => e puts e, e.backtrace { statusCode: 400, body: JSON.generate("Bad Request") } end def client @client ||= Line::Bot::Client.new do |config| config.channel_secret = LINE_CHANNEL_SECRET config.channel_token = LINE_CHANNEL_TOKEN end end def connect(line_code, line_user_id, reply_token:) res = post(URI.join(FS_URL, CONNECT_PATH), { code: line_code, line_user_id: line_user_id }) case res.code when "200" send_line_message("「 #{student_name}さん」と連携しました!", reply_token: reply_token) when "404" ... end end # FSにメッセージを送信 def send_fs_message(message, line_user_id) post(URI.join(FS_URL, MESSAGE_PATH), { line_user_id: line_user_id, message: message, }) end # LINEにメッセージを送信 def send_line_message(message, reply_token:) client.reply_message(reply_token, { type: "text", text: message }) end
messages.rb
require 'json' require 'line/bot' # FSからのメッセージ受けてをLINEへ送信する関数 def post_handler(event:, context:) body = JSON.parse(event["body"]) # メッセージとLINE UserIDを取得 message = body["message"] line_user_id = body["line_user_id"] # LINEにメッセージを送信 result = client.push_message(line_user_id, message) if result.all? { |res| res.code.start_with?('20') } { statusCode: 200, body: JSON.generate('success') } else response_body = result.map { |res| { code: res.code, body: res.body } } { statusCode: 400, body: JSON.generate(response_body) } end end def client # webhook.rb と同じ end
最後に
スタディプラスでは、前例がなくても要件を実現するためには新しいサービスやツールを積極的に取り入れています。
ForSchool事業部でLambdaを採用することは今回が初めてでしたが、大きな問題なく開発・運用ができています。
今後も外部との連携やシステムを疎結合にしていく際に、この事例を参考に必要なサービスを利用していこうと考えています。
LINEでのやりとりのキャプチャー