はじめに
フロントエンドから API 経由で Amazon S3 へアップロードを行う機能を実装するための行った内容をまとめておこうと思います。
IAM ロール
まずは API Gateway で利用する IAM ロールの作成を行います。
IAM ロールの作成
「IAM > ロール」 から [ロールを作成] をクリック。

信頼されたエンティティを選択
「信頼されたエンティティタイプ」 で AWS のサービス を選択し、ユースケース では API Gateway を選び [次へ] をクリックします。

許可を追加
名前、確認、および作成
「ロール名」を入力 (ここでは api-gateway-upload-to-s3)し [ロールを作成] をクリック。

IAM ポリシーの設定
「IAM > ロール」 から先ほど作成したロールを選択(ここでは api-gateway-upload-to-s3)

「許可 > 許可を追加」 から [インラインポリシーを作成] をクリック

アクセス許可を設定
S3 の PutObject と GetObject (Get 操作は行わないためなくてもOK)にチェックを入れ、「Effect」 は 許可 にチェックを入れる。


リソース は [特定] を選択し object の ARN を追加 をクリック。

ARN を指定
Resource bucket name の YOUR_BUCKET_NAME の部分に今回アクセスさせたい S3 バケット名を入力し [ARN を追加] をクリック。

確認して作成
「ポリシー名」 を入力 (ここでは api-gateway-upload-to-s3) し [ポリシーの作成] をクリック。

許可ポリシーに api-gateway-upload-to-s3 が付与されていることを確認。

API Gateway リソースの作成
「API Gateway > API」 から [API を作成] をクリック。

API タイプを選択
REST API を作成
API の詳細 で 新しい API を選択し、 API 名 を入力 (ここでは api-gateway-upload-to-s3) し [次へ] をクリック。

アップロード先パスを受け取るリソースの作成
これから、API の URL で指定したファイル名をそのままアップロード先として扱えるようにする設定を行います。
「リソースの詳細」のリソースパス / に リソース名 (今回は {proxy}) を入力し [リソースを作成] をクリック。

このリソース (ここでは {proxy})を使用することで、リクエスト URL のパスをパスパラメータとして受け取り、S3 連携時のオブジェクトキーへマッピングできるようにします。
PUT メソッドの作成
このステップでは、API Gateway で受け取った PUT リクエストを 直接 S3 の PutObject API に連携し、URL のパスをアップロード先(S3 オブジェクトキー)として利用できるように設定します。
「リソース」 で {proxy} を選択し、[メソッドを作成] をクリック。

メソッドの詳細 で以下を選択し [メソッドを作成] をクリック。
- メソッドタイプ:PUT
- 統合タイプ:AWS のサービス
項目 設定 AWS リージョン ap-norhteast-1 AWS のサービス Simple Storage Service (S3) HTTP メソッド PUT アクションタイプ パスオーバーライドを使用
・パスオーバーライド:{bucket}/{key}
・実行ロール:作成したロール ARN
※その他はデフォルトでOK
作成した PUT メソッドから 統合リクエスト の [編集] をクリック。

URL パスパラメータ に以下を入力し [保存] をクリック。
| 名前 | マッピング先 |
|---|---|
| bucket | 'YOUR_BUCKET_NAME' ※バケット名は '' で囲う |
| key | method.request.path.proxy |

bucket は常に指定した S3 バケットへアップロードするため、固定値を設定し、key は {proxy} リソースで受け取った URL のパス部分をそのまま S3 のオブジェクトキーとして利用。
Content-Type の設定
API Gateway から S3 へ直接ファイルをアップロードする場合、リクエストヘッダーの Content-Type は自動では S3 に引き継がれません。
そのため、この設定を行わないと、S3 に保存されるオブジェクトの
Content-Type が以下のようになります。
application/octet-stream
これは「不明なバイナリデータ」を意味するため、次のような問題が発生します。
- ブラウザで画像を開いても ダウンロード扱い になる
- CloudFront 経由で配信した際に 正しい MIME タイプとならない
- 将来的に Web 表示・配信用途で不具合が出る
そのため、本手順では API Gateway の 統合リクエスト にてクライアントから送信された Content-Type ヘッダーを、そのまま S3 に転送する設定を行います。
これにより、以下のように S3 オブジェクトへ正しいメタデータが設定されます。
| アップロードファイル | S3 上の Content-Type |
|---|---|
| JPEG 画像 | image/jpeg |
| PNG 画像 | image/png |
| application/pdf |
「HTTP リクエストヘッダー」 に Content-Type を入力し [保存] をクリック。

「URL リクエストヘッダーのパラメータ」 で以下を入力し [保存] をクリック。
| 名前 | マッピング先 |
|---|---|
| Content-Type | method.request.header.Content-Type |
API Gateway デプロイ
Deploy API で ステージ は 新しいステージ を指定し、ステージ名に v1 (任意) と入力し [デプロイ] をクリックします。

画像アップロード
今回は curl コマンドを使ってアップロードを行います。
まずは ステージ よりアップロード先となる URL を確認します。

確認ができたら以下のコマンドでアップロードを行います。
% curl -X PUT \
"https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/v1/sample.jpg" \
-H "Content-Type: image/jpeg" \
--data-binary @sample.jpg
正常に実行が完了すると、S3 バケットにファイルがアップロードされています。

おわりに
今回で API Gateway を使ってファイルアップロードができるようになりました。
ただ、これは基本的な部分なので、CORS 対応やその他のメソッドの設定など色々と試していきたいと思います。
参考









