はじめに

Amazon API Gatewayに関するトラブルシューティングの際にアクセスログを活用するシチュエーションはありますよね。
先日実施したトラブルシューティングの中でこれまで認識できていなかったアクセスログの記録の仕様に気付くことができたのでそちらを紹介します。

ログに記録されたパスをそのまま信じると、クライアントがリクエストしたURLを読み違える可能性があります。

前提

・APIタイプ:REST
・エンドポイントタイプ:リージョナル
・リソース:/info
・メソッド:GETおよびPOSTのみ
ステージ名:demo ※覚えておいてください
・リクエストURL:https://APIGatewayのデフォルトのFQDN/demo/info
・アクセスログのフォーマット:

{
    "requestId": "$context.requestId",
    "extendedRequestId": "$context.extendedRequestId",
    "ip": "$context.identity.sourceIp",
    "caller": "$context.identity.caller",
    "user": "$context.identity.user",
    "requestTime": "$context.requestTime",
    "httpMethod": "$context.httpMethod",
    "resourcePath": "$context.resourcePath", ←  本記事で注目しているフィールドです
    "status": "$context.status",
    "protocol": "$context.protocol",
    "responseLength": "$context.responseLength"
}

※ログフィールドの詳細は公式ドキュメントを参照ください。
【参考】API Gateway のアクセスのログ記録のための変数

結論:resourcePath の値は状況によって変わる

先述した公式ドキュメントでは、$context.resourcePathの説明は以下のように記載されています。

リソースへのパスです。たとえば、https://{rest-api-id}.execute-api.{region}.amazonaws.com/{stage}/root/child の非プロキシリクエスト URI の場合、$context.resourcePath 値は /root/child。

つまり、ステージ名は含まれないものと読み取れます。
しかし実際には、レスポンスステータスコード(リソースへのマッピング成否)によって resourcePath の記録内容が異なります。
クライアントがリクエストしたURLを誤認識しないよう注意が必要です。

レスポンスステータスコードが200の場合

正しくリソースにマッピングされた正常系です。

・リクエストURL:https://APIGatewayのデフォルトのFQDN/demo/info
・実行メソッド:許可されているGETメソッド
・結果:resourcePathにステージ名が含まれない

{
    "requestId": "0d0b67e8-2ca8-4f2d-a242-9729fa4e2f14",
    "extendedRequestId": "U77hIHyatjMEQxw=",
    "ip": "---.---.---.---",
    "caller": "-",
    "user": "-",
    "requestTime": "02/Dec/2025:01:23:44 +0000",
    "httpMethod": "GET",
    "resourcePath": "/info",
    "status": "200",
    "protocol": "HTTP/1.1",
    "responseLength": "0"
}

"resourcePath": "/info"
9行目のresourcePathにはステージ名demoが含まれていないことが分かります。

レスポンスステータスコードが403の場合

未定義のリソース(パス)や許可されていないメソッドを実行し、API Gateway側で弾かれた異常系です。

■パターン① 定義されていないリソース(パス)へのリクエスト

・リクエストURL:https://APIGatewayのデフォルトのFQDN/demo/not-defined
・実行メソッド:許可されているGETメソッド
・結果:resourcePathにステージ名が含まれる

{
    "requestId": "113f9ef0-7d83-4e3f-9c26-efaa55ac5a68",
    "extendedRequestId": "U_NiWFZutjMEDiQ=",
    "ip": "---.---.---.---",
    "caller": "-",
    "user": "-",
    "requestTime": "03/Dec/2025:01:17:28 +0000",
    "httpMethod": "GET",
    "resourcePath": "/demo/not-defined",
    "status": "403",
    "protocol": "HTTP/1.1",
    "responseLength": "42"
}

■パターン② 許可されていないメソッドを実行

・リクエストURL:https://APIGatewayのデフォルトのFQDN/demo/info
・実行メソッド:許可されていないDELETEメソッド
・結果:resourcePathにステージ名が含まれる

{
    "requestId": "d5184644-76e5-4132-965b-8e32f4449ff0",
    "extendedRequestId": "U770MGFVNjMEdaA=",
    "ip": "---.---.---.---",
    "caller": "-",
    "user": "-",
    "requestTime": "02/Dec/2025:01:25:46 +0000",
    "httpMethod": "DELETE",
    "resourcePath": "/demo/info",
    "status": "403",
    "protocol": "HTTP/1.1",
    "responseLength": "42"
}

"resourcePath": "/demo/info"
いずれのパターンでも9行目のresourcePathにはステージ名demoが含まれていることが分かります。
リクエストされたURLが、以下のようにステージ名である/demoが重複しているのではないかと誤認識してしまう恐れがあります。
https://APIGatewayのデフォルトのFQDN/demo/demo/info

まとめ

API Gatewayのアクセスログにおいて、リクエストが正しくリソースにマッピングされなかった場合(403等)、resourcePath は設定上のパスではなく、リクエストされた生のパス(ステージ名込み)になることがあります。
正常系と異常系の場合で挙動が少し異なるため、調査時に正しく現状把握をするため注意が必要です。
ログの確認とともにクライアントが実際に投げているパスを正確に把握することを心がけましょう!

この記事が誰かの助けになれば幸いです。