AWS SDK Examples

These examples show complete workflows using AWS SDKs with Oyster's S3-compatible API. For initial SDK setup, see S3 setup.

Python (boto3)

Setup

import boto3

s3 = boto3.client(
    "s3",
    endpoint_url="http://localhost:3000",
    aws_access_key_id="OYAK1234567890ABCDEF",
    aws_secret_access_key="abcdef1234567890abcdef1234567890abcdef12",
    region_name="us-east-1",
)

Create a bucket

s3.create_bucket(Bucket="my-bucket")

Upload a file

# From a file on disk
s3.upload_file("photo.png", "my-bucket", "images/photo.png")

# From a string
s3.put_object(
    Bucket="my-bucket",
    Key="hello.txt",
    Body=b"Hello, Oyster!",
    ContentType="text/plain",
)

Download a file

# To a file on disk
s3.download_file("my-bucket", "hello.txt", "downloaded.txt")

# To memory
response = s3.get_object(Bucket="my-bucket", Key="hello.txt")
content = response["Body"].read()
print(content.decode())  # "Hello, Oyster!"

List objects

# List all objects
response = s3.list_objects_v2(Bucket="my-bucket")
for obj in response.get("Contents", []):
    print(f"{obj['Key']}  {obj['Size']} bytes")

# List with prefix (simulate folder listing)
response = s3.list_objects_v2(
    Bucket="my-bucket",
    Prefix="images/",
    Delimiter="/",
)

# Files directly in "images/"
for obj in response.get("Contents", []):
    print(f"  File: {obj['Key']}")

# "Subfolders" in "images/"
for prefix in response.get("CommonPrefixes", []):
    print(f"  Folder: {prefix['Prefix']}")

Paginate through large listings

paginator = s3.get_paginator("list_objects_v2")
for page in paginator.paginate(Bucket="my-bucket", MaxKeys=100):
    for obj in page.get("Contents", []):
        print(obj["Key"])

Delete an object

s3.delete_object(Bucket="my-bucket", Key="hello.txt")

Delete a bucket

s3.delete_bucket(Bucket="my-bucket")

Check if an object exists

try:
    s3.head_object(Bucket="my-bucket", Key="hello.txt")
    print("Object exists")
except s3.exceptions.ClientError as e:
    if e.response["Error"]["Code"] == "404":
        print("Object not found")
    else:
        raise

Conditional requests

Use If-Match and If-None-Match headers for safe writes and cache validation:

# Create-only: fail if the key already exists
try:
    s3.put_object(
        Bucket="my-bucket",
        Key="config.json",
        Body=b'{"version": 1}',
        IfNoneMatch="*",
    )
except s3.exceptions.ClientError as e:
    if e.response["Error"]["Code"] == "PreconditionFailed":
        print("Key already exists — not overwritten")
    else:
        raise

# Safe overwrite: only update if the ETag matches
response = s3.head_object(Bucket="my-bucket", Key="config.json")
current_etag = response["ETag"]

s3.put_object(
    Bucket="my-bucket",
    Key="config.json",
    Body=b'{"version": 2}',
    IfMatch=current_etag,
)

# Cache validation: skip download if unchanged
try:
    s3.get_object(
        Bucket="my-bucket",
        Key="config.json",
        IfNoneMatch=current_etag,
    )
except s3.exceptions.ClientError as e:
    if e.response["Error"]["Code"] == "304":
        print("Not modified — use cached copy")
    else:
        raise

Full workflow

import boto3

s3 = boto3.client(
    "s3",
    endpoint_url="http://localhost:3000",
    aws_access_key_id="OYAK1234567890ABCDEF",
    aws_secret_access_key="abcdef1234567890...",
    region_name="us-east-1",
)

# Create bucket
s3.create_bucket(Bucket="demo")

# Upload
s3.put_object(Bucket="demo", Key="doc.txt", Body=b"Hello!")
s3.put_object(Bucket="demo", Key="images/a.png", Body=b"\x89PNG...")
s3.put_object(Bucket="demo", Key="images/b.png", Body=b"\x89PNG...")

# List with folder simulation
resp = s3.list_objects_v2(Bucket="demo", Delimiter="/")
print("Root files:", [o["Key"] for o in resp.get("Contents", [])])
print("Folders:", [p["Prefix"] for p in resp.get("CommonPrefixes", [])])
# Root files: ['doc.txt']
# Folders: ['images/']

# Download
obj = s3.get_object(Bucket="demo", Key="doc.txt")
print(obj["Body"].read().decode())  # "Hello!"

# Clean up
s3.delete_object(Bucket="demo", Key="doc.txt")
s3.delete_object(Bucket="demo", Key="images/a.png")
s3.delete_object(Bucket="demo", Key="images/b.png")
s3.delete_bucket(Bucket="demo")

JavaScript / TypeScript (AWS SDK v3)

