狛ログ

2022年1月11日火曜日

【AWS】API GatewayからS3に配置したファイルを直接レスポンスする。

オフィス狛 技術部のyuckieeeです。
今回もまた「API Gateway」を使用したAPI用Mockに関する小ネタをご紹介しようと思います。

本投稿の背景

API Gatewayで快適Mockライフを送る予定だったのですが、思わぬ壁にぶつかりました。
何かというと、データ量の多いJSONデータ(2~6MB程度)を返却しようと統合Mockを設定したところ見知らぬエラーが表示されたのです。
※そんなデータ、JSONで返却するなよ...というツッコミはとりあえず置いておいて下さい(笑)

エラーメッセージ:The resource being saved is too large.Consider reducing the number of modeled parameters, the number of response mappings, or perhaps the size of your VTL templates if used. 何だコレ...と思っていたのですが、どうやらAPI Gatewayにはマッピングテンプレートに設定容量制限があり、そこに引っかかったようです。
私の環境では、マッピングテンプレート128KB辺りを境界にエラーが発生しているようでしたが、公式ページ上のAPIGatewayの制限事項にドンピシャの記述は見つけられませんでした。
ですが、恐らく、この中の何かの制限に引っかかっているものと思います。
公式:REST API の設定および実行に関する API Gateway クォータ

