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/