LoginSignup
4

More than 5 years have passed since last update.

slackのincoming webhookからoutgoing webhookに移行するついでにサーバレス化したお話し

Posted at

slackのincoming webhookからoutgoing webhookに移行するついでにサーバレス化したお話し

背景

弊社のときふじが過去に「社WebをAWS s3 + cloudfrontなサーバーレス環境に移行した話」こんな知見を残していたことから、そろそろサーバレス化進めていくかと考えていました。

参考にしたURL

SlackからAWS API Gatewayを通してLambdaを起動するまで

Lambdaの使い方をローカルで試すのであればdocker-lambdaが早いです。
AWS Lambdaの開発環境を構築~docker-lambdaの紹介~

まずは概要図から

slackから特定の文字列を入力すると、outgoing webhookでAPI GatewayのURLにform-urlencodedで送信され、AWS Lambdaにjson形式でデータが渡り、関数を経由してjsonが返ってきます。返されたAPI Gatewayはそのままslackに送信してくるという仕様です。
※図の作成に使ったのはCacooです。

lambda-apigateway-slack.png

はじめにLambda関数を作成する

AWSコンソールから、はじめてAWS Lambdaにアクセスするとこんな画面がでてきます。「今すぐ始める」をクリックしましょう。

はじめだけ表示される画面

lambda_get_start.png

次に設計図の選択画面が出るので、ランタイムの選択やフィルターを駆使して目的の設計図(テンプレート)を探しましょう。最終的に「Blank Function」ばかりつかうことになるでしょう。

関数の作成を行うとはじめに表示される画面

lambda_get_template.png

フィルターのテキストボックスに「hello」と入力すると、「hello-world」が出てきます。こちらを使って入門編を進めても良いです。

lambda_set_filter.png

一度でも関数を作ったことがある場合は、AWS Lambdaの画面はここからになります。「Lambda関数の作成」ボタンからいつでも新しいLambda関数を作成することができます。

lambda_dashboard.png

設計図の選択で「次へ」ボタンを押すと、トリガーの設定画面に遷移します。ここで連携するAWSサービスを選びますが、今回はAPI Gateway側からLambda関数を選択するので、スキップしても構いません。

lambda_set_trigger.png

トリガーの設定画面からもAPI Gatewayを選ぶことができますが、今回はこのトリガーを使いません。

lambda_set_api_gateway.png

トリガーを設定してもしなくても「次へ」を押して関数をコーディングできる画面に遷移します。

lambda_set_iam.png

関数の設定画面

こちらで名前とランタイムを入力します。
名前は適当に「slackAPI」、ランタイムには「Node.js 6.10」を選択しました。

lambda_set_function.png

ランダムにテキストを返す関数のコード

そして、コードテキストエリアに、以下のコードを記述します。
res.usernameはslack上のbot名になります。
arrayにランダムに選択される文章をカンマ区切りで記述しています。

index.js
exports.handler = (event, context, callback) => {

    var res = {};
    res.username = "outgoing-webhook-from-lambda";
    var array = [
        'わからないことは<https://api.slack.com/custom-integrations|こちら>を参照してください。',
        'こんにちは、私は'+ res.username +'です。\nAWSのLambda functionで処理されています。\n',
        'API Gatewayを使ってLambda functionを起動する良い練習になりますね。',
        'outgoing-webhookを使用すればLambda functionをAPI Gateway経由でキックすることができます。'
    ];
    res.text = array[Math.floor(Math.random() * array.length)];

    callback(null, res);
};

Lambda 関数ハンドラおよびロールを設定する

関数の設定画面をもう少しスクロールすると、ハンドラとロールを設定する箇所が現れます。
ここでは、ハンドラは「index.handler」のままで、ロールに「テンプレートから新しいロールを作成」を選択、ロール名に任意のロール名を入力して、「次へ」ボタンをクリックします。

lambda_handler_role.png

作成した関数の確認画面が表示されるので、「関数の作成」ボタンをクリックします。

lambda_function_create.png

関数のテスト

関数のテスト画面が表示されるので、テストデータを準備して、テストを実行してもよいですが、ここでは省略します。

API Gatewayを作成する

api_gateway_menu.png

AWSコンソールのメニューからアプリケーションサービスにある「API Gateway」をクリックして、API GatewayのGetting Start画面を表示します。中央の「APIの作成」ボタンをクリックすると「新しいAPIの作成」画面に遷移します。

api_gateway_create.png

API名を入力して、「APIの作成」ボタンをクリックします。
すると、メソッドが空の状態のリソースが表示されます。

api_gateway_root.png

アクションから「リソースの作成」をクリックして、新しい子リソースの「リソース名」に任意の名前を入力します。※ここでは例として「start」を入力しています。

api_gateway_resource_create.png

次にアクションから「メソッドの作成」をクリックして、プルダウンから「POST」を選択してチェックマーク(レ点)をクリックします。

api_gateway_method_create.png

次にリージョンを選択します。(東京リージョンはap-northeast-1です)

api_gateway_region.png

そして、表示されるプルダウンから、作成済みのLambda関数名を入力して「保存」ボタンをクリックします。※Lambda関数名は途中まで入力すると補完されます。

api_gateway_function_select.png

