Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
5
Help us understand the problem. What is going on with this article?
@the_red

API GatewayからLambdaを呼び出すときにevent.bodyをオブジェクトで受け取る

はじめに

AWS API GatewayからLambdaを呼び出すこと、よくあると思います。
Lambdaではevent.bodyでリクエストボディを取得できますが、
デフォルトではこのbodyは文字列なので、
Content-Type:application/jsonの場合も「JSON文字列」になります。
そのため、一度JSONをパースしてあげないといけません。

たとえばNode.jsの場合はこんな感じ。

index.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}"
}

image.png

これはねぇ、、、辛いですよね。
ダブルクォートのエスケープの嵐で、サクッと手書きで書くことは無理です。

解決方法

API Gatewayの「マッピングテンプレート」という機能を使うと、
ちゃんとJSONをオブジェクトにしてからLambdaに飛ばすことができます。

Lambda側のトリガー設定から新規REST APIを作成

  • 検証用に、ごくごくシンプルな設定でAPIを作成
    • 実運用では「オープン」は危険なので要注意
  • HTTP APIではマッピングテンプレートが使えないので、REST APIにする

image.png

API Gatewayのリソース設定

  • API Gatewayのリソース設定に飛んぶ
  • 「ANY」メソッドの「統合リクエスト」を開く

image.png

  • Lambdaから作ったAPIは「Lambdaプロキシ統合の使用」がチェックされているので、このチェックを外す。
    image.png

  • チェックを外すとすると詳細な設定項目が現れるので、「マッピングテンプレート」を開く
    image.png

マッピングテンプレートの設定

  • リクエスト本文のパススルー:「テンプレートが定義されていない場合 (推奨)」を選択
  • マッピングテンプレートの追加:「application/json」を入力
  • テンプレートの生成:「メソッドリクエストのパススルー」を選択すると、いい感じのプリセットが入る
    • 書式が独特なので、一から書くのが大変なのですよね。。このプリセットがとってもありがたい。

image.png

  • ほとんどプリセットのままで良いのだけど、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」を選んで、説明は書きたければ書いて、「デプロイ」

image.png
image.png

Lambdaの修正版と実行結果

「Lambdaプロキシ統合の使用」が外れたことで、
レスポンスの作り方も変わります。
statusCodeはAPI Gateway側で定義するので、
Lambdaではシンプルに、正常系のレスポンスをそのままreturnするだけ。

index.js
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公式
* REST API のデータ変換の設定
* API Gateway で Lambda プロキシ統合を設定する

ブログ・Qiita
* [AWS]API Gatewayの本文マッピングテンプレートを理解する
* API Gateway + Lambda にFormからPOSTする時のマッピングテンプレートを作成しました
* API Gatewayのマッピングテンプレートの設定例

ではまた~。

5
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
the_red
富山県の旧細入村でリモートワークしてるプログラマー 。 kintoneカスタマイズ用のOSSフレームワーク「Goqoo on kintone」シリーズを開発しています。 https://github.com/goqoo-on-kintone
sonicgarden
「お客様に無駄遣いをさせない受託開発」と「習慣を変えるソフトウェアのサービス」に取り組んでいるソフトウェア企業

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
5
Help us understand the problem. What is going on with this article?