はじめに
AWS API GatewayからLambdaを呼び出すこと、よくあると思います。
Lambdaではevent.body
でリクエストボディを取得できますが、
デフォルトではこのbody
は文字列なので、
Content-Type:application/json
の場合も「JSON文字列」になります。
そのため、一度JSONをパースしてあげないといけません。
たとえばNode.jsの場合はこんな感じ。
exports.handler = async (event) => {
const body = JSON.parse(event.body);
console.log('api received!', body);
const response = {
statusCode: 200,
body: JSON.stringify([body.hoge, body.fuga, body.piyo]),
};
return response;
};
コード側でJSON.parse()
すること自体は大した手間ではないのですが、
面倒くさいのがテストです。
Lambdaの「テストイベントの設定」で、こんな感じで書きたいわけですよ。
{
"body": {
"hoge": 1,
"fuga": 2,
"piyo": 3
}
}
しかしながら、これは「JSON文字列」ではなく「JSONオブジェクト」なので、
API Gatewayのevent.body
とは互換性がありません。
こうしてやらなければならない。。。
{
"body": "{\"hoge\":1,\"fuga\":2,\"piyo\":3}"
}
これはねぇ、、、辛いですよね。
ダブルクォートのエスケープの嵐で、サクッと手書きで書くことは無理です。
解決方法
API Gatewayの「マッピングテンプレート」という機能を使うと、
ちゃんとJSONをオブジェクトにしてからLambdaに飛ばすことができます。
Lambda側のトリガー設定から新規REST APIを作成
- 検証用に、ごくごくシンプルな設定でAPIを作成
- 実運用では「オープン」は危険なので要注意
- HTTP APIではマッピングテンプレートが使えないので、REST APIにする
API Gatewayのリソース設定
- API Gatewayのリソース設定に飛ぶ
- 「ANY」メソッドの「統合リクエスト」を開く
マッピングテンプレートの設定
- リクエスト本文のパススルー:「テンプレートが定義されていない場合 (推奨)」を選択
- マッピングテンプレートの追加:「application/json」を入力
- テンプレートの生成:「メソッドリクエストのパススルー」を選択すると、いい感じのプリセットが入る
- 書式が独特なので、一から書くのが大変なのですよね。。このプリセットがとってもありがたい。
- ほとんどプリセットのままで良いのだけど、
body-json
はcamelCaseのbodyJson
にしておくと、JavaScriptでは扱いやすい- もしくはシンプルに
body
でもOK
- もしくはシンプルに
- 編集したら「保存」
## This template will pass through all parameters including path, querystring, header, stage variables, and context through to the integration endpoint via the body/payload
#set($allParams = $input.params())
{
-"body-json" : $input.json('$'),
+"bodyJson" : $input.json('$'),
"params" : {
#foreach($type in $allParams.keySet())
#set($params = $allParams.get($type))
APIのデプロイ
- アクションから「APIのデプロイ」を選択
- ステージ「default」を選んで、説明は書きたければ書いて、「デプロイ」
Lambdaの修正版と実行結果
「Lambdaプロキシ統合の使用」が外れたことで、
レスポンスの作り方も変わります。
statusCode
はAPI Gateway側で定義するので、
Lambdaではシンプルに、正常系のレスポンスをそのままreturn
するだけ。
exports.handler = async (event) => {
const body = event.bodyJson;
console.log('api received!', body);
return [body.hoge, body.fuga, body.piyo];
};
Lambdaテストイベント
{
"bodyJson": {
"hoge": 1,
"fuga": 2,
"piyo": 3
}
}
PCターミナルからcurlでAPI叩いてテスト
$ curl -X POST https://example.amazonaws.com/default/mappingTemplateTest -H 'Content-Type:application/json' -d '{"hoge":1,"fuga":2,"piyo":3}'
[1,2,3]
いい感じですね!
参考サイト
AWS公式
ブログ・Qiita
- [AWS]API Gatewayの本文マッピングテンプレートを理解する
- API Gateway + Lambda にFormからPOSTする時のマッピングテンプレートを作成しました
- API Gatewayのマッピングテンプレートの設定例
ではまた~。