権限を追加するか確認のダイアログが表示されるので、「OK」をクリックします。

api_gateway_function_kakunin.png

すると作成API Gatewayのメソッドの実行画面が表示されるので、「統合リクエスト」のリンクをクリックします。

api_gateway_function_setting.png

統合リクエストの設定画面が表示されるので、「本文マッピングテンプレート」をクリックして設定画面を表示させます。

api_gateway_request_setting.png

「+マッピングテンプレートの追加」リンクをクリックして、「application/json」と記入例が書かれたテキストボックスに「application/x-www-form-urlencoded」と入力してから、チェックマーク(レ点)をクリックします。

api_gateway_maping_template.png

「パススルー動作の変更」確認画面が表示されるので、「はい」をクリックします。

api_gateway_maping_template_confirm.png

コードエディタが表示されるので、以下のコードを記入して「保存」をクリックします。

api_gateway_maping_codeeditor.png

form-urlencoded形式をjson形式に変換するコード

このコードでは、「application/x-www-form-urlencoded」の時は json 型に変換するマッピングを定義しています。

mapping_template.txt
## convert HTML POST data or HTTP GET query string to JSON

## get the raw post data from the AWS built-in variable and give it a nicer name
#if ($context.httpMethod == "POST")
 #set($rawAPIData = $input.path('$'))
#elseif ($context.httpMethod == "GET")
 #set($rawAPIData = $input.params().querystring)
 #set($rawAPIData = $rawAPIData.toString())
 #set($rawAPIDataLength = $rawAPIData.length() - 1)
 #set($rawAPIData = $rawAPIData.substring(1, $rawAPIDataLength))
 #set($rawAPIData = $rawAPIData.replace(", ", "&"))
#else
 #set($rawAPIData = "")
#end

## first we get the number of "&" in the string, this tells us if there is more than one key value pair
#set($countAmpersands = $rawAPIData.length() - $rawAPIData.replace("&", "").length())

## if there are no "&" at all then we have only one key value pair.
## we append an ampersand to the string so that we can tokenise it the same way as multiple kv pairs.
## the "empty" kv pair to the right of the ampersand will be ignored anyway.
#if ($countAmpersands == 0)
 #set($rawPostData = $rawAPIData + "&")
#end

## now we tokenise using the ampersand(s)
#set($tokenisedAmpersand = $rawAPIData.split("&"))

## we set up a variable to hold the valid key value pairs
#set($tokenisedEquals = [])

## now we set up a loop to find the valid key value pairs, which must contain only one "="
#foreach( $kvPair in $tokenisedAmpersand )
 #set($countEquals = $kvPair.length() - $kvPair.replace("=", "").length())
 #if ($countEquals == 1)
  #set($kvTokenised = $kvPair.split("="))
  #if ($kvTokenised[0].length() > 0)
   ## we found a valid key value pair. add it to the list.
   #set($devNull = $tokenisedEquals.add($kvPair))
  #end
 #end
#end

## next we set up our loop inside the output structure "{" and "}"
{
#foreach( $kvPair in $tokenisedEquals )
  ## finally we output the JSON for this pair and append a comma if this isn't the last pair
  #set($kvTokenised = $kvPair.split("="))
 "$util.urlDecode($kvTokenised[0])" : #if($kvTokenised[1].length() > 0)"$util.urlDecode($kvTokenised[1])"#{else}""#end#if( $foreach.hasNext ),#end
#end
}

APIをデプロイしてURLを取得

保存したらアクションから「APIのデプロイ」をクリックします。

api_gateway_deploy.png

APIのデプロイを行うステージを入力する画面が表示されます。

api_gateway_deploy_stage1.png

「デプロイされるステージ」で「[新しいステージ]」を選択すると入力欄が増えます。

api_gateway_deploy_stage2.png

ここでは仮に「beta」と入力しました。※説明欄は任意入力です。

api_gateway_deploy_stage3.png

「デプロイ」ボタンをクリックするとAPIのデプロイが実行され、水色背景の箇所にURLが表示されます。これをslackの設定時に使用するのでメモしておきます。

api_gateway_deploy_fin.png

slackの設定

slackチームのapp or integrateから遷移するAPP Browse画面の検索ボックスに「outgoing」と入力して、「Outgoing Webhooks」を選択します。

slack_app_browse.png

表示されたOutgonig Webhooksの画面より、緑色の「Add Configuration」ボタンをクリックします。

slack_app_outgouing.png

次に「Add Outgoing Webhooks integration」ボタンをクリックして、詳細設定画面へ遷移します。

slack_app_outgouing_integration.png

「Outgoing Payload and Responses」の右側にある「Close」ボタンをクリックします。

slack_app_outgouing_setting3.png

「Outgoing Payload and Responses」の次の項の「Integration Settings」で、「Trigger Word(s)」にbotに反応してもらいたい文字列と「URL(s)」にAPI Gatewayでデプロイ後にメモしたURLを入力します。

slack_app_outgouing_integrate_url.png

例として「Trigger Word(s)」に「lambda」、「URL(s)」にメモしたURLを入力しました。入力したら、最下段の「Save Settings」ボタンをクリックします。

slack_app_outgouing_integrate_url2.png

試してみましょう!

lambda_apigateway_slack.png

できましたね!!

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4