Authors Top

If you have a few years of experience in the Java ecosystem, and you’d like to share that with the community, have a look at our Contribution Guidelines.

Spring Top – Temp

Get started with Spring 5 and Spring Boot 2, through the reference Learn Spring course:

>> LEARN SPRING
Lightrun – Third Party Code
announcement - icon

Flakiness in REST requests is a common issue. A request can get a 200 OK in one scenario and a 409 next time. Sometimes a request can even succeed and fail intermittently on the same exact request. In short, working over HTTP can be a bit of a mess without solid tooling.

Also, while it’s easy enough to debug these issues locally when developing the application, we’re talking about production here - we can’t afford the downtime while you’re stepping in and out of code. Uptime is kind of the whole point.

With Lightrun, you can get the same level of access you get with a local debugger or profiler - no downtime required. You can add logs, metrics, and snapshots (think breakpoints, but without stopping the running service), in a safe and read-only manner - without redeploying, restarting, or even stopping the running service. Performance and security are maintained throughout the process.

Learn how to debug a live REST API (built with Spring, of course), using Lightrun, in this 5-minute tutorial:

>> Debugging REST Requests in Spring-Based applications using the Lightrun Platform

1. Overview

Our applications often have to handle file uploads via an HTTP request. Since Spring 5, we can now make these requests reactive.
The added support for Reactive Programming allows us to work in a non-blocking way, using a small number of threads and Backpressure.

In this article, we'll use WebClient – a non-blocking, reactive HTTP client – to illustrate how to upload a file. WebClient is part of the reactive programming library called Project Reactor. We'll cover two different approaches to uploading a file using a BodyInserter.

2. Uploading a File with WebClient

In order to use WebClient, we'll need to add the spring-boot-starter-webflux dependency to our project:

<dependency>
    <groupId>org.springframework.boot</groupId>. 
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

2.1. Uploading a File from a Resource

To start with, we want to declare our URL:

URI url = UriComponentsBuilder.fromHttpUrl(EXTERNAL_UPLOAD_URL).build().toUri();

Let's say in this example we want to upload a PDF. We'll use MediaType.APPLICATION_PDF as our ContentType.
Our upload endpoint returns an HttpStatus. Since we're expecting only one result, we'll wrap it in a Mono:

Mono<HttpStatus> httpStatusMono = webClient.post()
    .uri(url)
    .contentType(MediaType.APPLICATION_PDF)
    .body(BodyInserters.fromResource(resource))
    .exchangeToMono(response -> {
        if (response.statusCode().equals(HttpStatus.OK)) {
            return response.bodyToMono(HttpStatus.class).thenReturn(response.statusCode());
        } else {
            throw new ServiceException("Error uploading file");
        }
     });

The method consuming this method can also return a Mono, and we can continue until we actually need to access the result. Once we're ready, we can call the block() method on the Mono object.

The fromResource() method uses the InputStream of the passed resource to write to the output message.

2.2. Uploading a File from Multipart Resource

If our external upload endpoint takes a Multipart form data, we can use the MultiPartBodyBuilder to take care of the parts:

MultipartBodyBuilder builder = new MultipartBodyBuilder();
builder.part("file", multipartFile.getResource());

Here, we could be adding various parts according to our requirements. The value in the map can be an Object or an HttpEntity.

When we call WebClient, we use BodyInsterter.fromMultipartData and build the object:

.body(BodyInserters.fromMultipartData(builder.build()))

We update the content type to MediaType.MULTIPART_FORM_DATA to reflect the changes.

Let's look at the entire call:

Mono<HttpStatus> httpStatusMono = webClient.post()
    .uri(url)
    .contentType(MediaType.MULTIPART_FORM_DATA)
    .body(BodyInserters.fromMultipartData(builder.build()))
    .exchangeToMono(response -> {
        if (response.statusCode().equals(HttpStatus.OK)) {
            return response.bodyToMono(HttpStatus.class).thenReturn(response.statusCode());
        } else {
            throw new ServiceException("Error uploading file");
        }
      });

3. Conclusion

In this tutorial, we've shown two ways to upload a file with WebClient using BodyInserters. As always, the code is available over on GitHub.

Spring bottom

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> THE COURSE
Generic footer banner
Comments are closed on this article!