ちょっと話題の記事

CloudFront と S3 で 配信した Angular 製 SPA から API Gateway を通してファイルアップロードする

2017.11.01

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

サーバーレスな話で以下のような構成、よく見かけます。

  • CloudFront と S3 で SPA を配信する
  • API Gateway と S3 で CRUD API を作る

よく見かけるのですが、私が知っているのは「構成」であって「実装」ではないな、ということで簡単なものを作ってみることにしました。図にすると以下のようなイメージ。

s3

簡単なストーリー

  • 各地域に投票所があり、エンドユーザーが投票する
  • 地域ごとに投票データをCSV管理しており、投票が終わったら管理者が中央ストレージへCSVファイルをアップロードする

想定読者

サーバーレス構成で CloudFront や S3 を組み合わせたサンプルを見てみたい方。

作ってみて

最初に感想を書いてしまいます。

  • CloudFront と S3 の組み合わせは強力。ドメインを持っていたら迷わず横綱構成へ持っていくべき。
  • API Gateway は思った以上にいろいろな AWS サービス と組み合わせられる。運用を考えると AWS CLI でAPI構成を変更管理できる状態が望ましい。今回はAWSコンソールで作成した。
  • 10年前の私がファイルアップロードシステムを作ろうと思ったらまずアップロード先のストレージシステムを選定してサーバーサイドは Tomcat で作ってフロントエンドはJSP触るの嫌だから別のテンプレートエンジンを…とか考えるところからスタートしてたと思います。いい時代になった。

フロント側 = Angular4 + S3 + CloudFront

Angular製SPAを作る

可能な限り省力化します。今回は認証も考慮しません。その前提で、 ng2-file-upload を使いました。ファイルアップロードの高レベルAPIを提供してくれるディレクティブで、デモページを参考にすれば簡単にファイルアップロードページを実装できます。

デモページを参考に、以下のようなページを実装しました。

vote

コードサンプルは GitHub にアップしています。実際に利用する場合は、ソースコード内、アップロード先のURLを調整してください。

$ git clone git@github.com:cm-wada-yusuke/vote.git

file-upload.component.ts

import {Component, OnInit} from '@angular/core';
import {FileItem, FileUploader} from 'ng2-file-upload';
import {FormControl, Validators} from '@angular/forms';

// const URL = '/api/';
const URL = 'https://your.file.upload.server.com/v1/vote_uploader';

@Component({
  selector: 'app-file-upload',
  templateUrl: './file-upload.component.html',
  styleUrls: ['./file-upload.component.css']
})
export class FileUploadComponent implements OnInit {
  // 後略 ...

ソースコードをビルドします。

$ cd path/to/vote-angular-project
$ ng build --prod

これで、Angular SPA の準備は完了です。早い…!

SPA配信用 S3 を用意する

簡単のために、今回は、配信元とCSVファイルアップロード先を同一バケットにしました。

vote-uploader(bucket)
├── site              # SPA 配信元
└── uploads           # CSV アップロード先(地域ごと)
    ├── chiyoda
    ├── sumida
    ├── ...

先で作った SPA ファイルを S3 にアップロードします。

$ cd dist/
$ aws s3 sync . s3://vote-uploader/site

SPAアップロード先の S3 は以下のような画面になります。デプロイ完了。

s3-site

CloudFront をたてる

Origins を以下のように設定します。

cloudfront

Origin Path/site とすることによって、ドキュメントルートの階層を変更することが可能です。

Behavior を以下の様に設定します。

cloudfront

この設定で保存し、しばらくまちます。その後、https://yourcloudfrontsubdomain.cloudfront.net/index.html へアクセスすると、アップロードした SPA へアクセスすることができます。これでフロント側は終わりです。

アップロードAPI側 = API Gateway + S3

今回はファイルアップロード機能のみ作ります。API Gateway を通して、S3 上の /vote-uploader/uploads/{地域フォルダ} へアップロードすることが目標です。いくつかポイントがあります。

  • S3をバックエンドとしたAPIを定義する
  • パスパラメータとクエリパラメータをマッピングする
  • CORS を許可する

APIの定義

まずは API Gateway のリソースを作りましょう。アクション>リソースの作成 を行って以下のように作成します。

resources

次に、PUTメソッドを作成します。バックエンドをS3とする関係上、API Gateway から S3 へのアクセスが許可されている必要があります。これを IAMポリシーのアタッチ により実現します。AWSコンソールで、API Gateway のロールを作成しましょう。

iam-apigeteway.png

API Gateway の画面に戻り、作成したリソースに対してPUTメソッドを定義します。

apigateway_path.png

パスの上書き について。このような書き方をすると、

  • 使われるバケット: vote-uploader
  • キー: uploads/{placeId}
  • オブジェクト名: {key}

という意味になります。{placeId}と{key}は、動的な値が入ることを意味します。API Gateway で受け付けたパスパラメータやクエリパラメータを、S3 へアクセスするためのパラメータに変換します。これが パスのマッピング です。

パスのマッピング

さて、PUTメソッドを作成すると、メソッドのリクエスト/レスポンスについて設定できるようになります。

apigateway_methodsettings.png

apigateway_methodsettings.png

②③の設定で、API Gateway が https"//xxx/vote_uploader/chiyoda?fileName=2017-10-31.csvといったパスを解釈してくれるようになります。②により{placeId}にはchiyodaが、③により{fileName}には2017-10-31.csvが入ります。次にこれらを S3 のパスにマッピングします。

apigateway_methodsettings.png

apigateway_methodsettings.png

  • ⑤: API Gateway のクエリパラメータ fileName を、S3パスkeyにマッピングします
  • ⑥: API Gateway のパスパラメータ placeId を、S3パスplaceIdにマッピングします

結果、https://xxx/vote_uploader/chiyoda?fileName=2017-10-31.csv というアクセスに対しては、

  • 使われるバケット: vote-uploader
  • キー: uploads/chiyoda
  • オブジェクト名: 2017-10-31.csv

と解釈されます。

CORSの許可

SPAのドメインと API Gateway のドメインは異なるため、API Gateway 側でCORSを許可する必要があります。API Gateway 管理画面、アクション>CORSの有効化 で、以下のように設定してください。

apigateway_cors.png

準備完了です。デプロイします。デプロイした後に取得できるURLが、ファイルアップロード先のURLになります。

apigateway_deploy.png

試す

フロントとサーバーどちらも用意できました。早速使ってみましょう。

use_front.png

Vote region は chiyoda 、ファイル名は 2017-10-31.csv であることがわかります。このとき、Angularで、アップロードURL https://XXXXXX.execute-api.ap-northeast-1.amazonaws.com/v1/vote_uploader/chiyoda?2017-10-31.csv が生成されるよう実装しています。アップロードされたはずですので S3 を見てみましょう。

use_server.png

ファイルがアップロードできました。

おわりに

SPAのホスティングと、ファイルアップロード先としてS3を使うことができました。S3は高可用なオンラインストレージという印象が強いですが、それだけでなく CloudFront や API Gateway と組み合わせることで、思った以上に便利だとわかりました。「静的なコンテンツを保存し、配信する」という要件に出くわしたときは、まずS3をベースにできるかどうか、検討すると良いでしょう。

今回は投票ファイルをアップロードするところまででしたが、その先、集計業務もセットで必要になることが多いと思います。集計についてもAWSを使ってやってみたいと思います。

ソースコード

参考