Skip to main content

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" }));