はじめに
お仕事的にはインフラエンジニアですが、昨今の技術の進歩からインフラエンジニアいらないんじゃない的なことを感じたり感じなかったりなので、インフラエンジニアでもある程度コードかけないとまずいとは思ってるけど、じゃいざ何作るの?って段階になるとなかなかアイデアで出ない人は多いのではないのでしょうか。
そんな人は簡単なLINE Botを作ってみるとこから初めて見たらいかがでしょうか?という記事です。
環境
何かしらでBotサーバーを用意しなければなりません。
選択肢としては、GASやHerokuなどが思いつくと思いますが、普段私がAWSしかいじってないのでAPI Gateway + Lambda(Ruby)をserverless frameworkでデプロイします。
普段AWSをいじってる人はこの構成でやることを是非オススメします
手順
ここからはLINE Botが定型文を返すまでの手順となります
1. LINE@アカウントの取得
まずは以下のリンクからLINE@アカウント(一般アカウント)を取得する必要があります。
一般アカウントとは?
「一般アカウント」は審査なしで作成できるアカウントです。
一般アカウントの作成後に認証済みアカウントを申し込むことも可能です。
ご利用可能なプランはお住まいの国によって異なります。
2. チャネルの作成
LINE@アカウントを作成したらチャネルを作成する必要があります。
チャネルとは?
チャネルは、LINEプラットフォームが提供する機能を、プロバイダーが開発するサービスで利用するための通信路です。LINEプラットフォームを利用するには、チャネルを作成し、サービスをチャネルに関連付けます。チャネルを作成するには、名前、説明文、およびアイコン画像が必要です。チャネルを作成すると、固有のチャネルIDが識別用に発行されます。
チャネル作成の詳細な手順は以下の通りです。
2-1. LINEアカウントでLINE Developersコンソールにログイン
2-2. 開発者として登録する(初回ログイン時のみ)
2-3. 新規プロバイダーを作成する
2-4. チャネルの作成
このとき以下のどちらかのプランを選ぶ必要がありますが、お遊びの範囲であればDeveloper Trialを選択してください。
Developer Trial
MessagingAPIを利用したBotを試すプランです。友だちとメッセージの送受信を行うことができます。
※追加可能友だち数は50人に制限されています。また、Developer Trialからプランの切り替えやプレミアムIDの購入はできません。
フリー
MessagingAPIを利用したBotを開発するプランです。友だちの人数に制限はありませんが、Push messagesを利用してBotから友だちにメッセージを送信することはできません。
※サービス拡張に向けプラン変更が可能です。
3. Botの作成
BotはServerless Frameworkを使って、API gatewayとLambda(ruby)で作成してみます。
serverless frameworkがインストールされている前提で進みますが、インストールからという方は以下を参照してインストールしてください。
https://serverless.com/framework/docs/providers/aws/guide/installation/
3-1. serverlessコマンドでテンプレート作成
$ serverless create --template aws-ruby --path line-bot-test
3-2. serverless.ymlの編集
とりあえず最低限としてこんな感じにしておきます
service: line-bot-test # NOTE: update this with your service name
provider:
name: aws
runtime: ruby2.5
region: ap-northeast-1
memorySize: 512
timeout: 900
functions:
hello:
handler: handler.hello
events:
- http:
path: bot/hello
method: get
3-3. デプロイ
$ serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: WARNING: Function hello has timeout of 900 seconds, however, it's attached to API Gateway so it's automatically limited to 30 seconds.
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service line-bot-test.zip file to S3 (686 B)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
.......................
Serverless: Stack update finished...
Service Information
service: line-bot-test
stage: dev
region: ap-northeast-1
stack: line-bot-test-dev
resources: 11
api keys:
None
endpoints:
GET - https://xxxxxx/dev/bot/hello
functions:
hello: line-bot-test-dev-hello
layers:
None
とりあえずAPI GatewayとLambda関数がデプロイされました。
4. LINE Developersコンソールからボットを設定する
4-1. チャンネルアクセストークンを発行する
コンソール画面上はChannel Secretのことでコンソール上からこれを発行します。
チャネルアクセストークンとは?
チャネルアクセストークンは長期間有効なアクセストークンで、APIを呼び出すときにAuthorizationヘッダーに設定する必要があります。チャネルアクセストークンはいつでもコンソールで再発行できます。
4-2. Webhook URLを設定する
先ほど作ったAPI gatewayのURLをWebhook URLとして設定します。
Webhook URLとは?
Webhook URLはボットアプリケーションのサーバーのエンドポイントで、Webhookペイロードの送信先です。
コンソール上から接続確認をすると...
原因はAPI Gateway側のメソッドがGETになっていることでした...
よくよく考えたらPOSTですよね...
API Gateway側のメソッドをPOSTに直して再デプロイ
$ sls deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service line-bot-test.zip file to S3 (686 B)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
...................
Serverless: Stack update finished...
Service Information
service: line-bot-test
stage: dev
region: ap-northeast-1
stack: line-bot-test-dev
resources: 11
api keys:
None
endpoints:
POST - https://xxxxxxx/dev/bot/hello
functions:
hello: line-bot-test-dev-hello
layers:
None
再度、接続確認
今後はうまくいきました!!
これで一旦LINEからBotにメッセージを送ってみます
こんな感じで変なメッセージが返ってきちゃいます...
これはチャネル基本設定 > LINE@基本機能の利用 > 自動応答メッセージを利用しないにする必要があるそうです
自動応答メッセージを利用しないにしたので再度試してみます
とりあえず自動応答メッセージはなくなりました
5. Lambda関数の作成
Lambda関数がserverless createコマンドで作られたものままなのでちゃんと返信するようにしてきます
とりあえずLINEからどんなリクエストが来るかeventの中身を見てみます
{
"resource": "/bot/hello",
=================途中省略=================
"body": "{\"events\":[{\"type\":\"message\",\"replyToken\":\"7e36bf04b9104b26b11b0a2a7df2336c\",\"source\":{\"userId\":\"xxxxccccc\",\"type\":\"user\"},\"timestamp\":1555321188152,\"message\":{\"type\":\"text\",\"id\":\"9697231865658\",\"text\":\"つ\"}}],\"destination\":\"xxxxxxxx\"}",
"isBase64Encoded": false
}
肝心なのはbody部分のみです
bodyのみ抽出
{
"body": "{\"events\":[{\"type\":\"message\",\"replyToken\":\"7e36bf04b9104b26b11b0a2a7df2336c\",\"source\":{\"userId\":\"xxxxxxxx\",\"type\":\"user\"},\"timestamp\":1555321188152,\"message\":{\"type\":\"text\",\"id\":\"9697231865658\",\"text\":\"つ\"}}],\"destination\":\"xxxxxxx\"}"
}
メッセージイベントの詳細は以下にあります
https://developers.line.biz/ja/reference/messaging-api/#message-event
rubyなのでnet/httpで対応することも可能ですが、LINE公式のline-bot-sdk-rubyが存在することのでこちらを使ってみたいと思います。
def client
@client ||= Line::Bot::Client.new { |config|
config.channel_secret = ENV["LINE_CHANNEL_SECRET"]
config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
}
end
こんな感じでなんか簡単に作れそうなのでnet/httpでやるより良さそうです
でchannel_secretとchannel_tokenって??
channel_secretとは?
これはLINE Developersコンソールのチャネル基本設定 > 基本情報 > Channel Secret
から確認出来ます
channel_tokenとは?
これは2種類あるようです。
注:この方法では、30日間有効な短期のチャネルアクセストークンが発行されます。長期のチャネルアクセストークンを発行するには、コンソールにある[再発行]ボタンを使います。長期のアクセストークンは、アカウントの種類やプランによってはご利用いただけません。
長期的なものと短期的なものがあります。
短期的なものはLINE messageing APIにアクセスして発行してもらえます。
長期的なものはLINE Developersコンソールのチャネル基本設定 > メッセージ送受信設定 > アクセストークン(ロングターム)から発行することが出来ます。
channel_secretとchannel_tokenはLambdaの環境変数として設定したいのですが、serverless.ymlに書いちゃうとgithubのリポジトリに残ってしまうのでどうしましょ?
※githubのパブリックリポジトリを使ってる前提です
serverless.yml内で秘匿情報を扱う方法
serverless.yml内で環境変数を参照することが出来ます。
今回はこの方法でいきます。
https://serverless.com/framework/docs/providers/aws/guide/variables/#referencing-environment-variables
こんな感じで使えます。
service: new-service
provider: aws
functions:
hello:
name: ${env:FUNC_PREFIX}-hello
handler: handler.hello
Lambdaのrubyランタイムでgemを使う方法
色々方法はあるかと思いますが、serverless-ruby-packageというserverlessのプラグインを見つけたのでこれを利用したいと思います。
使い方はREADMEを読めば簡単です。
注意点はローカルのrubyのバージョンをLambdaに合わせて2.5.0にしておいてください。
もしくはdockerを使ってgemをインストールするのもありです。
むしろdockerを使ってgemをインストールすることをオススメします。
なぜrubyのバージョンを2.5.0にする必要があるかはvendor/bundle/bundler/setup.rbを見るとわかります
定型文を返すようにする
ほとんどLINE公式のline-bot-sdk-rubyのサンプルのままですが、以下のようなLambda関数で定型文が返ってくるようになりました
load "vendor/bundle/bundler/setup.rb"
require 'json'
require 'line/bot'
def hello(event:, context:)
message = {
type: 'text',
text: 'hello'
}
client = Line::Bot::Client.new { |config|
config.channel_secret = ENV["LINE_CHANNEL_SECRET"]
config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
}
body = event["body"]
requests = client.parse_events_from(body)
requests.each do |req|
case req
when Line::Bot::Event::Message
case req.type
when Line::Bot::Event::MessageType::Text
response = client.reply_message(req['replyToken'], message)
p response
end
end
end
end
LINEから試してみるとこんな感じです。
とりあえず定型文を返すとこまでいけました。
まとめ
インフラエンジニアだけどコードを書きたいということでしたが、serverless frameworkとの格闘がほとんどでした...
なのでここから役に立つBotとして進化させて、この続編として記事を書きたいと思います。