serverless framework でS3バケットの作成・操作をする
概要
serverless frameworkでS3バケットを作成し、画像を登録・取得します。 リクエストにはfetchAPIを利用しました。
実装
今回の実装内容はgithubにも載せてありますのでご参考までに。 https://github.com/naok1207/serverless-framework-s3-tryal
流れ
- S3バケットを作成する
- 画像アップロード関数を作成する
- 画像アップロードをfetchAPIで行う
- 画像取得関数を作成する
- 画像取得をfetchAPIで行う
serverless.ymlの事前設定
provider:
...
httpApi:
cors:
allowedOrigins:
- "*" # 指定しないとcorsエラーとなる任意の値を設定
handler.jsの事前設定
import {
S3Client,
PutObjectCommand,
GetObjectCommand,
} from "@aws-sdk/client-s3";
const client = new S3Client({});
const response = (statusCode, success, params) => {
return {
statusCode,
body: JSON.stringify({
success,
...params,
}),
};
};
export const upload = async (event, context, callback) => {}
export const getImage = async (event, context, callback) => {}
index.jsの事前設定
// lambda関数のエンドポイント
const baseUrl = "";
function onUpload() {}
function onGet() {}
1. S3バケットを作成する
providerにS3の操作権限とlambda関数とresourcesで使用する環境変数を設定
provider:
...
iamRoleStatements:
- Effect: "Allow"
Action:
- "s3:ListBucket"
- "s3:GetObject"
- "s3:PutObject"
- "s3:DeleteObject"
Resource:
- "*"
environment:
BUCKET: ${self:service}-${self:provider.stage}
resourcesにS3バケットを作成する設定を追加
resources:
Resources:
Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: ${self:provider.environment.BUCKET} # 任意の名前
2. 画像アップロード関数を作成する
handler.jsのupload関数を書き換える
PutObjectCommandを利用して画像の登録を行います。
export const upload = async (event, context, callback) => {
const { base64_image, key } = JSON.parse(event.body);
try {
const base64 = base64_image.replace(/data:.+;base64,/, "");
// ファイルの拡張子を取得
const fileExtension = base64_image
.toString()
.slice(base64_image.indexOf("/") + 1, base64_image.indexOf(";"));
// ContentType(image/png)を取得
const contentType = base64_image
.toString()
.slice(base64_image.indexOf(":") + 1, base64_image.indexOf(";"));
const imageBuf = Buffer.from(base64, "base64");
const bucketParams = {
Bucket: process.env.BUCKET,
Key: [key, fileExtension].join("."),
Body: imageBuf,
ContentType: contentType,
};
const result = await client.send(new PutObjectCommand(bucketParams));
console.log(result);
return response(200, true, { message: "file saved to S3" });
} catch (err) {
console.error(err);
return response(500, false, { message: "Error saving file to S3" });
}
};
3. 画像アップロードをfetchAPIで行う
function onUpload() {
console.log("onclick");
const inputElement = document.getElementById("image");
const keyElement = document.getElementById("key");
const file = inputElement.files[0];
const reader = new FileReader();
reader.onload = (event) => {
const base64 = event.currentTarget.result;
const body = {
base64_image: base64,
key: keyElement.value,
};
fetch(baseUrl + "/upload", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
})
.then((res) => res.json())
.then((json) => console.log(json))
.catch((err) => {
console.error(err);
});
};
reader.readAsDataURL(file);
}
4. 画像取得関数を作成する
export const getImage = async (event, context, callback) => {
const { key } = event.queryStringParameters;
try {
const bucketParams = {
Bucket: process.env.BUCKET,
Key: key,
};
console.log({ bucketParams });
const data = await client.send(new GetObjectCommand(bucketParams));
const objectData = data.Body;
const base64Data = await objectData.transformToString("base64");
const contentType = data.ContentType;
const body = {
base64Data,
contentType,
};
return response(200, true, {
message: "Success to get file from S3",
...body,
});
} catch (err) {
console.log(err);
return response(500, false, { message: "Error get file from S3" });
}
};
5. 画像取得をfetchAPIで行う
function onGet() {
const keyElement = document.getElementById("show-key");
const ImageElement = document.getElementById("show-image");
fetch(baseUrl + "/get?key=" + keyElement.value)
.then((res) => res.json())
.then((json) => {
const { base64Data, contentType } = json;
const dataUrl = `data:${contentType};base64,${base64Data}`;
ImageElement.src = dataUrl;
})
.catch((err) => console.error(err));
}
以上でlambda関数を利用してのS3への画像の登録と取得の実装が終了です。
こちらの内容にcognito authorizerを組み合わせてユーザー毎のkeyを作成したりするとまたいろいろできそうですね。
また、今回はaws-sdkではなく@aws-sdk/s3-clientを利用しました。書き方は若干異なりますが、やることはほとんど同じなので特に問題なく実装できました。
感想
作成する際にcorsに結構ハマってしまいました。serverless frameworkのApiGateway2ではoriginがデフォルトで * に設定されていると思っていましたが、そんなこともないようで、明示的にcorsの設定を行わないとダメなようでした。
会社の紹介
株式会社 mofmof では一緒に働いてくれるエンジニアを募集しています。 興味のある方は是非こちらのページよりお越しください! https://www.mof-mof.co.jp/ https://www.mof-mof.co.jp/recruit/