読者です 読者をやめる 読者になる 読者になる

年中アイス

いろいろつらつら

AWS API Gateway+LambdaでSlackにメッセージをPOSTする(中編)

前回、Slack Incoming Webhookの作成と、それを使うLambdaを作成したので、続いてAWS API GatewayとLambdaを繋いでいきます。書いていたら思ったより長くなったので、API Gatewayのテスト実行までを中編にして、後編で、API keyの設定とデプロイを行います。

Lambda自体は、サーバレス(正確にはインスタンス管理レス)で動きますが、呼び出しは他のAWSイベントをフックするものが多いです。それはそれでいいんですが、どうしてもAWSよりのコードが入るので、そこをWebAPIという形で、汎用的に扱えるようにします。

しかし、普通にWebAPIを用意しようとすると、サーバを準備して、nginx/apacheやプログラムを作って、Lambdaを呼び出すようにしなければならないため、API Gatewayを使って、サーバの運用なしで使えるWebAPIを作ります。

今回は1機能だけなので、直接/にJSON{"message":"hello world"}をPOSTしたら、Slackに投稿されるようにします。

AWS API GatewayとLambdaを繋ぐ

まずはAPI Gatewayで、WebAPIを作っていきます。AWS Consoleから、API Gatewayを開きます。

f:id:reiki4040:20170202221643p:plain:w400

[Create API]を選択するとフォームが出てくるので、名称を入れます。ここでは、post-slack(好きな名称で良いです)としておきます。

f:id:reiki4040:20170202221709p:plain

[Create API]で作成すると、post-slack APIのメニューが出てきます。Resourceを選び、そこで/を選択し、[Action] -> [create method]を選択し、

f:id:reiki4040:20170202221726p:plain

POSTを選択します。

f:id:reiki4040:20170202221732p:plain:w300

そうすると、Integrationを何にするか選択する画面が出てくるので、Lambdaを選択し、リージョンとLambda function名を入れます。入力を始めるとサジェストしてくれます。ap-northeast-1と前回作ったpost-slack-generalを選びます。 f:id:reiki4040:20170202221752p:plain

[Save]を押すと、API GatewayにLambdaの呼び出しを許可するかと求められるので[OK]にします。

f:id:reiki4040:20170202221933p:plain:w400

Client->Request->Integration->Responseのフローを表す、左右に縦長長方形、間に2x2 4つのマス目が表示されます。HTTPのリクエストをLambdaに渡す時の設定を行います。[Integration Request]を選択します。 f:id:reiki4040:20170202222019p:plain

下部のBody Mapping Templatesを開きます。Request body passthroughは、Neverにしておきます。これは定義したContent-Type以外は、HTTP status code 415でfailさせる扱いです。*1 f:id:reiki4040:20170202222101p:plain

今回は、JSONをPOSTしてくるので、+Add mapping templateを選択し、 f:id:reiki4040:20170202222130p:plain:w300

application/jsonを入力してチェックマークを選択します。(例として表示されてますが入力が必要です)

f:id:reiki4040:20170202222136p:plain:w300

application/jsonを選択すると、下部に入力欄が出てでくるので、以下を入力して[save]します。

{ "text": $input.json('$.message') }

f:id:reiki4040:20170202222155p:plain:w400

POSTされてきたJSONmessageというkeyの値を、textというkeyの値として置き換えるということをやっています。{"message":"hello"}{"text":"hello"}にしています。

Mappingが何に役立つかというと、Lambdaはtextで受け付けるように作ったけど、key名がいけてないなーと思っても、Lambdaには手を入れたくない(入れられない)という時に、WebAPIではmessageで受け取って、Lambdaに渡す時に変換できるということです。*2

とりあえずこれで動くので、API GatewayのTest機能を使って動かしてみます。 上部の<- Method Executionで、マス目の並ぶ画面に戻ります。

テスト実行する

左の[Test]雷マークみたいなのを選ぶと、テスト実行の画面になります。

f:id:reiki4040:20170202222349p:plain:w400

Request Bodyに{"text":"POST from API Gateway + Lambda"}を入れ、 [Test]を実行すると、横にレスポンス *3 やログが出てきます。 f:id:reiki4040:20170202222424p:plain

特に問題なければ、Slackにメッセージが出てきます。動かない時はログ見てください。 f:id:reiki4040:20170202224832p:plain

これでとりあえずWebAPIとしての動作はOKです。あとはデプロイすれば、実際に世界中から使えるようになります。

次回、API keyを使ってアクセスを制限して、デプロイして使えるようにします。

参考

*1:AWSのドキュメントみると、Request body passthroughのWhen no templateとNever何が違うんだろうという。

*2:リクエスト情報を一通り受けたい場合は、Lambda Proxy Integrationを使うと楽そうです。

*3:レスポンスが雑なメッセージですが、多分設定追加すれば{“response”:“ok”}とかぐらいにはできるはず・・・