🐣

AWSのAPI Gatewayを使用してS3にファイルをアップロード

2024/10/05に公開

AWSのAPI GatewayとS3を使用してサーバレスでS3にファイルをアップロードする方法です。

基本的に、AWSのナレッジにあるAPI ゲートウェイを使用して Amazon S3 に画像や PDF ファイルをアップロードするには、どうすればよいですか?をベースに記載しています。

1. 保存先S3バケットの作成

S3で保存先に使用するバケットを作成します。

2. IAMでポリシーを作成

作成したバケットにPUTのみを行うために、ポリシーを作成します。

ポリシーの作成画面のサービスで「S3」を選択します

アクセスレベルの書き込みから「PutObject」を選択します

リソースの「ARNを追加」をクリックします

バケットネームに作成したS3のバケット名を入力し、任意のobject nameにチェックをつけて「ARNを追加」をクリックします

「次へ」をクリックします

ポリシー名を入力し、「ポリシーの作成」をクリックします

3. ロールの作成

API Gatewayにアタッチするためのロールを作成します。

ユースケースでAPI Gatewayを選択して「次へ」をクリックします

「次へ」をクリックします

ロール名を入力し、「ロールを作成」をクリックします

「ロールを表示」をクリックします

許可を追加の「ポリシーをアタッチ」をクリックします

作成したポリシーを選択して「許可を追加」をクリックします

4. API Gatewayの作成

REST APIの「構築」をクリックします

API名を入力して「APIを作成」をクリックします

「リソースを作成」をクリックします

リソース名に「{object}」を入力して「リソースを作成」をクリックします

「メソッドを作成」をクリックします

メソッドタイプからHTTPメソッドまでをセット

メソッドタイプ PUT
統合タイプ AWSのサービス
AWSリージョン ap-northeast-1
AWSのサービス Simple Storage Service (S3)
AWSサブドメイン
HTTPメソッド PUT

アクションタイプから実行ロールまでをセットして「メソッドを作成」をクリックします

アクションタイプ パスオーバーライドを使用
パスオーバーライド 作成したバケット名/{object}
実行ロール 作成した実行ロール

統合リクエストをクリックして、統合リクエストの設定の「編集」をクリックします

URLパスパラメータの「パスパラメータを追加」をクリックします

名前とマッピング元をセットして「保存」をクリックします

名前 マッピング元
object method.request.path.object

「/{object}」を選択して、「CORSを有効にする」をクリックします

Access-Control-Allow-Methodsの「PUT」と「Access-Control-Allow-Credentials」にチェックをつけて「保存」をクリックします

「API」の設定をクリックします

バイナリメディアタイプの「メディアタイプを管理」をクリックします

「バイナリメディアタイプを追加」をクリックします

アップロードしたいファイルのメディアタイプを入力し、「変更を保存」をクリックします

「APIをデプロイ」をクリックします

ステージ名を入力して「デプロイ」をクリックします

デプロイが完了すると、URLが表示されます

APIの動作確認

PostmanなどでPUTリクエストを送信してファイルがアップロードできているかチェックします。

URLの後ろにファイル名をセットし、ボディにバイナリ形式でファイルを指定し、PUTリクエストを送信します

S3にアップロードしたファイルが存在し、ダウンロードして正常に表示されると成功です

フロント側からファイルをアップロードするためのサンプルコード

S3とCloudFrontなどで静的ページをホストしているページにファイルアップロード処理が必要になることがあるかと思うため、HTMLとJavaScriptで動作するサンプルコードを記載します

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ファイルアップロード</title>
</head>

<body>
    <div>
        <input type="file" id="file-input">
    </div>
    <div><button onclick="fileUpload()">アップロード</button></div>
</body>

<script src="https://unpkg.com/axios@1.6.7/dist/axios.min.js"></script>
<script>
    // アップロードAPI エンドポイント
    const ENDPOINT = "https://lx0xr5t60k.execute-api.ap-northeast-1.amazonaws.com/develop"

    /** 
     * ファイルアップロード処理
     */
    const fileUpload = async () => {
        try {
            // input要素の取得
            const fileInput = document.getElementById("file-input");

            if (fileInput.files[0] === undefined) {
                throw "ファイル未選択"
            }
            // ファイル名
            const fileName = fileInput.files[0].name
            // コンテンツタイプ
            const contentType = fileInput.files[0].type

            const reader = new FileReader();
            // Fileをバイナリに変換
            reader.readAsArrayBuffer(fileInput.files[0]);
            await new Promise((resolve) => (reader.onload = () => resolve()));

            // アップロード
            await axios.put(
                `${ENDPOINT}/${fileName}`,
                reader.result,
                {
                    headers: {
                        "Content-Type": contentType
                    }
                }
            );

            alert("アップロード完了")
        } catch (error) {
            alert(error)
        }
    }
</script>

</html>

Discussion