今回のお題
LINEのMessagingAPIを触っていると、アクションイベントごとに処理を分けたくなり、今回の記事をかきました。どうしてもswitchで分けたり、ひとつのJSで処理をしてしまいがちですが、複数のModuleに切り分けることで少しでも処理の分散を行うことが出ればと思っております。
環境
今回は無料で使用することができるherokuのサーバーを使用して、
LINEの実装環境を紹介していきます。
https://jp.heroku.com/home
サーバーサイドの言語として、NodeJsを使って開発を行いたいと思います。
※herokuではDefaultでPHPやNodeJSなどの環境を簡単に構築できる様になっていますので、おすすめでございます。
以前までの私
switch ~ case
を使った方法でのアクションの実装を行っていました。
しかし、見てわかるようにコードが間延びしていき、すごく見づらくなってしまいました。
少しのアクションメソッドだけなら対応できますが、より多くのイベントを個別にとなってくるとコードが破綻しました。
app.post('/webhook', line.middleware(config), (req, res) => {
Promise
.all(req.body.events.map(eventHandler))
.then((result) => res.json(result))
.catch((err) => {
console.error(err)
res.status(500).end()
})
})
function eventHandler(event) {
let client = new line.Client(this.config)
...
switch(event.message) {
case "":
return client.replyMessage(token, {
type: "text",
text: replyText
})
break
}
...
}
ディレクトリ構成
破綻しないためにはどうすればいいか,悩みに悩んだ挙句ディレクトリごとに処理を切り分けたら切ではないかと思い、以下のようなディレクトリ構成を実装しました。
実際に動くアクションの部分を毎回作り替えることで一から書くプログラムの量も少なくなり、他との差別化が測れるのではないかと考えました。
├── message
│ ├── message.js
│ ├── text
│ ├── action
│ │ ├── action1
│ │ │ └── action1.js
│ ├── reply.json
│ └── text.js
├── postback
│ ├── action
│ │ └── template.js
│ └── postback.js
└── replyModule.js // message typeによる実行moduleの変更
index.js // webhookの受け取り
イベントタイプごとにディレクトリを区切り、そのイベントがあった際に受け取る窓口を各ディレクトリに用意しておく。
index.js
nodeでexpressを使ってwebhookを用意します。
オリジナルのReplyModule
を読み込み、そこでイベントタイプごとに実行するjsを変更するようにします。
const line = require('@line/bot-sdk')
const express = require('express')
/**
* オリジナルのリプライモジュールを読み込む
*/
const ReplyModule = require('./event/replyModule')
const app = express()
/**
* LINEのチャンネルアクセストークンとチャンネルシークレットを適用させる
*/
const config = {
channelAccessToken: process.env.CHANNEL_ACCESS_TOKEN,
channelSecret: process.env.CHANNEL_SECRET
}
app.post('/webhook', line.middleware(config), (req, res) => {
Promise
.all(req.body.events.map(eventHandler))
.then((result) => res.json(result))
.catch((err) => {
console.error(err)
res.status(500).end()
})
})
function eventHandler(event) {
let replyModule = new ReplyModule(event)
return replyModule.replyHandller()
}
## replyModule.js
イベントタイプごとに実行するModuleを切り替えます。
中身は単純に連想配列で実行する関数を切り替えているだけです。
switch文ではなく、LINEのイベントごとに実行する関数を切り替えることで、どのイベントで何をやるを明確に分けることができるので使いやすいのではないかとおもいます。
"use strict"
const line = require('@line/bot-sdk')
/**
* @constructor
*/
const ReplyModule = function(req)
{
this.event = req;
this.execFunc = {
...
"message": this.execMessage.bind(ReplyModule, this.event),
"follow": this.execFollow.bind(ReplyModule, this.event),
...
}
}
/**
* exec message function
* @return json
*/
ReplyModule.prototype.execMessage = (event) => {
// 別moduleにするもよし
let MessageModule = require('./message/message')
let messageModule = new MessageModule(event)
return messageModule.messageHandller()
}
/**
* exec follow function
* @return json
*/
ReplyModule.prototype.execFollow = (event) => {
// そのままリプライするもよし
let config = {
channelAccessToken: ...,
channelSecret: ...
}
let client = new line.Client(config)
return client.replyMessage(event.replyToken, {
type: "text",
text: "登録してくれてありがとう!"
}
}
/**
* @return json
*/
ReplyModule.prototype.replyHandller = function() {
let type = this.event.type
return this.execFunc[type]()
}
module.exports = ReplyModule;
あとは、message typeごとに切り分けたりすることでそれぞれのModuleを実行してくれるので,このイベントはこれ!のようにうまく分けられたりするのではないかと思います。
postbackイベントとtextイベントはそれぞれ似たような作りにできるかと思います。
おそらく言語解析系のサービスに接続されると思いますので、各サービスに合わせた形でtextModuleのようなものを作成し、
言語解析系のアクションごとに切り分ける方法も有用かと思います。
学び始めて日が浅いので拙いコーディングですが、誰かの参考になれば幸いです。