この記事はAmplify Functionから、Amplify Storageのファイルを操作する方法を共有するためのものです。
この記事では、JavaScriptベースのWebアプリケーションを対象とします。モバイルアプリケーションは対象としません。
必須となるnpmモジュールは以下の通りです。
▼package.json
"dependencies": {
"aws-amplify": "^3.3.6"
}
この記事では2020/12/04時点でのAmplifyを前提にしています。Amplifyは活発に開発が行われているため、導入手順が大きく変更されている場合があります。記事を読む前に、お手元の環境を確認してください。
FunctionにStorageへのアクセス権限を設定すれば、FunctionのLambda関数内からS3ストレージとして読み書きできます。しかしAmplifyが設定するアクセス権限に制限があるため、一部の命令は実行できません。
まず、今回の記事で対象となる各サービスを解説します。
Amplifyとは、モバイル/Webアプリケーションの開発に必要なAWSサービスのパッケージです。アプリケーションに必要となるAPI/ユーザー認証/ホスティング/ユーザー分析…といった機能がパッケージされています。
Amplify Functionはサーバーレスでプログラムを実行するサービスです。AWS EC2のように仮想マシンが立ち上がっているわけではありません。何らかのトリガーによって呼び出された時だけ、事前に設定したプログラムが動きます。
FunctionサービスはAWS Lambdaで構成されています。
Amplify Storageはアプリケーションに統合されたオンラインストレージです。データベースには向かないメディアファイルを格納できます。たとえばユーザーがアップロードした写真を任意のユーザーにシェアするといった使い方ができます。
StorageサービスはAmazon S3で構成されています。
Amplify FunctionとStorageを連携させる手順を解説します。amplify init
コマンドを実行し、空のAmplifyアプリケーションが作成されている時点から手順を開始します。
amplify add storage
コマンドで新規ストレージを追加します。サービスの種類はコンテンツを選びます。
% amplify add storage
? Please select from one of the below mentioned services: Content (Images, audio, video, etc.)
? You need to add auth (Amazon Cognito) to your project in order to add storage for user files. Do you want to add auth now? Yes
StorageにはAuthサービスが必須なので、まだセットアップされていない場合はAmplifyから追加を求められます。
Using service: Cognito, provided by: awscloudformation
The current configured provider is Amazon Cognito.
Do you want to use the default authentication and security configuration? Default configuration
Warning: you will not be able to edit these selections.
How do you want users to be able to sign in? Email
Do you want to configure advanced settings? No, I am done.
Successfully added auth resource <Auth名> locally
Some next steps:
"amplify push" will build all your local backend resources and provision it in the cloud
"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud
Authのセットアップが完了すると、そのままStorageの作成が続きます。
? Please provide a friendly name for your resource that will be used to label this category in the project: <ストレージ名>
? Please provide bucket name: <S3バケット名>
? Who should have access: Auth users only
? What kind of access do you want for Authenticated users? create/update, read, delete
? Do you want to add a Lambda Trigger for your S3 Bucket? No
Successfully added resource <ストレージ名> locally
If a user is part of a user pool group, run "amplify update storage" to enable IAM group policies for CRUD operations
Some next steps:
"amplify push" builds all of your local backend resources and provisions them in the cloud
"amplify publish" builds all of your local backend and front-end resources (if you added hosting category) and provisions them in the cloud
まずamplify add function
コマンドで、Functionを追加します。
▼ログ
$ amplify add function
Scanning for plugins...
Plugin scan successful
? Select which capability you want to add: Lambda function (serverless function)
? Provide an AWS Lambda function name: <任意のFunction名>
? Choose the runtime that you want to use: NodeJS
? Choose the function template that you want to use: Hello World
Available advanced settings:
- Resource access permissions
- Scheduled recurring invocation
- Lambda layers configuration
? Do you want to configure advanced settings? Yes
? Do you want to access other resources in this project from your Lambda function? Yes
? Select the category storage
? Storage has 5 resources in this project. Select the one you would like your Lambda to access
❯◉ <ストレージ名>
^^^^^^^^^^^^^^^^^^^
? Do you want to configure advanced settings?
(詳細設定をしますか?)でYes
を選択します。アクセス権限の追加について聞かれますので、操作したいバケットへのアクセスを許可します。
❗下線で強調した部分は複数選択可能なチェックボックスです。スペースキーで選択、リターンで決定という操作方法です。なにもチェックを行わないままリターンを押すと操作がキャンセルされたと解釈して処理が進みます。ご注意ください。
Functionのindex.jsにS3バケット名を格納した環境変数が追加されます。STORAGE_<ストレージ名>_BUCKETNAME
がバケット名です。
▼amplify/backend/function/"Function名"/src/index.js
/* Amplify Params - DO NOT EDIT
ENV
REGION
STORAGE_<ストレージ名>_BUCKETNAME
Amplify Params - DO NOT EDIT */
既存のFunctionにStorageへのアクセス権限を追加する場合はamplify update function
コマンドを使います。Function一覧が表示されますので、その中から権限を追加するFunctionを選択してください。
Functionを実装します。
▼amplify/backend/function/"Function名"/src/index.js
/* Amplify Params - DO NOT EDIT
ENV
REGION
STORAGE_<ストレージ名>_BUCKETNAME
Amplify Params - DO NOT EDIT */
const AWS = require("aws-sdk");
const s3 = new AWS.S3();
/**
* Storageにオブジェクトを追加する。
* @return {Promise<*>}
*/
const putObjectToStorage = async () => {
const testObj = {
test: "test string",
};
return await s3
.putObject({
Bucket: process.env.STORAGE_<ストレージ名>_BUCKETNAME,
Key: "file.json",
Body: JSON.stringify(testObj),
ContentType: "application/json",
})
.promise();
};
exports.handler = async (event) => {
const result = await putObjectToStorage();
const response = {
statusCode: 200,
body: JSON.stringify(result),
};
return response;
};
レスポンスに、生成されたS3オブジェクトのエンティティタグが出力されれば成功です。
Amplifyによって生成されるLambda用IAMロールは以下のようになります。
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:ListBucket",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::<バケット名>/*"
],
"Effect": "Allow"
}
]
}
このロールで許可されない処理は実行できません。
Functionに割り当てられる権限には、ACLの操作権限がありません。そのためPutObjectAclのようなACL操作を伴う処理はできません。
2020/12/13現在、FunctionからStorageバケットのオブジェクトリストを取得できません。Functionへの権限割り当てに問題があるようです。 参考 : Issue #5528
以上、ありがとうございました。