リポジトリに置きたくない、StreamingAssetsに配置するデータとか、ビルド時の中間処理用の定義ファイルだったりとか、S3においといて、環境非依存で使えるようにする、、というのはわりとやりたい人多いと思う。
今回それを実装したので、自分が忘れたときようにメモ。
実装について
やり方は色々あるだろうけど、
- awscliは使えないので、システムコールで誤魔化すのは無理
- AWS SDKを組み込むのは 嫌だ
という前提のもと、
- APIGateway + S3 で配信側を作って、HttpClient でダウンロード
という汎用的な実装で解決を図った。構成としてはこういう感じ。
AWS側の設定のハマりどころ
S3のバイナリデータをAPIGatewayで単純に返すのって、意外と分かりやすい例がなくて、ハマった。
失敗例は書くと際限がないので、成功例の最低限の設定項目を列挙しておく。
グローバル > 設定 > バイナリメディアタイプ
- 必要なタイプを列挙、、すると不毛なので、Internal用途で荒れば、割り切って "/" と書いておくのが吉。
リソース
- GETクエリを設定
- パスパラメータを使おうと思ったが、それやると、多段パスの引数取りたいときにメンドくさいことになるので、RootにGETを設定して、S3のリソース指定は全てクエリでセットする方針で
リソース > GET > メソッドリクエスト
- APIキー
- 専用のものを用意するのが無難
- リクエストの検証
- "クエリ文字列パラメータおよびヘッダーの検証"
- URLクエリ文字列パラメータ
- accept | 必須 => Clientは "/" を指定
- bucket | 必須 => Clientは Bucket名を指定
- item | 必須 => Clientは ObjectのPathを指定
リソース > GET > 総合リクエスト
- 統合タイプ
- "AWSサービス"
- AWSリージョン
- 一番近いところを指定
- AWSサービス
- "S3"
- HTTPメソッド
- GET
- パス上書き
- {bucket}/{item}
- 実行ロール
- S3/CloudFront のRead権限を付与したロールを設定
- コンテンツの処理
- パススルー
- デフォルトタイムアウトの使用
- On(Offにして手動設定しても、どうせデフォルト値の29秒よりは大きくできない)
- URLパスパラメータ
- item | method.request.querystring.item
- bucket | method.request.querystring.bucket
- HTTPヘッダー
- Accept | method.request.querystring.accept
リソース > GET > メソッドレスポンス
- HTTPのステータス > 200 のレスポンス本文 > コンテンツタイプ
- application/octet-stream
- HTTPのステータス
- 400, 500 をそれぞれ追加(内容は未設定で良い)
リソース > GET > 総合レスポンス
素の状態だとエラーでも200が返って、クライアントのエラー処理がめんどくさいことになるので、エラーコードをS3 Integrationが返してきた時用に、エラーコードをMappingする。
これにより、存在しないファイルを指定した時や、APIKeyミスった場合にエラーがちゃんとかえるようになる。
- 設定追加(正規表現の記法に注意)
- 4\d{2} | 400 | パススルー
- 5\d{2} | 500 | パススルー
本当は、Serverless Frameworkで定義しておきたかったけど、S3 Integration ないみたいなので断念。
Terraformは定義量が尋常ではなくなるので、論外。(やりたいことに対するコストが見合わない)