From e33b82bc672af128f5541d8e6a87ff7579ff0a51 Mon Sep 17 00:00:00 2001 From: Seonghyeon Cho Date: Sat, 17 Jan 2026 23:53:22 +0900 Subject: [PATCH 1/3] Add R2 example for aws-sdk-kotlin Signed-off-by: Seonghyeon Cho --- .../docs/r2/examples/aws/aws-sdk-kotlin.mdx | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 src/content/docs/r2/examples/aws/aws-sdk-kotlin.mdx diff --git a/src/content/docs/r2/examples/aws/aws-sdk-kotlin.mdx b/src/content/docs/r2/examples/aws/aws-sdk-kotlin.mdx new file mode 100644 index 000000000000000..92692dc9deca9f2 --- /dev/null +++ b/src/content/docs/r2/examples/aws/aws-sdk-kotlin.mdx @@ -0,0 +1,101 @@ +--- +title: aws-sdk-kotlin +pcx_content_type: example +--- + +import { Render } from "~/components"; + + +
+ +This example uses the [aws-sdk-kotlin](https://github.com/aws/aws-sdk-kotlin). You must pass in the R2 configuration credentials when instantiating your `S3` client: + +## Basic Usage + +```kotlin +import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider +import aws.sdk.kotlin.services.s3.S3Client +import aws.sdk.kotlin.services.s3.listObjects +import aws.sdk.kotlin.services.s3.model.GetObjectRequest +import aws.sdk.kotlin.services.s3.model.PutObjectRequest +import aws.sdk.kotlin.services.s3.presigners.presignGetObject +import aws.sdk.kotlin.services.s3.presigners.presignPutObject +import aws.smithy.kotlin.runtime.auth.awscredentials.Credentials +import aws.smithy.kotlin.runtime.net.url.Url +import kotlinx.coroutines.runBlocking +import kotlin.time.Duration.Companion.minutes + +val ACCOUNT_ID = "" +val ACCESS_KEY = "" +val SECRET_KEY = "" + +fun main() = runBlocking { + val r2Client = S3Client.fromEnvironment { + region = "auto" // Required by SDK, but not used by R2 + endpointUrl = Url.parse("https://${ACCOUNT_ID}.r2.cloudflarestorage.com") + credentialsProvider = StaticCredentialsProvider( + Credentials( + accessKeyId = ACCESS_KEY, + secretAccessKey = SECRET_KEY + ), + ) + } + + println("Available buckets:") + r2Client.listBuckets().buckets?.forEach { bucket -> + println("* ${bucket.name}") + } + + val bucketName = "" + println("\nObjects in bucket '${bucketName}':") + r2Client.listObjects { bucket = bucketName }.contents?.forEach { + println("* ${it.key} (size: ${it.size} bytes, modified: ${it.lastModified})") + } +} +``` + +```sh output +Available buckets: +* my-bucket-1 +* my-bucket-2 + +Objects in bucket 'my-bucket-1': +* image1.png (size: 253167 bytes, modified: 2026-01-17T11:30:58.896Z) +* image2.png (size: 247027 bytes, modified: 2026-01-17T11:30:57.779Z) +``` + +## Generate presigned URLs + +You can also generate presigned links that can be used to temporarily share public read or write access to a bucket. + +```kotlin +val uploadUrl = r2Client.presignPutObject( + input = PutObjectRequest { + bucket = bucketName + key = "README.md" + }, + duration = 15.minutes, +).url +println(uploadUrl) + +val getUrl = r2Client.presignGetObject( + input = GetObjectRequest { + bucket = bucketName + key = "README.md" + }, + duration = 15.minutes, +).url +println(getUrl) +``` + +You can use these presigned URLs with any HTTP client. For example, to upload a file using the PUT URL: + +```bash +curl -X PUT "https://" -H "Content-Type: application/octet-stream" --data-binary "@local-file.txt" +``` + +To download a file using the GET URL: + +```bash +curl -X GET "https://" -o downloaded-file.txt +``` From 400de6b6ff604ee86a0fb85a676bb89190aa37ed Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Wed, 28 Jan 2026 11:27:09 +0000 Subject: [PATCH 2/3] PCX: AI Review of code example --- .../docs/r2/examples/aws/aws-sdk-kotlin.mdx | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/content/docs/r2/examples/aws/aws-sdk-kotlin.mdx b/src/content/docs/r2/examples/aws/aws-sdk-kotlin.mdx index 92692dc9deca9f2..b1c33bef3490074 100644 --- a/src/content/docs/r2/examples/aws/aws-sdk-kotlin.mdx +++ b/src/content/docs/r2/examples/aws/aws-sdk-kotlin.mdx @@ -26,30 +26,30 @@ import kotlinx.coroutines.runBlocking import kotlin.time.Duration.Companion.minutes val ACCOUNT_ID = "" -val ACCESS_KEY = "" -val SECRET_KEY = "" +val ACCESS_KEY_ID = "" +val SECRET_ACCESS_KEY = "" fun main() = runBlocking { - val r2Client = S3Client.fromEnvironment { + S3Client.fromEnvironment { region = "auto" // Required by SDK, but not used by R2 endpointUrl = Url.parse("https://${ACCOUNT_ID}.r2.cloudflarestorage.com") credentialsProvider = StaticCredentialsProvider( Credentials( - accessKeyId = ACCESS_KEY, - secretAccessKey = SECRET_KEY + accessKeyId = ACCESS_KEY_ID, + secretAccessKey = SECRET_ACCESS_KEY ), ) - } - - println("Available buckets:") - r2Client.listBuckets().buckets?.forEach { bucket -> - println("* ${bucket.name}") - } - - val bucketName = "" - println("\nObjects in bucket '${bucketName}':") - r2Client.listObjects { bucket = bucketName }.contents?.forEach { - println("* ${it.key} (size: ${it.size} bytes, modified: ${it.lastModified})") + }.use { r2Client -> + println("Available buckets:") + r2Client.listBuckets().buckets?.forEach { bucket -> + println("* ${bucket.name}") + } + + val bucketName = "" + println("\nObjects in bucket '${bucketName}':") + r2Client.listObjects { bucket = bucketName }.contents?.forEach { + println("* ${it.key} (size: ${it.size} bytes, modified: ${it.lastModified})") + } } } ``` From 1265039cb739d102bf7675a902cdaa39d0ecdff7 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Fri, 6 Feb 2026 13:09:37 +0000 Subject: [PATCH 3/3] Fix imports, use listObjectsV2, self-contain examples Co-authored-by: elithrar --- .../docs/r2/examples/aws/aws-sdk-kotlin.mdx | 73 +++++++++++++------ 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/src/content/docs/r2/examples/aws/aws-sdk-kotlin.mdx b/src/content/docs/r2/examples/aws/aws-sdk-kotlin.mdx index b1c33bef3490074..2041f9be0ced6d4 100644 --- a/src/content/docs/r2/examples/aws/aws-sdk-kotlin.mdx +++ b/src/content/docs/r2/examples/aws/aws-sdk-kotlin.mdx @@ -15,15 +15,10 @@ This example uses the [aws-sdk-kotlin](https://github.com/aws/aws-sdk-kotlin). Y ```kotlin import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider import aws.sdk.kotlin.services.s3.S3Client -import aws.sdk.kotlin.services.s3.listObjects -import aws.sdk.kotlin.services.s3.model.GetObjectRequest -import aws.sdk.kotlin.services.s3.model.PutObjectRequest -import aws.sdk.kotlin.services.s3.presigners.presignGetObject -import aws.sdk.kotlin.services.s3.presigners.presignPutObject +import aws.sdk.kotlin.services.s3.model.ListObjectsV2Request import aws.smithy.kotlin.runtime.auth.awscredentials.Credentials import aws.smithy.kotlin.runtime.net.url.Url import kotlinx.coroutines.runBlocking -import kotlin.time.Duration.Companion.minutes val ACCOUNT_ID = "" val ACCESS_KEY_ID = "" @@ -47,7 +42,7 @@ fun main() = runBlocking { val bucketName = "" println("\nObjects in bucket '${bucketName}':") - r2Client.listObjects { bucket = bucketName }.contents?.forEach { + r2Client.listObjectsV2(ListObjectsV2Request { bucket = bucketName }).contents?.forEach { println("* ${it.key} (size: ${it.size} bytes, modified: ${it.lastModified})") } } @@ -69,23 +64,53 @@ Objects in bucket 'my-bucket-1': You can also generate presigned links that can be used to temporarily share public read or write access to a bucket. ```kotlin -val uploadUrl = r2Client.presignPutObject( - input = PutObjectRequest { - bucket = bucketName - key = "README.md" - }, - duration = 15.minutes, -).url -println(uploadUrl) - -val getUrl = r2Client.presignGetObject( - input = GetObjectRequest { - bucket = bucketName - key = "README.md" - }, - duration = 15.minutes, -).url -println(getUrl) +import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider +import aws.sdk.kotlin.services.s3.S3Client +import aws.sdk.kotlin.services.s3.model.GetObjectRequest +import aws.sdk.kotlin.services.s3.model.PutObjectRequest +import aws.sdk.kotlin.services.s3.presigners.presignGetObject +import aws.sdk.kotlin.services.s3.presigners.presignPutObject +import aws.smithy.kotlin.runtime.auth.awscredentials.Credentials +import aws.smithy.kotlin.runtime.net.url.Url +import kotlinx.coroutines.runBlocking +import kotlin.time.Duration.Companion.minutes + +val ACCOUNT_ID = "" +val ACCESS_KEY_ID = "" +val SECRET_ACCESS_KEY = "" + +fun main() = runBlocking { + S3Client.fromEnvironment { + region = "auto" // Required by SDK, but not used by R2 + endpointUrl = Url.parse("https://${ACCOUNT_ID}.r2.cloudflarestorage.com") + credentialsProvider = StaticCredentialsProvider( + Credentials( + accessKeyId = ACCESS_KEY_ID, + secretAccessKey = SECRET_ACCESS_KEY + ), + ) + }.use { r2Client -> + val bucketName = "" + + val uploadUrl = r2Client.presignPutObject( + input = PutObjectRequest { + bucket = bucketName + key = "README.md" + }, + duration = 15.minutes, + ).url + println(uploadUrl) + + val getUrl = r2Client.presignGetObject( + input = GetObjectRequest { + bucket = bucketName + key = "README.md" + }, + duration = 15.minutes, + ).url + println(getUrl) + } +} ``` You can use these presigned URLs with any HTTP client. For example, to upload a file using the PUT URL: