2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【これ検索するの何回目だよ】API Gateway + Lambdaプロキシ統合でもう躓きたくない

Posted at

はじめに

フロントエンドからAPI Gatewayを経由してLambdaを実行する時、毎回少しだけ躓きます、、、。
解決はするのですが、何度も同じことを経験しては忘れてを繰り返しているので教訓をまとめます!!!

教訓

  1. 統合レスポンスをクライアントに返却する際、lambda → API Gatewayのレスポンスは正しい形式である必要がある!
  2. ライブラリによってPOSTの仕方が異なるので注意するべし!!
  3. フロントのリクエストボディはparseして利用!!!

これだけです!あとは簡単!!
lambda統合機能最高!!!

動作確認

1. 統合レスポンスをクライアントに返却する際、lambda → API Gatewayのレスポンスは正しい形式である必要がある!!

API Gatewayのメソッドテスト機能で、以下のようなエラーが発生することがあります。

cap05.PNG

cap06.PNG

Sat Aug 31 06:47:31 UTC 2024 : Execution failed due to configuration error: Malformed Lambda proxy response
Sat Aug 31 06:47:31 UTC 2024 : Method completed with status: 502

エラーメッセージを読むと、以下の記載があることが確認できます。

Malformed Lambda proxy response

ドキュメントには、以下のように記載されています。
lambdaプロキシ統合をしている場合は、lambdaのレスポンスが所定の形式である必要があるとのことです。

cap07.PNG

In Lambda proxy integration, API Gateway requires the backend Lambda function to return output according to the following JSON format:

プロキシ統合では、API Gatewayはプロキシサーバー的な動作を行います。
具体的には、フロントからのリクエストはそのままlambdaへ、lambdaからのレスポンスはそのままフロントへプロキシします。
そのため、lambdaのレスポンスはWeb APIのレスポンス形式でなければならないわけです。

output.json
{
    "isBase64Encoded": true|false,
    "statusCode": httpStatusCode,
    "headers": { "headerName": "headerValue", ... },
    "multiValueHeaders": { "headerName": ["headerValue", "headerValue2", ...], ... },
    "body": "..."
}

:x: 怒られるlambda

cap04.PNG

:o: 怒られないlambda

cap08.PNG

おまけ:CORS設定

API Gatewayはプロキシサーバー的な動作を行うと上記しました。
フロントからのリクエストはそのままlambdaへ、lambdaからのレスポンスはそのままフロントへプロキシするイメージです。
この場合、CORS関係のレスポンスヘッダーもlambda側で設定する必要があります。

cap10.PNG

2. ライブラリによってPOSTの仕方が異なるので注意するべし!!

これは読んで字のごとくです。気分でfetchとaxiosを使い分けてるのですが、POSTメソッドの仕様が異なります。

fetch:

fetch.ts
  const onClickFetch = async () => {
    try {
      const requestBody = {
        id: 123,
        name: 'api-gateway-test',
      }

      const response = await fetch(`${API_GATE_URL}/test`, {
        method: 'POST',
        body: JSON.stringify(requestBody),
      });

      console.log(response);
    } catch (error) {
      console.error('Error:', error);
    }
  }

第二引数のobjectのbodyはStringに変換しないといけません。

axios:

axios.ts
  const onClickAxios = async () => {
    try {
      const requestBody = {
        id: 123,
        name: 'api-gateway-test',
      }

      const response = await axios.post(`${API_GATE_URL}/test`, requestBody,);

      console.log(response);
    } catch (error) {
      console.error('Error:', error);
    }
  }

第二引数にobjectをそのまま代入して大丈夫です。

3. フロントのリクエストボディはparseして利用!!!

以下がドキュメントです。lambdaがAPI Gatewayから受け取るinput形式が記載されています。

ドキュメントにある通り、プロキシ統合では、handler関数の第一引数eventオブジェクト内にフロントエンドのリクエストボディがstringで代入されます。
具体的に言うと、event.bodyですね!

input.json
{
  "resource": "/my/path",
  "path": "/my/path",
  "httpMethod": "GET",
  "headers": {
    "header1": "value1",
    "header2": "value1,value2"
  },
  ~(略)~
  "body": "Hello from Lambda!",
  "isBase64Encoded": false
}

lambda関数でリクエストボディにアクセスする場合、以下のようなコードになります。

handler.js
exports.handler = async (event, context) => {
    const requestBody = JSON.parse(event.body)
    console.log(requestBody);

    /**
    * 処理 
    */

    return {
        statusCode : "200",
        headers: {
            "Access-Control-Allow-Origin": "*",
            "Access-Control-Allow-Headers": "Content-Type",
            "Access-Control-Allow-Methods": "OPTIONS,POST,GET"
        },
    }
};

おわりに

もう何回このミスするんだよ・・・なことをまとめました。
こういったふりかえりを何度もして、検索しなくても良い知識を増やしていきたいですね。

2
2
0

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
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?