ASW SDK for Wasabi Cloud Storage (S3) - Quick Reference

21-Jul-2023

Generic badge

aws-sdk-2.x is not the current version of node.js AWS client. But at the time I write this article, many S3 providers except aws are only supporting aws-sdk-2.

DO NOT USE aws-sdk-2.x IN AWS. USE NEWER VERSION OF AWS SDK

Installation
npm i aws-sdk
import { Credentials } from "aws-sdk";
import S3 from "aws-sdk/clients/s3";
import { Stream } from "stream";
S3 Client

Here S3 client is configured for wasabi cloud storage

const s3Client = new S3({
  region: "ap-southeast-1",
  endpoint: "s3.ap-southeast-1.wasabisys.com",
  sslEnabled: true,
  signatureVersion: "v4",
  s3ForcePathStyle: false,
  credentials: new Credentials({
    accessKeyId: process.env.ACCESS_KEY,
    secretAccessKey: process.env.SECRET_KEY,
  }),
});
Upload File
function Upload(fileStream: Stream, fileName: string) {
  const params = {
    Bucket: <BUCKET>,
    Key: fileName,
    Body: fileStream,
    ACL: "public-read",
    ContentEncoding: "base64",
    ContentType: "image/png",
    prefix: "img",
  };
  const { Location } = await s3Client.upload(params).promise();
  return Location;
}

Valid ACL: private | public-read | public-read-write | authenticated-read | aws-exec-read | bucket-owner-read | bucket-owner-full-control

Presigned Get URL
async function PresignedPutUrl(file: string) {
  const params = {
    Bucket: <BUCKET>,
    Key: file,
    Expires: 300, //5 x 60 = 300 seconds (5 minutes)
  };
  return await s3Client.getSignedUrl("getObject", params);
}
Presigned Put URL

Presigned put url is used to upload file from client/browser side.

async function PresignedPutUrl(file: string) {
  const params = {
    Bucket: <BUCKET>,
    Key: file,
    ACL: "public-read",
    ContentType: "image/png",
    Expires: 300,
  };
  return await s3Client.getSignedUrl("putObject", params);
}

To upload file PUT request has to be made with ContentType and ACL header from the client. Here is an axios example.

axios.put(signedurl, file, {
  headers: {
    "Content-Type": "image/png",
    "x-amz-acl": "public-read",
  },
});
Delete
async function Delete(key: string) {
  const params = {
    Bucket: <BUCKET>,
    Key: key,
  };
  try {
    await s3Client.deleteObject(params).promise();
  } catch (error) {
    console.log("[Wasabi error]", error);
    throw error;
  }
}
Delete Directory
async function DeleteDirectory(dir:string){
  const Bucket = <BUCKET>;
  const listParams = {
    Bucket,
    Prefix: dir,
  };

  const listedObjects = await s3Client.listObjectsV2(listParams).promise();

  if (listedObjects.Contents.length === 0) return;

  const deleteParams = {
    Bucket,
    Delete: {
      Objects: getDeleteObjects(listedObjects),
    },
  };

  await s3Client.deleteObjects(deleteParams).promise();

  if (listedObjects.IsTruncated) await DeleteDirectory(dir);
};

const getDeleteObjects = (list) => {
  return list.Contents.map((i) => ({ Key: i.Key }));
};
Download to server
import path from "path";
import fs from "fs";

async function Download(Key) {
  const params = {
    Bucket: <BUCKET>,
    Key,
  };
  try {
    const data = await s3Client.getObject(params).promise();
    const file = path.join("path", "to", "save", "file");
    await fs.writeFileSync(file, data.Body);
    return file;
  } catch (error) {
    throw err;
  }
}