API GatewayをS3のプロキシとして作成してみる。

## はじめに
先日の記事で `Lambda` と `API Gateway` を利用したREST API経由のS3内のファイルダウンロードは試してみたが、`API Gateway` のみでも同じ事はできそうと聞いたので、そちらの方も今回試してみた。
　※先日の記事は[**こちら**](https://qiita.com/smiler5617/items/660f549137fc6851b391)


## 作成の流れ
基本的には以下の公式サイトをベースに作成しているが、いくつか分かりづらかったところは勝手に手順をアレンジしている。
また、公式サイトではバケット内の一覧情報の取得などの方法も含まれているが、今回の記事では**バケット内の指定オブジェクトをダウンロードする** ところのみに絞った内容にしている。

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/integrating-api-with-aws-services-s3.html

① IAMロールの作成
② API Gatewayの作成
　・リソースの作成
　・GETメソッドの作成
　・統合リクエストの設定
　・メソッドレスポンスの設定
　・統合レスポンスの設定



## ① IAMロールの準備

### IAMロールの新規作成
AWSサービスのIAMより、ロールの画面を開いてロールを作成する。
下図の様に`API Gateway` をユースケースとして、【次のステップ】をクリック。
![Qiita-no055_img01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/bc2d1a09-59f8-0bcb-a15f-f4bb241acebc.jpeg)
『Attached アクセス権限ポリシー』、『タグの追加 (オプション)』の設定画面に遷移するが、デフォルトから特に変更せずに【次のステップ】をクリック。

最後に任意なロール名を付けて【ロールの作成】をクリック。


### 作成したロールにポリシーアタッチ
作成したロールを開き、『アクセス権限』タブよりポリシーをアタッチする。
今回デフォルト以外に追加でアタッチするポリシーは `AmazonS3ReadOnlyAccess`のみ。（今回の記事ではS3内オブジェクトのダウンロードしかしないため。）


## ② APIGatewayの作成

### リソースの作成
Root直下に `folder`リソースを作成する。
URLリクエストの際にバケット名を指定してする部分に相当。
![Qiita-no055_img02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/31dec0ac-f0c9-bd81-ea20-48c0640f183d.jpeg)

`folder` の下に `item` リソースを作成する。
こちらはURLリクエストの際にオブジェクトを指定する部分に相当。
![Qiita-no055_img03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/ae1ec4fa-9ef6-b929-4981-2a9ebb57fb88.jpeg)

### GETメソッドの作成
`item` リソースの下に `GET` メソッドを作成。（設定は下図を参照）
![Qiita-no055_img04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/ebb0761c-0977-e7cc-0ff8-6785cb971b26.jpeg)

※1．AWSリージョンについては、今回GETを試すS3バケットのリージョン。
※2．パス上書きでは、`S3`で受け取れるパスにしている。
※3．実行ロールの部分には、①で作成したロールの `ロールARN` をコピペ。


### 統合リクエストの設定
`S3` にバケット名とオブジェクト名を投げるために、URLパスパラをマッピングする。
![Qiita-no055_img05.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/c96832f0-edf4-276e-e445-e3ccf45982e4.jpeg)


### メソッドレスポンスの設定
200(成功時)のレスポンスヘッダーに、出力時に追加したいHeader名称を追加。
今回は `Content-Type` と `Content-Disposition` を追加。


### 統合レスポンスの設定
上記のメソッドレスポンスにより返すヘッダーを決めたので、その中身のマッピングを行う。
　・`Content-Type` ⇒ integration.response.header.Content-Type
　・`Content-Disposition` ⇒ 'attachment; filename="download"'
　　※ダウンロードファイルの名前は`download`

（中身のファイル構造が影響を受ける訳ではないため、この段階で拡張子は付ける必要なし。拡張子はローカルに落とした後に単にどのアプリを使って開くかくらいな話なので、ダウンロードしてからリネームすればOK。）
![Qiita-no055_img07.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/83d4cad8-ff72-bd83-45aa-1e0f94c3c65c.jpeg)


### テストを実施
対象のバケット内に適当なテストファイルを入れた後、`{folder}`と`{item}` を入力して、下図の様なレスポンスがちゃんと返ってくればOK！
![Qiita-no055_img08.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/7a93ae26-4962-c7fa-ce2b-87b216b98c29.jpeg)

**テストで特に問題なければAPIをデプロイし、URLからバケットとオブジェクト（今回の場合バケット直下に置いたオブジェクト）を指定して`download`という名前のファイルがダウンロードできればOK！**

　　　　　　
## おまけ

### バケット直下より深いオブジェクトを指定する方法
API Gatewayのリソース作成でそもそも `folder` と `item` しか作成していない場合は無理そう。
試しにGETテストで `{item}`に `test_folder/test.txt` を入れてみたが、2つのリソースの情報が含まれているため、これではオブジェクトの情報を取得できなかった。
解決方法としては、バケット内のフォルダ階層に応じたリソース、`bucket`、`folder1`、`folder2`、`item` などを作成すれば、後は同じ要領でオブジェクトにちゃんとアクセスできる。

### ちゃんとデータを取得できなかったときはエラーステータスを返す方法
メソッドレスポンスより`400`や`500`のHTTのステータスを追加する。
![Qiita-no055_img09.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/6f55c3da-f0df-c069-fea5-90c019f7f8eb.jpeg)

統合レスポンスの追加より、バックエンドから400番台のステータスコードが返った場合に、メソッドレスポンスのステータス400とマッピングする（500番台も同様に作成）
![Qiita-no055_img10.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/f89f517a-b9cd-d119-a932-18d11efac5b9.jpeg)

**この状態で試しにテストし、存在しないファイルを指定した場合にステータス400で返ってくれば、ちゃんと設定できている。**


### バイナリファイルをダウンロードする方法（jpg、zipなど）

**以下のサイトを参考に現在試し中。やり方が分かり次第更新予定。**

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-payload-encodings.html

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-payload-encodings-workflow.html