いまさらですが、LambdaとDynamoを触ってみたのでまとめておきたいと思います。
APIGateway/Lambda/Dynamoなど触ったことのない人の助けになれば幸いです。
- SlackのAppにメッセージを送信
- Slackのevent apiでAPI Gatewayのエンドポイントにリクエストを送る
- Lambdaで、飛んできたリクエスト内容をDynamoDBに保存
- Lambdaで登録した旨をSlackに返信
作成手順
以下の順序で作成を行います
- Lambda関数の作成
- API Gatewayでエンドポイントを作成
- Slackのevent APIの設定と、メッセージの送信
- CloudWatchでログを確認する
- Lambdaでのメッセージ処理
- LambdaからDynamoにデータを登録
1. Lambda関数の作成
Lambdaとは
AWS Lambda はサーバーレスコンピューティングサービスで、サーバーのプロビジョニングや管理、ワークロード対応のクラスタースケーリングロジックの作成、イベント統合の維持、ランタイムの管理を行わずにコードを実行できます。Lambda を使用すれば、実質どのようなタイプのアプリケーションやバックエンドサービスでも管理を必要とせずに実行できます。
凄く雑な説明をすれば、Lambda上にスクリプトを置いておくと、
こちらが指定したトリガー(HTTPリクエストなど)のタイミングでそのスクリプトを実行してくれます。
スクリプトを置いておくサーバーは意識する必要はなく、課金は実行回数によって発生します。
月100万リクエストまで無料なので、遊びで使う分には(多分)お金は発生しません。
関数の作成
AWSのマネジメントコンソールからLambdaを検索します。
「関数の作成」というボタンがあるはずなので、クリックして作成しましょう。
こういう画面になるので、関数名
とランタイム
の欄を入れて関数の作成をしましょう。
他に詳細設定などがありますが、今回は大枠を理解するだけなので、パスします。
関数のテスト
Test
というボタンがあるので、イベント名
に適当な名前を入れて作成
再度Test
ボタンを教えてみましょう。
画面に以下のようなテスト結果が出ればOKです!
2. API Gatewayでエンドポイントを作成
API Gatewayの設定
非常に簡素ですが、Lambdaの関数は作成できました。
次はLambda関数の実行を外からできるように、API Gatewayを設定します。
Lambdaの関数の画面から、デザイナ>トリガーを追加
をクリック
すると、トリガーを追加という画面がでてくるので、以下のように設定してください。
大枠を理解するため、また後で消すのでオープンにしていますが、そうでない場合はきちんと設定してください。
作成後にAPI Gateway
の項目にslack_sample_APIができていればOKです。
エンドポイントの作成
API Gatewayのリンクをクリックし、設定画面に行きます。
アクションからメソッドの作成を行います。
POSTを選択した後、以下のように選択して、保存します
作成後、再度アクション
ボタンからAPIのデプロイ
を実行します。
デプロイされるステージをdefault
を選択肢、デプロイします。
このようなURLが表示されていればエンドポイントの作成は完了です。
とりあえず、テストでcurlを叩いてみましょう!
以下のように返ってきたら成功です!!
curl -X POST https://それぞれのURL/default/slack_sample
=> {"statusCode":200,"body":"\"Hello from Lambda!\""}%
3. Slackのevent APIの設定と、メッセージの送信
Slackのアプリ作成
こちらからAppの作成
名前を適当に入れ、workspaceを設定します。
request urlと、Lambada関数の修正
サイドバーのBasic Information
から
Add features and functionality>Event Subscriptions
を選択してください。
requestを送るURLを求められるので、先程作成したエンドポイントのURLを入れましょう。
すると、以下のように怒られます。
どうやらchallenge
というパラメータを返す必要があるようです
Lambda関数のメソッドを、以下のように修正した後、Deploy
ボタンを押しましょう。
def lambda_handler(event:, context:)
# event["challenge"]がどこから来たかは、後述します
{ statusCode: 200, body: JSON.generate('Hello from Lambda!'), challenge: event["challenge"] }
end
デプロイ後にSlack画面のretry
ボタンを押すと、Request URL Verified と表示されるはずです
Subscribe to bot events
botの権限を設定します。
今回はBotへのメンションをトリガーにrequestを送信。Botぽくそれに返信をしたいので
app_mentions:read
とchat:write
を入れておきます
workspaceへのインストール
再び、Basic Information
に戻り、
今度はInstall your app
からworkspaceにアプリをインストールします
Slackでメッセージを送る
Bot的に使いたいので、適当なchannelにbotを入れて、
メンションをつけてメッセージを送ってみましょう
4. CloudWatchでログを確認する
実はLambda関数を作成したタイミングで
のロググループが出来ています。
AWSでCloudWatchを検索し、
サイドバーのログ>ロググループ
から/aws/lambda/slack_sample
を見てみましょう。
ログストリームの項目に、先程メンションを送った時間のものが増えていれば、
SlackからAPI Gatewayを介してLambda関数が実行出来ています!!
5. Lambdaでのメッセージ処理
Botぽく反応させたいのでSlackのスレッドに返信するようにしましょう。
とりあえず、メンション付きで「hoge」と送ったら、
「hogeと受信したよ!」とでも返すようにします。
Slackからのeventを見る
slackからのメッセージをLambda上で処理したいので、requestがどんな形か知りたいです。
lambda関数を以下のように修正して
def lambda_handler(event:, context:)
puts event
{ statusCode: 200, body: JSON.generate('Hello from Lambda!'), challenge: event["challenge"] }
end
デプロイしたあとに、
再度、slackでbotにメンション付きでメッセージを送りましょう。
CloudWatchのログに以下のようなものが出ていればOKです。
{
"token"=>"hoge",
"team_id"=>"foo",
"api_app_id"=>"fuga",
"event"=>{
"client_msg_id"=>"1234",
"type"=>"app_mention",
"text"=>"<@id> hoge",
"ts"=>"1614412451.000800",
~~~~~略~~~~
}
スレッドに返信する
Token
返信するためにSlackのTokenが必要です。
Slackアプリ画面のサイバーの
Features>OAuth&Permissions
からBot User OAuth Token
をメモしておきます。
コードの修正
Lambda関数を
と、先程のCloudWatchのログを参考に、以下のように書き換えます。
# サンプルなので、ここに書いていますが本当は適切に暗号化する必要があります
SLACK_TOKEN = "token"
def lambda_handler(event:, context:)
event_data = event["event"]
# メッセージにメンションがついてしまうため、送信されたテキストからIDを削除
text = event_data.dig("text").delete("<@id>")
channel = event_data.dig("channel")
params =
{
token: SLACK_TOKEN,
channel: channel,
as_user: true,
text: "#{text}と受信したよ!",
thread_ts: event_data["ts"]
}
uri = URI.parse("https://slack.com/api/chat.postMessage")
Net::HTTP.post_form(uri, params)
{ statusCode: 200, body: "test", challenge: event["challenge"] }
end
これで、Slack API → API Gateway → Lambda →Slackの流れができました!
7. LambdaからDynamoにデータを登録
最後に、なんとなくDynamoにSlackのメッセージを入れてみましょう!
Dynamoとは
KeyValue型のNoSQLです。集計などには向きませんが、1件のデータの登録、抽出に優れています。
テーブルの作成
Dynamoの画面からテーブルの作成
をクリック
テーブル名とプライマリーキーを入れます。
他の設定はデフォルトでOKです。
テーブルが作成できたら、項目の作成
から増やしてみます。
今回はtextを増やしてみました。
Lambdaの設定変更
このままだとLambdaからDynamoにまだアクセスできないのでポリシーを追加します
Lambda関数の画面のアクセス権限
のタブから実行ロール
のロール名をクリック
IAMの画面からポリシーをアタッチします。
自分しか使わないアカウントなのでFullAccessですが、本当は良くないです。
Lambda関数の修正
後は、
を参考に、
Lambda関数を以下のように修正します
require 'json'
require "net/http"
require 'aws-sdk-dynamodb'
SLACK_TOKEN = "token"
def lambda_handler(event:, context:)
event_data = event["event"]
# メッセージにメンションがついてしまうため、送信されたテキストからIDを削除
text = event_data.dig("text").delete("<@id>")
# Dynamoへのinput
dynamodb = Aws::DynamoDB::Client.new(region: 'ap-northeast-1')
item = {
text: text,
sender_id: event_data["user"],
}
params = {
table_name: 'dynamo_table_name',
item: item
}
dynamodb.put_item(params)
# slackへの送信
channel = event_data.dig("channel")
params =
{
token: SLACK_TOKEN,
channel: channel,
as_user: true,
text: "#{text}と受信したよ!",
thread_ts: event_data["ts"]
}
uri = URI.parse("https://slack.com/api/chat.postMessage")
Net::HTTP.post_form(uri, params)
{ statusCode: 200, body: "test", challenge: event["challenge"] }
end
ここまでうまく行っていれば、このように
Dynamoにレコードが登録され、
とりあえずしたかったことは出来たので、完了です。
最後に
やっぱり、インフラが分かって無くても、AWSがいい感じにしてくれるのはすごいですね。
工程も簡単で、この記事を書きながらしても3時間ぐらいで終わりました。
多分、作業だけすれば1時間ぐらいで終わると思います。
大枠を理解するために雑な紹介でしたが、
IAMの設定や、API Gatewayのアクセス制限、Lambda関数が失敗したときの処理など
本当はしないといけないことが、実はまだまだあります。
今回の記事で興味を持ってくれた人がいたら、ぜひやってみください。
「LambdaやDynamo全然わからないけど、なんか触ってみたい!」という人に役立てばば幸いです。