今回のお題
module化して一つ一つの処理を分けたい。
hello -> helloを返すmoduleにするような感じにしてメインのJsをすっきりさせたい。
環境
- heroku
- 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()})})functioneventHandler(event){letclient=newline.Client(this.config)...switch(event.message){case"":returnclient.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を変更するようにします。
constline=require('@line/bot-sdk')constexpress=require('express')/**
* オリジナルのリプライモジュールを読み込む
*/constReplyModule=require('./event/replyModule')constapp=express()/**
* LINEのチャンネルアクセストークンとチャンネルシークレットを適用させる
*/constconfig={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()})})functioneventHandler(event){letreplyModule=newReplyModule(event)returnreplyModule.replyHandller()}
replyModule.js
イベントタイプごとに実行するModuleを切り替えます。
中身は単純に連想配列で実行する関数を切り替えているだけです。
switch文ではなく、LINEのイベントごとに実行する関数を切り替えることで、どのイベントで何をやるを明確に分けることができるので使いやすいのではないかとおもいます。
"use strict"constline=require('@line/bot-sdk')/**
* @constructor
*/constReplyModule=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にするもよしletMessageModule=require('./message/message')letmessageModule=newMessageModule(event)returnmessageModule.messageHandller()}/**
* exec follow function
* @return json
*/ReplyModule.prototype.execFollow=(event)=>{// そのままリプライするもよしletconfig={channelAccessToken:...,channelSecret:...}letclient=newline.Client(config)returnclient.replyMessage(event.replyToken,{type:"text",text:"登録してくれてありがとう!"}}/**
* @return json
*/ReplyModule.prototype.replyHandller=function(){lettype=this.event.typereturnthis.execFunc[type]()}module.exports=ReplyModule;
あとは、message typeごとに切り分けたりすることでそれぞれのModuleを実行してくれるので,このイベントはこれ!のようにうまく分けられたりするのではないかと思います。
postbackイベントとtextイベントはそれぞれ似たような作りにできるかと思います。
おそらく言語解析系のサービスに接続されると思いますので、各サービスに合わせた形でtextModuleのようなものを作成し、
言語解析系のアクションごとに切り分ける方法も有用かと思います。
学び始めて日が浅いので拙いコーディングですが、誰かの参考になれば幸いです。