How to upload multipart files to a cloud storage locally with Spring Boot, Kotlin and MinIO
Tags: kotlin, spring, minio
Published: 2024-07-11 23:19:31

MinIO, an AWS S3 alternative. Easy, Dockerized and straightfoward.

## Introduction

If you’ve ever tried to kick off a personal project, something that might be meaningful or even fun but involves dealing with file storage, this seemingly straightforward task can turn into a bit of a headache.

There are various options for storing files nowadays, but let’s focus on the main ones:

* Bytes: One approach is to convert your files into a series of bytes and store them in your database. It works, but it might not be as practical as one would hope. Let’s suppose you have and API, how would you display this information?

* Cloud Storage: In my opinion, this is the way to go for file management. Simply put, you’re not burdened with handling the intricacies of data manipulation. All you need to do is upload the file to your cloud application, and in return, you receive a URL for the uploaded file. You can then access and display it however you see fit.
There are a lot of points to defend the cloud storage, but you probably will find better writers down there explaining the pros and cons way more accurate than me.

If you look closely and pay attention, maybe you’re wondering: It looks like that cloud storage is simply better and easier that store with bytes, what’s the big deal than? Simply, cloud storage isn’t free.

If you want to run a instance of AWS S3 — the most used cloud storage — you’ll get a free trial of 12 months and after that you’ll be charged for it. Not worthy if the application is just for personal studies. And that’s how it bring us to this post, is there any way to run a cloud storage locally and simulate something like S3?

## What's MinIO?

> MinIO is a high-performance, S3 compatible object store. It is built for large scale AI/ML, data lake and database workloads. It is software-defined and runs on any cloud or on-premises infrastructure. MinIO is dual-licensed under open source GNU AGPL v3 and a commercial enterprise license.
https://min.io/

## Steps 

Now, I’ll try to show in 4 simple and shorts steps how to upload a multipart file with Kotlin, Spring Boot and Mi

Make sure you have Docker installed before any steps.

### Step 1
Just run the MinIO docker container
```
docker run \
    -p 9000:9000 \
    -p 9090:9090 \
    --name minio \
    -v ~/minio/data:/data \
    -e "MINIO_ROOT_USER=root" \
    -e "MINIO_ROOT_PASSWORD=password" \
    quay.io/minio/minio server /data --console-address ":9090"
```

### Step 2
Add MinIO SDK dependency

`implementation("io.minio:minio:8.5.7")`

### Step 3
Create a client to communicate with MinIO
```kotlin
import io.minio.BucketExistsArgs
import io.minio.MakeBucketArgs
import io.minio.MinioClient

object MinioFactory {
    // These are the envs you pass as argument in your docker run
    private const val URL = "http://localhost:9000"
    private const val USER = "root"
    private const val PASSWORD = "password"
    const val BUCKET = "exam"

    private val minioClient: MinioClient by lazy {
        val client = MinioClient.builder()
            .endpoint(URL)
            .credentials(USER, PASSWORD)
            .build()
         
        // Logic to create the bucket if don't exists yet
        if (!client.bucketExists(BucketExistsArgs.builder().bucket(BUCKET).build())) {
            client.makeBucket(MakeBucketArgs.builder().bucket(BUCKET).build())
        }

        client
    }

    fun getInstance() = minioClient
}
```
### Step 4
Create a service responsible to upload the file
```kotlin
import io.minio.PutObjectArgs
import org.springframework.stereotype.Service
import org.springframework.web.multipart.MultipartFile

fun uploadExam(file: MultipartFile) {
    val minioClient = MinioFactory.getInstance()

    val putObjectArgs = PutObjectArgs.builder()
        .bucket(MinioFactory.BUCKET)
        .`object`("YOUR_PATH")
        .contentType(file.contentType)
        .stream(file.inputStream, file.size, -1)
        .build()

    minioClient.putObject(putObjectArgs).etag()
}
```
That’s it, you’ve just upload your first file to MinIO. You can check your work of art in http://localhost:9090/browser