Boy was I happy when I read the news about the general availability of the AWS SDK for Kotlin. Finally—time to use Kotlin for my infrastructure-as-code projects.

https://aws.amazon.com/about-aws/whats-new/2023/11/aws-sdk-kotlin/

In this tutorial I follow Amazon’s guide on how to create an S3 bucket, put an object from a ByteStream into the S3 bucket, and then clean up everything using the AWS SDK for Kotlin. I had to make a few changes to the original tutorial to make it work in my development environment. All in all, it was straightforward.

Here is the general AWS SDK for Kotlin page: https://aws.amazon.com/sdk-for-kotlin/

The tutorial I followed is here: https://docs.aws.amazon.com/sdk-for-kotlin/latest/developer-guide/get-started.html

First, create a Gradle project. I kept the default settings.

% mkdir aws-cdk-kotlin
% cd aws-cdk-kotlin
% gradle init --type kotlin-application --dsl kotlin
 
Project name (default: aws-cdk-kotlin):
 
Source package (default: aws.cdk.kotlin):
 
Enter target version of Java (min. 7) (default: 21):
 
Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no]
 
> Task:init
To learn more about Gradle by exploring our Samples at https://docs.gradle.org/8.5/samples/sample_building_kotlin_applications.html
 
BUILD SUCCESSFUL in 5s
2 actionable tasks: 2 executed
%

Next, add the AWS SDK dependency.

in build.gradle.kts

...
 
dependencies {
	...
	implementation("aws.sdk.kotlin:s3:1.0.0")
}

Here is the tutorial code, slightly adapted to newer syntax:

import aws.sdk.kotlin.services.s3.S3Client
import aws.sdk.kotlin.services.s3.model.*
import aws.smithy.kotlin.runtime.content.ByteStream
import kotlinx.coroutines.runBlocking
import java.util.*
 
val REGION = "eu-central-1"
val BUCKET = "bucket-${UUID.randomUUID()}"
val KEY = "my-s3-bucket-key"
 
fun main(): Unit = runBlocking {
	S3Client.fromEnvironment { region = REGION }.use { s3 ->
		setupTutorial(s3)
 
		println("Creating object $BUCKET/$KEY...")
 
		val putObjectRequest = PutObjectRequest {
			bucket = BUCKET
			key = KEY
			body = ByteStream.fromString("Testing with the Kotlin SDK")
		}
		s3.putObject(putObjectRequest)
 
		println("Object $BUCKET/$KEY created successfully!")
		cleanUp(s3)
	}
}
 
suspend fun setupTutorial(s3: S3Client) {
	println("Creating bucket $BUCKET...")
	val createBucketRequest = CreateBucketRequest {
		bucket = BUCKET
		createBucketConfiguration {
			locationConstraint = BucketLocationConstraint.fromValue(REGION)
		}
	}
	s3.createBucket(createBucketRequest)
	println("Bucket $BUCKET created successfully!")
}
 
suspend fun cleanUp(s3: S3Client) {
	println("Deleting object $BUCKET/$KEY...")
	val deleteObjectRequest = DeleteObjectRequest {
		bucket = BUCKET
		key = KEY
	}
 s3.deleteObject(deleteObjectRequest)
 
 println("Object $BUCKET/$KEY deleted successfully!")
 
 println("Deleting bucket $BUCKET...")
 val deleteBucketRequest = DeleteBucketRequest {
  bucket = BUCKET
 }
 s3.deleteBucket(deleteBucketRequest)
 println("Bucket $BUCKET deleted successfully!")
}

Let my friend ChatGPT explain what the code does:

  • Imports: The code imports necessary classes from the AWS SDK for Kotlin, including S3 client classes and models. It also imports ByteStream for handling data streams and runBlocking for coroutine support.
  • Constants:
  • REGION: Specifies the AWS region (e.g., “eu-central-1”).
  • BUCKET: A unique bucket name is generated using UUID.randomUUID().
  • KEY: Defines the key name for the object to be stored in S3.
  • Main Function:
  • Initializes an S3 client with the specified region.
  • Calls setupTutorial to create a new S3 bucket.
  • Creates a text object in the bucket with the specified key.
  • Cleans up by deleting the created object and bucket.
  • setupTutorial Function:
  • Creates an S3 bucket in the specified region.
  • Uses CreateBucketRequest to configure and create the bucket.
  • cleanUp Function:
  • Deletes the previously created object and bucket.
  • Uses DeleteObjectRequest and DeleteBucketRequest for deletion.
  • Coroutine Usage: The runBlocking coroutine builder is used to execute suspend functions (setupTutorial and cleanUp) in main. AWS SDK calls are suspending functions and require a coroutine context.

Thank you, ChatGPT.

Finally, I ran the code and received the expected output:

Creating bucket bucket-bad30829-1f4f-432a-acf3-fccafac14ecf...
Bucket bucket-bad30829-1f4f-432a-acf3-fccafac14ecf created successfully!
Creating object bucket-bad30829-1f4f-432a-acf3-fccafac14ecf/my-s3-bucket-key...
Object bucket-bad30829-1f4f-432a-acf3-fccafac14ecf/my-s3-bucket-key created successfully!
Deleting object bucket-bad30829-1f4f-432a-acf3-fccafac14ecf/my-s3-bucket-key...
Object bucket-bad30829-1f4f-432a-acf3-fccafac14ecf/my-s3-bucket-key deleted successfully!
Deleting bucket bucket-bad30829-1f4f-432a-acf3-fccafac14ecf...
Bucket bucket-bad30829-1f4f-432a-acf3-fccafac14ecf deleted successfully!

That was easy!

If you have any further questions, need specific code examples, or require additional assistance, please leave a comment or send me a message.

Thank you for reading!