Setup

import {
  S3Client,
  CreateBucketCommand,
  PutObjectCommand,
  GetObjectCommand,
  HeadObjectCommand,
  ListObjectsV2Command,
  DeleteObjectCommand,
  DeleteBucketCommand,
} from "@aws-sdk/client-s3";

const client = new S3Client({
  endpoint: "http://localhost:3000",
  region: "us-east-1",
  credentials: {
    accessKeyId: "OYAK1234567890ABCDEF",
    secretAccessKey: "abcdef1234567890abcdef1234567890abcdef12",
  },
  forcePathStyle: true,
});

Create a bucket

await client.send(new CreateBucketCommand({ Bucket: "my-bucket" }));

Upload an object

await client.send(
  new PutObjectCommand({
    Bucket: "my-bucket",
    Key: "hello.txt",
    Body: "Hello, Oyster!",
    ContentType: "text/plain",
  })
);

Upload a file from disk (Node.js)

import { createReadStream } from "fs";

await client.send(
  new PutObjectCommand({
    Bucket: "my-bucket",
    Key: "images/photo.png",
    Body: createReadStream("photo.png"),
    ContentType: "image/png",
  })
);

Download an object

const response = await client.send(
  new GetObjectCommand({
    Bucket: "my-bucket",
    Key: "hello.txt",
  })
);

const body = await response.Body.transformToString();
console.log(body); // "Hello, Oyster!"

List objects

const response = await client.send(
  new ListObjectsV2Command({
    Bucket: "my-bucket",
    Prefix: "images/",
    Delimiter: "/",
  })
);

for (const obj of response.Contents ?? []) {
  console.log(`File: ${obj.Key} (${obj.Size} bytes)`);
}

for (const prefix of response.CommonPrefixes ?? []) {
  console.log(`Folder: ${prefix.Prefix}`);
}

Delete an object

await client.send(
  new DeleteObjectCommand({
    Bucket: "my-bucket",
    Key: "hello.txt",
  })
);

Check if an object exists

try {
  await client.send(
    new HeadObjectCommand({
      Bucket: "my-bucket",
      Key: "hello.txt",
    })
  );
  console.log("Object exists");
} catch (err) {
  if (err.name === "NotFound") {
    console.log("Object not found");
  } else {
    throw err;
  }
}

Conditional requests

Use IfMatch and IfNoneMatch parameters for safe writes and cache validation:

// Create-only: fail if the key already exists
try {
  await client.send(
    new PutObjectCommand({
      Bucket: "my-bucket",
      Key: "config.json",
      Body: JSON.stringify({ version: 1 }),
      IfNoneMatch: "*",
    })
  );
} catch (err) {
  if (err.name === "PreconditionFailed") {
    console.log("Key already exists — not overwritten");
  } else {
    throw err;
  }
}

// Safe overwrite: only update if the ETag matches
const head = await client.send(
  new HeadObjectCommand({ Bucket: "my-bucket", Key: "config.json" })
);

await client.send(
  new PutObjectCommand({
    Bucket: "my-bucket",
    Key: "config.json",
    Body: JSON.stringify({ version: 2 }),
    IfMatch: head.ETag,
  })
);

Full workflow

import { S3Client, CreateBucketCommand, PutObjectCommand,
  GetObjectCommand, ListObjectsV2Command, DeleteObjectCommand,
  DeleteBucketCommand } from "@aws-sdk/client-s3";

const client = new S3Client({
  endpoint: "http://localhost:3000",
  region: "us-east-1",
  credentials: {
    accessKeyId: "OYAK1234567890ABCDEF",
    secretAccessKey: "abcdef1234567890...",
  },
  forcePathStyle: true,
});

// Create bucket
await client.send(new CreateBucketCommand({ Bucket: "demo" }));

// Upload objects
await client.send(new PutObjectCommand({
  Bucket: "demo", Key: "doc.txt", Body: "Hello!",
}));
await client.send(new PutObjectCommand({
  Bucket: "demo", Key: "images/a.png", Body: Buffer.from([0x89, 0x50]),
}));

// List with folder simulation
const list = await client.send(new ListObjectsV2Command({
  Bucket: "demo", Delimiter: "/",
}));
console.log("Files:", list.Contents?.map(o => o.Key));
console.log("Folders:", list.CommonPrefixes?.map(p => p.Prefix));

// Download
const obj = await client.send(new GetObjectCommand({
  Bucket: "demo", Key: "doc.txt",
}));
console.log(await obj.Body.transformToString()); // "Hello!"

// Clean up
await client.send(new DeleteObjectCommand({ Bucket: "demo", Key: "doc.txt" }));
await client.send(new DeleteObjectCommand({ Bucket: "demo", Key: "images/a.png" }));
await client.send(new DeleteBucketCommand({ Bucket: "demo" }));