Rso's Jotter

日々の開発の知見のメモやその他雑記

プロキシ統合と使用してLambdaのレスポンスをそのままAPI Gatewayにパススルーする

普段、ちょっとしたデータの取得、加工などにAPI Gatewayを使用してLambdaを使用しているのですが、かなりやっつけで開発していたコードで、正常系は問題なく動いていたのですが、エラー時に Lambdaが返したHTTPレスポンスコードが API Gatewayに連携されず、Lambdaが5XX系エラーを返しているのに、API Gatewayが200 OK を 返していたと言う不具合がありました。

Lambdaの統合レスポンスをうまくマッピングしてやれば解消するのですが、 Lambdaプロキシ統合 を使用すればもっと簡単にできそうだったので、その内容をメモしておきます。

今回の対応はAWSの以下の内容を参照して試しました。

docs.aws.amazon.com

Lambdaプロキシ統合の設定

Lambdaプロキシ統合を使用すると、 API GatewayからLambdaへの値の受け渡しの方法が自動化され、個別にパススルーなどの設定することなくAPI Gateway - Lambdaがイイ感じに使用できます。

f:id:rso:20190217201935p:plain
Lambdaプロキシ統合の設定

Lambdaプロキシ統合を使用すると、リクエストパラメータの渡し方やレスポンスの受け取り方が通常と異なるので注意が必要です。

今回は GET メソッドをプロキシ統合で設定した例を示します。 どの言語でも内容は変わりませんが、Lambdaはnodeで書きました。

API Gateway -> Lambdaへのリクエストデータの渡し方

API Gateway -> Lambdaへのデータの受け渡しは以下のフォーマットに従う必要があります。

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format

例えば、API Gatewayから GETリクエストをパラメータ付きで行った場合、Lambda側は以下のようなフォーマットとなります。

API Gatewayからのリクエスト

GET https://xxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/production/getapi?param1=111&param2=222

Lambda側での受け取り

{
  "resource": "Resource path",
  "path": "Path parameter",
  "httpMethod": "GET",
  "headers": {},
  "multiValueHeaders": {},
  "queryStringParameters": {
    "param1": "111",
    "param2": "222"
  },
  "multiValueQueryStringParameters": {},
  "pathParameters": {},
  "stageVariables": {},
  "requestContext": {},
  "body": "{}",
  "isBase64Encoded": false
}

上記のように、 queryStringParameters に含まれてLambdaに渡されます。

Lambda -> API Gateway へのレスポンスデータの渡し方

Lambda -> API Gatewayへのデータの受け渡しは以下のフォーマットに従う必要があります。

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-output-format

const lambda_response_format = {
 "isBase64Encoded": false,
 "statusCode": 200,
 "headers": {},
 "body": "json string"
}

body の中には、jsonをstringにしたものを入れてやれば、そのまま API Gatewayにbodyやステータスが連携されます。ステータスコード statusCode もそのままAPI Gatewayのレスポンスとして返ります(これがやりたかった)。

使用してみた所感

レスポンスがパススルーの設定することなくAPI Gatewayと連動するのは楽と感じる一方で、 若干リクエストやレスポンスのフォーマットを合わせるのに少し戸惑いました。

例えば通常の API Gatewayから /api?param1=111 のようなパラメータ渡しの場合 通常のパススルー(nodeの例)だと event.param1 のようにアクセスできますが、 プロキシ統合だと event.queryStringParameters.param1 のように受け渡し方法が変化するので、その辺りを留意すれば問題ないと感じました。

また、そもそもの話として、軽いAPIをサクッと作りたい場合、 API Gateway - Lambda間のやり取りは意識しないようにできれば良いのかなと思います。この辺りがやりたいだけならGCP(Firebase)のCloud Functionの方が手っ取り早いかもしれません。もしくは以前軽く触れたNetlifyのFunctionsなどを使えば静的コンテンツも含めてサクッとできたりしないかなと期待しています。

rso.hateblo.jp