HTTP カスタム統合の API Gateway でバックエンドのステータスコードと異なるコードが返ってくるのはなぜでしょうか
困っていた内容
バックエンドが EC2 の HTTP カスタム統合 の APIGateway を通してリクエストを行うと、全てのレスポンスが HTTP ステータスコード 「200」で返ってきます。
例えば、バックエンドの EC2 インスタンスに直接リクエストすると、想定通り「500」のステータスコードが返ってきます。しかしながら、API Gateway を経由する場合は、「200」が返ってきてしまいます。
どうすれば、バックエンドのサーバ が返したステータスコードを、APIGateway のステータスコードとして返せるのでしょうか。
どう対応すればいいの?
HTTP カスタム統合の場合、バックエンドから返ってきたレスポンスを API Gateway に対応するレスポンス統合をメソッドレスポンスに関連付けてあげないと、どのステータスコードでも、デフォルトで設定されているステータスコード「200」が API Gateway からクライアントへ返ってしまいます。
AWS 公式では HTTP カスタム統合を以下のように記載しています。
HTTP: このタイプの統合は、API がバックエンドの HTTP エンドポイントを公開することを可能にします。HTTP 統合 (HTTP カスタム統合とも呼ばれます) では、統合リクエストと統合レスポンスの両方を設定する必要があります。メソッドリクエストから統合リクエストへの、また統合レスポンスからメソッドレスポンスへの、データマッピングを設定する必要があります。
API ゲートウェイ API 統合タイプの選択 - Amazon API Gateway
後半に記述のように、バックエンドからのレスポンスを API Gateway 側でよしなにクライアントへ返してはくれませんので、注意しましょう。
準備
では、実際に上記のような挙動となるか検証してみましょう。 まず、バックエンドから返ってきたレスポンスをそのままクライアントへ返すように API Gateway とバックエンドの EC2 インスタンス を設定してみます。
構成
今回の検証の以下の図のような構成で進めます。
API Gateway の設定
以下の様に、API Gateway のリソース、メソッドを作成します。
また、EC2 へ HTTP 統合するように、EC2 の バブリック IP を取得しておき、ポートが 8080 でアクセスするように、
API Gateway の統合リクエストを設定します。
EC2 インスタンスの設定
EC2 は Amazon Linux 2 を利用し、EC2 上にインストールして Doker に PHP をデプロイする前提で話を進めます。
それでは、まず EC2 インスタンスへ SSH して、Docker と docker-compose をインストールします。
まず、Docker のインストールします。
$ sudo yum -y install docker $ sudo systemctl start docker.service $ sudo systemctl enable docker $ sudo usermod -a -G docker ec2-user
次に、docker-compose のインストールします。
sudo curl -L "https://github.com/docker/compose/releases/download/1.26.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
それぞれインストールされたか確認します。
$ docker --version Docker version 20.10.4, build d3cb89e $ docker-compose --version docker-compose version 1.26.0, build d4451659
次に、ec2-user のカレントディレクトリで以下のディレクトリ構造のファイル群を作成します。
$ tree . ├── Dockerfile ├── docker-compose.yml └── src └── index.php
Dockerfile は以下の様に、最新の PHP と Apache の公式イメージを利用します。
適宜、Dockerhub で確認しましょう。
FROM php:8.0.7-apache
Dockerdocker-compose.yml は、以下を利用します。
ポート 8080 でホスト側が待ち受けるように設定します。コンテナ側のポートは 80 にします。
version: '3' services: php: build: . volumes: - ./src:/var/www/html ports: - 8080:80
最後に、クライアントがアクセスした際に表示する、index.php を作成します。
<?php echo "Hello Nakano"
それでは、準備ができたので、イメージを構築後、コンテナを起動します。
$ docker-compose build $ docker-compose up
ここで、ブラウザで直接 EC2 へアクセスして正常に表示されるか確認しましょう。
$ curl -i http://XX.XX.XX.XX:8080 HTTP/1.1 200 OK Date: Tue, 22 Jun 2021 08:59:17 GMT Server: Apache/2.4.38 (Debian) X-Powered-By: PHP/8.0.7 Content-Length: 12 Content-Type: text/html; charset=UTF-8 Hello Nakano
検証してみた
想定外の挙動になることを確認
上述の例にも挙げたように、API Gateway にリクエストした際にバックエンドから 500 エラーが返ってくる場合の検証をしてみましょう。
まず、意図的に 500 エラーをバックエンドからレスポンスするように、index.php で http_response_code を使ってレスポンスステータスを書き換えます。
<?php http_response_code(500); echo "Hello Nakano";
再度 EC2 の IP をブラウザに入力して表示すると、レスポンスコードが「500」で返っていることが確認できました。
$ curl -i http://XX.XX.XX.XX:8080 HTTP/1.1 500 Internal Server Error Date: Tue, 22 Jun 2021 09:01:17 GMT Server: Apache/2.4.38 (Debian) X-Powered-By: PHP/8.0.7 Content-Length: 12 Connection: close Content-Type: text/html; charset=UTF-8 Hello Nakano
それでは、API Gateway 経由でレスポンスがどうなるか確認してみましょう。
$ curl -i https://XXXXX.execute-api.ap-northeast-1.amazonaws.com/test/hello HTTP/2 200 date: Tue, 22 Jun 2021 09:02:14 GMT content-type: application/json content-length: 12 x-amzn-requestid: 7a7a3197-9842-49dd-a455-d3f23e2a3900 x-amz-apigw-id: BUcLiH3ANjMFcrA= x-amzn-trace-id: Root=1-60d1a716-1bc3c65959cc464e455af33c Hello Nakano
curl から返ってきたレスポンスを見てもわかるように、ステータスコード「500」で返ってこないといけないところが、「200」として返ってきています。
やはり、「困っていた内容」の通りの挙動となることが確認されました。
レスポンスをマッピング設定する
それでは、API Gateway にバックエンドから返ってきたレスポンスをクライアントへ返すように、マッピング設定を行います。
まず、メソッドレスポンスのコンソールで、HTTP ステータス「500」を追加します。
次に、統合レスポンスのコンソールで、以下の図のようにステータスコード「500」の場合の設定を追加します。
以上で、バックエンドから返ってきた HTTP ステータスコード「500」がクライアントへ返るようになりました。
想定通りの挙動になったか確認
最後に、本当にステータスコード「500」が返るようになったか検証してみます。
ブラウザで、API Gateway のエンドポイントへアクセスすると、HTTP ステータスコード「500」が返っていることが確認できました。
これで想定通りの挙動となりました。
$ curl -i https://XXXXX.execute-api.ap-northeast-1.amazonaws.com/test/hello HTTP/2 500 date: Tue, 22 Jun 2021 09:05:43 GMT content-type: application/json content-length: 12 x-amzn-requestid: b3fddbb3-e0bd-4ab0-85b3-867b9fcd07b9 x-amz-apigw-id: BUcsRGjItjMFtSQ= x-amzn-trace-id: Root=1-60d1a7e7-5fe400d14ca1728c581290ac Hello Nakano
参考資料
API ゲートウェイ API 統合タイプの選択 - Amazon API Gateway
API Gateway で統合レスポンスを設定する - Amazon API Gateway
EC2(Amazon Linux 2)に docker と docker-compose をインストールしてみる - Qiita
docker-compose で PHP 開発環境 - Qiita