NTTドコモ様_dカーシェア
NTTドコモ様_dカーシェア
2018.11.09

【面倒は】API Gateway + Lambda + CloudWatch LogsでPOSTされたデータのログを残す【いやだ】

まさくに

「あぁー」

仕事していると、考えなきゃならないことっていっぱいありますよね。

「あぁー、コールバックをするAPIを作ったけど、そのテストだとか検収作業のためにコールバックの受け口が必要で、できれば手間なくコストあんまりかけることなく、ただただ単純にWebのアクセスログとPOSTされたデータだけを見られるような、そんな一時的な仕組みが割とすぐ欲しいー」みたいなのを考えなきゃならないことが。僕にはよくあります。

こんにちは。バックエンドエンジニアのまさくにです。何も考えたくない。

さて、このような必要が生じたとき、どのような手段を取ればよいのでしょうか。僕が教えて欲しいくらいなのですが、いろんな方法が考えられると思います。Webサーバーが一台あってPHPなんかが動いていれば楽勝ですね。でもこんなちょっとした役割のためのサーバーが見つからない。

じゃあHerokuとかNetlifyとかでどうにかならなんかなーって考えたんですけど、リポジトリ一個用意してデプロイー? 永続データどーすっかなーって考えるとちょっと面倒な気もする。じゃあログかーCloudWatch Logsかなー、Lambdaかなー、というのが以下の方法です。いきましょう。

全体像

簡単ですね。

今回はAPIのコールバックを受けるような用途を想定しているので、どっかからAPI GatewayがPOSTで叩かれ、Lambdaが起動され、CloudWatch LogsにPOSTデータが載るようなものを考えています。認証などは設けないので、秘匿データの扱いにはご注意ください。

Lambda部分

まずLambdaでPOSTデータをCloudWatch Logsに書き出すスクリプトを書いておきます。LambdaはデフォルトでCloudWatch Logsにログを書き出すようになっているので、IAM設定する必要はありません。(自動で作ってくれます)下記のようにLambdaを作ります。

この条件で作成し、あとはFunctionを書いておきます。今回はNode.js 8.1.0を選んでいるので下記のように。eventの中の body-json にPOSTデータが入ってくるのですが、これは後で設定します。それにしてもconsole.logでCloudWatch Logsに入れてくれるのはとても楽ですね。

exports.handler = (event, context, callback) => {
    console.log("callback response " + JSON.stringify(event['body-json']));
    callback(null, {"message":"seikou_daze"});
};

ここまで書いたら右上の「保存」で保存しておきましょう。一応「テストイベントの作成」からテストを作って、実行してみると下記のようになります。ちゃんと動いているようです。

まだデータが入ってきていないので、ログ出力の部分で「callback response undefined」となっていますが、これをAPI Gatewayとつなげてログ出力できるようにします。

API Gateway部分

上記のように新しくAPI Gatewayを作りましょう。

リソースを作成しときます。API Gatewayでリソースというのは要するにURLを追加するということになります。このURLにアクセスすることでLambdaを起動させるということですね。下記では /reciever というリソースを追加しています。

で、このリソースに対してメソッドの追加もしておきます。今回はデータを送るのでPOST。Lambda関数に先ほど作成した関数を設定しておきましょう。

この時点で、テストをすると下記のようにLambdaからレスポンスが帰ってくると思います。テストでLambdaとの疎通が確認できたら、一度デプロイしてしまいましょう。下記のようにステージを適当に作成し、デプロイを行います。

これでAPI Gateway用のURLが発行されるので、POSTができるようになります。何を使ってもいいんですが、下記のようなコマンドでPOSTしてみましょう。

$ curl -X POST -H 'Content-Type: application/json' -d '{"hey": "yo!"}' https://xyz.execute-api.ap-northeast-1.amazonaws.com/test-receiver-999-105/receiver
{"message":"seikou_daze"}

ちゃんとLambdaからレスポンスが帰ってきているのが確認できますね。でもこれだけだとCloudwatch Logsには何も書かれません。「callback response undefined」のままだと思います。POSTデータを渡すには、API Gatewayでもう少し設定が必要です。

もう一度API GatewayのPOSTメソッドを開き、「統合メソッド」を開いてください。その「マッピングテンプレート」を下記のように設定します。

{
    "body-json" : $input.json('$') 
}

これで保存すれば設定完了です。何をしてるかというとAPI GatewayはLambdaを起動するのですが、デフォルトでPOSTデータなどを渡しません。それを渡すためのマッピングを書く必要があり、上記の設定を行うことで body-json にデータが入るようになります。

試してみる

もう一度curlで実行してみます。ちなみにapplication/jsonだった時のマッピングテンプレートを書いたので Content-Type で指定しないとLambdaにデータが渡りません。

curl -X POST -H 'Content-Type: application/json' -d '{"hey": "yo!"}' https://xyz.execute-api.ap-northeast-1.amazonaws.com/test-receiver-999-105/receiver
{"message":"seikou_daze"}

Cloudwatch Logsを見ましょう。ログストリームに下記のようなログが入ってくるのではないでしょうか。

やったぜー! 成功だぜー! 無料枠だぜー! という感じで目的を達することができました。でも絶対にもっと簡単にできる気がするので、皆さまからのグッドアイデアお待ちしてます。まさくにでした。