それじゃあ、サイズの大きいデータはどうやって返せば良いのか...
Lambdaを使用することも可能ですが、出来るだけ簡単に対応したいと思ってAPI Gatewayを使用してMockを作成したのに構成が複雑になったら使う意味g(以下略
調査の結果「S3に配置したJSONファイルを直接返却する方法」が一番簡単そうでした。
実際に試すと6MBまでのデータであれば対応可能で、今回の私の要件は満たせそうです。

ということで、 今回はAPI GatewayからS3に直接アクセスしてJSONを返却する方法をご紹介します!

設定手順

以下の作成が完了している前提で、説明割愛いたします。
・S3バケットの作成
・API Gatewayで任意の統合Mock作成(→詳細はコチラで紹介しています!)

Step1: IAMロール作成

デフォルトの状態ではAPI GatewayにS3へのアクセス権限は付与されていません。
そのため、API GatewayにS3へのアクセス許可を与えるためのロールを作成します。

AWSコンソールからIAMの管理画面を開きます。
アクセス管理のロールを選択し、表示された画面右上にある[ロールを作成]を選択して下さい。
[ロールの作成]画面が表示されたら、[信頼されたエンティティの種類を選択]で「AWSサービス」が選択されていることを確認します。
[ユースケースの選択]で[S3(一覧)]>[S3(画面下部)]を選択し、[次のステップ:アクセス権限]ボタンをクリックします。
※今回は、信頼されたエンティティとして「API Gateway」を設定したいのですが、「API Gateway」として用意されているユースケースは、API GatewayからCloud watchにログをアップするというもので、S3へアクセスするユースケースは用意されていないようでした。そのため、本ユースケース設定をベースにカスタマイズします。

次画面の[Attach アクセス権限ポリシー]で、一覧から「AmazonS3ReadOnlyAccess」(※)を選択し、[次のステップ:タグ]ボタンをクリックしてください。
※今回はMockとして使用するため、リクエストがPOSTやPUTであっても、S3上のオブジェクトを読み込みレスポンスとして返却するのみです。そのため、必要最低限である読み取り権限のみのポリシーを選択しています。
タグの追加画面では特に設定変更を行わず[次のステップ:確認画面]をクリックし、確認画面まで遷移してください。
確認画面では以下2項目を設定し、[ロールの作成]ボタンをクリックすれば、ロールが作成されます。

【設定値】
・ロール名:任意
・ロールの説明:任意 ※今回だと「Allows API Gateway to access to S3.」とかでしょうか。

Step2: IAMロールのカスタマイズ

ロールを作成した段階では、ユースケースで選択したとおり「Allows S3 to call AWS services on your behalf.」という、S3が、このロールを使用して任意のAWSサービス(今回はS3)を呼び出すことを想定したものとなっています。
そのため、信頼関係を変更することで「S3」ではなく「API Gateway」が、このロールを使用できるようにします。

作成したIAMロールの概要ページに遷移し、[信頼関係]タブの[信頼関係の編集]ボタンをクリックして信頼関係の編集画面を開きます。
7行目の"Service": "s3.amazonaws.com"の記述を"Service": "apigateway.amazonaws.com"に書き換え、[信頼ポリシーの更新]ボタンをクリックして信頼関係を変更します。
これでAWSサービス「API Gateway」が、該当ロールとして振る舞うことを許可(信頼)されました。

信頼関係の変更後、IAMロールの設定状態を確認します。

[アクセス権限]タブ
「AmazonS3ReadOnlyAccess」権限のみが付与されていることを確認します。
[信頼関係]タブ
信頼されたエンティティに「IDプロバイダー apigateway.amazonaws.com」が設定されていることを確認します。

これで今回使用するロールの作成が完了しました。

Step3:S3にレスポンスファイルを配置する

S3バケットを任意で作成後、管理コンソールからレスポンス用のファイルをアップロードします。
今回は、JSON形式で返却したいため、以下のようなファイルを準備しました。
    {      "result_code" : "0",     "result_message" : "OK"     }

Step4:API Gatatewayの設定を変更する

S3オブジェクトによるレスポンスに変更したい、API Gateway上のリソースを選択します。
[メソッドの実行]画面で[統合リクエスト]をクリックし、設定画面で以下のように設定を変更して[保存]をクリクします。

【設定値】
 ・統合タイプ:AWSサービス
 ・AWSリージョン:ap-notheast-1
 ・AWSサービス:Simpe Storage Service(S3)
 ・AWSサブドメイン:指定なし
 ・HTTPメソッド:GET 
 ・アクションの種類:[パス上書きの使用]にチェック
 ・パス上書き:レスポンス用ファイルのパス ※バケット名/オブジェクト名
 ・実行ロール:今回用に作成したロールを指定(arn:aws:iam::xxxxx)
 ・コンテンツの処理:パススルー※デフォルト設定
 ・デフォルトタイムアウトの使用:チェックオン※デフォルト設定
AWSの統合に切り替えてよいかの確認ダイアログが表示されますので、[OK]をクリックしてください。
これで設定変更は完了です。

Step5: 動作確認&APIのデプロイ

実際に動くかどうか確認を行います。
[メソッドの実行]画面で画面右にある[テスト⚡]をクリックし、[メソッドテスト]画面に遷移します。
[メソッドテスト]画面の左下にある[⚡テスト]ボタンをクリックして、テスト実行してください。
リクエストのレスポンス本文にS3オブジェクトに配置したとおりの内容が返ってきていればOKです。

ここまで確認ができれば、APIのデプロイを行い、作業終了です。
実際にMockとして呼び出して、テストしてみてください。

おまけ:レスポンスに画像を指定する

JSONだけではなく画像ファイルを返却したいという場合もあると思います。
今の設定でも、S3上のファイルを画像ファイルに変えれば上手くいくんじゃないの?って感じるかもしれませんが、デフォルトで画像ファイルのレスポンスは制限されているようです。
以下設定手順を軽くご紹介しておきます。

設定手順

該当APIの設定メニューを選択し、設定画面を開きます。
設定画面の下部にある「バイナリメディアイプ」の[+バイナリメディアタイプの追加]を押下することで、入力フィールドが追加されるため、「*/*」(※)を入力して、右下の[変更の保存]を押下して完了です。
※指定する内容は、HTTPヘッダーのContent-Typeと同様の内容でも問題ありませんが、ワイルドカードで指定しておくのが一番楽ちんかと思います。
これでS3の画像オブジェクトを指定しても、問題なくレスポンスできるようになったかと思います。

まとめ

こちらの方が従来のMockツールに近い感じですね。
また、S3のファイルを置き換えれば、レスポンス内容変更のたびにAPIをデプロイし直すという手間も省けて楽な感じがします。
ガッツリテストをするとなると、こちらの方が向いているかな...というのが個人的な感想です。

API Gatewayには、いろいろな使い方があるのがわかってきたので、もっと色々と紹介していきたいと思います!


, ,

0 件のコメント:

コメントを投稿