API GatewayのGETメソッド、bodyの挙動は統合タイプで変わる

  • AWS
  • API Gateway

この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。

結論

API GatewayのGETメソッドでbodyを送った場合の挙動は、統合タイプで完全に分かれる。

  • Lambdaプロキシ統合: bodyはそのままLambdaの event.body に渡る
  • HTTP統合・VPC Link統合(非プロキシ): Integration Requestのメソッドをリソースメソッドと同じGETのままにしていると、bodyはAPI Gatewayの時点でドロップされ、バックエンドには空のペイロードしか届かない

「GETにbodyを付けたら無視されることがある」くらいのふわっとした理解だと、Lambda統合で普通に動いてしまって気づかないパターンと、HTTP/VPC Link統合で無言でデータが消えるパターンの両方を踏み抜く。

仕様上の位置づけ

API Gatewayの公式ドキュメントでは、method requestのpayload設定はPOST・PUT・PATCHのケースとして説明されていて、GETはそもそも対象に入っていない。つまりGETでbodyを使うこと自体、公式に想定された使い方ではない。

HTTP/1.1の仕様自体はGETリクエストのbodyを明示的に禁止しているわけではないけど、意味的な扱いが定義されていないので、多くのHTTPクライアント・サーバー・プロキシで想定通りに扱われる保証がない。

統合タイプ別の挙動

Lambdaプロキシ統合

GETでもbodyはそのままLambda関数に渡る。event.body に入ってくるので、実装上は「GETなのにbodyを読める」状態になる。動くには動くが、REST的な意味論からは外れた使い方になる。

HTTP統合・VPC Link統合(非プロキシ)

Integration Requestのメソッドがリソースメソッドと同じGETのままだと、bodyはAPI Gatewayの時点でドロップされる。バックエンドには空のペイロードしか届かない。

bodyを通したい場合は、リソースメソッド自体はGETのままにしつつ、Integration RequestのメソッドだけをPOSTに変更する、という回避策がある。ただしこれは実質「GETの皮を被ったPOST」を作っているだけなので、素直にリソースメソッド自体をPOSTにした方が分かりやすい場面が多い。

対処法

複雑なデータや多めの情報を渡したいなら、素直にPOSTかPUTを使うのが一番安全。API Gatewayのpayload設定周りも、この2つ(とPATCH)を前提に作られている。

GETでどうしても情報を渡したいなら、クエリパラメータかパスパラメータに寄せる。API Gatewayのmethod request側で普通に設定できるし、キャッシュやロギング、途中に挟まるプロキシでの扱いも安定してる。

未確認

Lambda以外のAWSサービス統合(DynamoDBやS3への直接統合など)でGET+bodyがどう扱われるかは、今回確認してない。統合タイプごとに個別に見た方が良さそう。