---
title: Accessing S3 API Using Spring's RestTemplate/RestClient Without SDK
tags: ["Java", "S3", "Spring Boot"]
categories: ["Programming", "Java", "am", "ik", "s3"]
date: 2024-07-08T04:56:20Z
updated: 2024-07-09T00:52:16Z
---

> ⚠️ This article was automatically translated by OpenAI (gpt-4o).
> It may be edited eventually, but please be aware that it may contain incorrect information at this time.

When accessing S3 with Java,

* [AWS SDK for Java 2.0](https://github.com/aws/aws-sdk-java-v2/)
* [MinIO Java SDK](https://github.com/minio/minio-java)

are potential candidates. While they are well-maintained and feature-rich, these libraries have a lot of dependencies.

In the case of AWS SDK for Java 2.0,

```
\- software.amazon.awssdk:s3:jar:2.26.16:compile
   +- software.amazon.awssdk:aws-xml-protocol:jar:2.26.16:compile
   |  \- software.amazon.awssdk:aws-query-protocol:jar:2.26.16:compile
   +- software.amazon.awssdk:protocol-core:jar:2.26.16:compile
   +- software.amazon.awssdk:arns:jar:2.26.16:compile
   +- software.amazon.awssdk:profiles:jar:2.26.16:compile
   +- software.amazon.awssdk:crt-core:jar:2.26.16:compile
   +- software.amazon.awssdk:http-auth:jar:2.26.16:compile
   +- software.amazon.awssdk:identity-spi:jar:2.26.16:compile
   +- software.amazon.awssdk:http-auth-spi:jar:2.26.16:compile
   |  \- org.reactivestreams:reactive-streams:jar:1.0.4:compile
   +- software.amazon.awssdk:http-auth-aws:jar:2.26.16:compile
   +- software.amazon.awssdk:checksums:jar:2.26.16:compile
   +- software.amazon.awssdk:checksums-spi:jar:2.26.16:compile
   +- software.amazon.awssdk:retries-spi:jar:2.26.16:compile
   +- software.amazon.awssdk:sdk-core:jar:2.26.16:compile
   |  +- software.amazon.awssdk:retries:jar:2.26.16:compile
   |  \- org.slf4j:slf4j-api:jar:2.0.13:compile
   +- software.amazon.awssdk:auth:jar:2.26.16:compile
   |  \- software.amazon.eventstream:eventstream:jar:1.0.1:compile
   +- software.amazon.awssdk:http-client-spi:jar:2.26.16:compile
   +- software.amazon.awssdk:regions:jar:2.26.16:compile
   +- software.amazon.awssdk:annotations:jar:2.26.16:compile
   +- software.amazon.awssdk:utils:jar:2.26.16:compile
   +- software.amazon.awssdk:aws-core:jar:2.26.16:compile
   +- software.amazon.awssdk:metrics-spi:jar:2.26.16:compile
   +- software.amazon.awssdk:json-utils:jar:2.26.16:compile
   |  \- software.amazon.awssdk:third-party-jackson-core:jar:2.26.16:compile
   +- software.amazon.awssdk:endpoints-spi:jar:2.26.16:compile
   +- software.amazon.awssdk:apache-client:jar:2.26.16:runtime
   |  +- org.apache.httpcomponents:httpclient:jar:4.5.13:runtime
   |  |  \- commons-logging:commons-logging:jar:1.2:runtime
   |  +- org.apache.httpcomponents:httpcore:jar:4.4.16:runtime
   |  \- commons-codec:commons-codec:jar:1.16.1:runtime
   \- software.amazon.awssdk:netty-nio-client:jar:2.26.16:runtime
      +- io.netty:netty-codec-http:jar:4.1.111.Final:runtime
      +- io.netty:netty-codec-http2:jar:4.1.111.Final:runtime
      +- io.netty:netty-codec:jar:4.1.111.Final:runtime
      +- io.netty:netty-transport:jar:4.1.111.Final:runtime
      +- io.netty:netty-common:jar:4.1.111.Final:runtime
      +- io.netty:netty-buffer:jar:4.1.111.Final:runtime
      +- io.netty:netty-handler:jar:4.1.111.Final:runtime
      |  \- io.netty:netty-transport-native-unix-common:jar:4.1.111.Final:runtime
      +- io.netty:netty-transport-classes-epoll:jar:4.1.111.Final:runtime
      \- io.netty:netty-resolver:jar:4.1.111.Final:runtime
```

In the case of MinIO Java SDK,

```
\- io.minio:minio:jar:8.5.11:compile
   +- com.carrotsearch.thirdparty:simple-xml-safe:jar:2.7.1:compile
   +- com.google.guava:guava:jar:33.0.0-jre:compile
   |  +- com.google.guava:failureaccess:jar:1.0.2:compile
   |  +- com.google.guava:listenablefuture:jar:9999.0-empty-to-avoid-conflict-with-guava:compile
   |  +- com.google.code.findbugs:jsr305:jar:3.0.2:compile
   |  +- org.checkerframework:checker-qual:jar:3.41.0:compile
   |  +- com.google.errorprone:error_prone_annotations:jar:2.23.0:compile
   |  \- com.google.j2objc:j2objc-annotations:jar:2.8:compile
   +- com.squareup.okhttp3:okhttp:jar:4.12.0:compile
   |  +- com.squareup.okio:okio:jar:3.6.0:compile
   |  |  \- com.squareup.okio:okio-jvm:jar:3.6.0:compile
   |  |     \- org.jetbrains.kotlin:kotlin-stdlib-common:jar:1.9.24:compile
   |  \- org.jetbrains.kotlin:kotlin-stdlib-jdk8:jar:1.9.24:compile
   |     +- org.jetbrains.kotlin:kotlin-stdlib:jar:1.9.24:compile
   |     |  \- org.jetbrains:annotations:jar:13.0:compile
   |     \- org.jetbrains.kotlin:kotlin-stdlib-jdk7:jar:1.9.24:compile
   +- com.fasterxml.jackson.core:jackson-annotations:jar:2.17.1:compile
   +- com.fasterxml.jackson.core:jackson-core:jar:2.17.1:compile
   +- com.fasterxml.jackson.core:jackson-databind:jar:2.17.1:compile
   +- org.bouncycastle:bcprov-jdk18on:jar:1.78:compile
   +- org.apache.commons:commons-compress:jar:1.26.0:compile
   |  +- commons-io:commons-io:jar:2.15.1:compile
   |  \- org.apache.commons:commons-lang3:jar:3.14.0:compile
   +- commons-codec:commons-codec:jar:1.16.1:compile
   \- org.xerial.snappy:snappy-java:jar:1.1.10.5:compile
```

> [!NOTE]
> In the case of [AWS SDK for Java](https://github.com/aws/aws-sdk-java/), which is nearing EoL, the dependencies are somewhat better.
> 
> ```
> \- com.amazonaws:aws-java-sdk-s3:jar:1.12.757:compile
>    +- com.amazonaws:aws-java-sdk-kms:jar:1.12.757:compile
>    +- com.amazonaws:aws-java-sdk-core:jar:1.12.757:compile
>    |  +- commons-logging:commons-logging:jar:1.1.3:compile
>    |  +- commons-codec:commons-codec:jar:1.16.1:compile
>    |  +- org.apache.httpcomponents:httpclient:jar:4.5.13:compile
>    |  |  \- org.apache.httpcomponents:httpcore:jar:4.4.16:compile
>    |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.17.1:compile
>    |  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.17.1:compile
>    |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.17.1:compile
>    |  +- com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:jar:2.17.1:compile
>    |  \- joda-time:joda-time:jar:2.12.7:compile
>    \- com.amazonaws:jmespath-java:jar:1.12.757:compile
> ```

If you are using other AWS services, AWS SDK for Java 2.0 might be fine, but if you are only doing simple put/get operations on S3-compatible Object Storage, these libraries are too much. Additionally, AWS SDK uses Apache HTTP Client or Netty, and MinIO SDK uses OkHttp (implemented in Kotlin) as their HTTP clients.

When creating an application with Spring Boot, you usually use `RestTemplate` or `RestClient`. If the SDK uses a separate HTTP client, it becomes inconvenient as you cannot use the Interceptors for Observability, Logging, Retry, etc., that you have set up on the application side.

For simple use cases where you only do put/get operations with access key and secret key authentication, it is sufficient to create HTTP Headers for S3 and perform XML marshalling/unmarshalling. This can be done with just `RestTemplate` or `RestClient` without using an SDK.

Therefore, I created a library called [simple-s3-client](https://github.com/making/simple-s3-client). Although it is named "s3-client," it only includes utilities for creating HTTP Headers and data classes for commonly used APIs.

You can use it by adding the following dependency:

```xml
<dependency>
	<groupId>am.ik.s3</groupId>
	<artifactId>simple-s3-client</artifactId>
	<version>0.2.2</version>
</dependency>
```

Usage is as follows:

```java
import static am.ik.s3.S3RequestBuilder.s3Request;

URI endpoint = URI.create("https://...");
String region = "...";
String accessKeyId = "...";
String secretAccessKey = "...";
String bucket = "...";
```

To PUT an object:

```java
// Put an object
String body = "Hello World!";
S3Request putObjectRequest = s3Request().endpoint(endpoint)
	.region(region)
	.accessKeyId(accessKeyId)
	.secretAccessKey(secretAccessKey)
	.method(HttpMethod.PUT)
	.path(b -> b.bucket(bucket).key("hello.txt"))
	.content(S3Content.of(body, MediaType.TEXT_PLAIN))
	.build();
```

In the case of `RestTemplate`:

```java
restTemplate.exchange(putObjectRequest.toEntityBuilder().body(body), Void.class);
```

In the case of `RestClient`:

```java
restClient.put()
	.uri(putObjectRequest.uri())
	.headers(putObjectRequest.headers())
	.body(body)
	.retrieve()
	.toBodilessEntity();
```

> [!NOTE]
> Multipart is not supported.

To GET an object:

```java
// Get an object
S3Request getObjectRequest = s3Request().endpoint(endpoint)
	.region(region)
	.accessKeyId(accessKeyId)
	.secretAccessKey(secretAccessKey)
	.method(HttpMethod.GET)
	.path(b -> b.bucket(bucket).key("hello.txt"))
	.build();
```

In the case of `RestTemplate`:

```java
String response = restTemplate.exchange(getObjectRequest.toEntityBuilder().build(), String.class).getBody();
System.out.println("Response: " + response); // Response: Hello World!
```

In the case of `RestClient`:

```java
String response = restClient.get()
	.uri(getObjectRequest.uri())
	.headers(getObjectRequest.headers())
	.retrieve()
	.body(String.class);
System.out.println("Response: " + response); // Response: Hello World!
```

For other usage, please refer to the [README](https://github.com/making/simple-s3-client).

The dependencies are as follows, and since it only adds `jackson-dataformat-xml` for handling XML with Jackson to the `spring-web` required for creating a web application with Spring Boot, it is minimal from the perspective of a typical Spring Boot application.

```
\- am.ik.s3:simple-s3-client:jar:0.2.2:compile
   +- org.springframework:spring-web:jar:6.1.10:compile
   |  +- org.springframework:spring-beans:jar:6.1.10:compile
   |  +- org.springframework:spring-core:jar:6.1.10:compile
   |  |  \- org.springframework:spring-jcl:jar:6.1.10:compile
   |  \- io.micrometer:micrometer-observation:jar:1.13.1:compile
   |     \- io.micrometer:micrometer-commons:jar:1.13.1:compile
   +- com.fasterxml.jackson.dataformat:jackson-dataformat-xml:jar:2.17.1:compile
   |  +- com.fasterxml.jackson.core:jackson-core:jar:2.17.1:compile
   |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.17.1:compile
   |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.17.1:compile
   |  \- org.codehaus.woodstox:stax2-api:jar:4.2.2:compile
   \- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.17.1:compile
```
