Spring 5 WebClient with Spring Boot and Kotlin

1. Introduction

2. What is WebClient?

3. Imports

implementation("org.springframework.boot:spring-boot-starter-webflux:2.3.1.RELEASE")

4. Create a Configuration Class

@Configuration
class WebClientConfiguration {
@Bean
fun webClient(builder: WebClient.Builder): WebClient =
builder
.baseUrl("localhost:8080")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build()
}

5. Make Requests and Map Responses to Objects

{
"message": "Hello world",
"timestamp": "2020-07-23T10:10:10.273174"
}
data class ExampleResponse(
val message: String,
val timestamp: LocalDateTime
)

@Component
class ExampleClient(
private val webClient: WebClient
) {
// our functions will go here
}

5.1. Fetch the Data Using Retrieve() Function

fun retrieveExampleResponse(): ExampleResponse? =
webClient.get()
.uri { it.pathSegment("api", "hello").build() }
.retrieve()
.bodyToMono(ExampleResponse::class.java)
.block()

5.2. Fetching the Data Using Exchange() Function

fun exchangeExampleResponse(): ResponseEntity<ExampleResponse>? =
webClient.get()
.uri { it.pathSegment("api", "hello").build() }
.exchange()
.flatMap {
println("Raw status code: ${it.rawStatusCode()}")
it.toEntity(ExampleResponse::class.java)
}
.block()

5.3. What Is the Difference Between the Exchange() and Retrieve() Functions?

5.4. Fetch the Array Of Objects

inline fun <reified T> typeReference() = object : ParameterizedTypeReference<T>() {}

fun retrieveExampleResponseList(): List<ExampleResponse>? =
webClient.get()
.uri { it.pathSegment("api", "hello-list").build() }
.retrieve()
.bodyToMono(typeReference<List<ExampleResponse>>())
.block()

5.5. Call Secured Endpoints

webClient.get()
.uri { it.pathSegment("api", "secured", "bearer", "hello").build() }
.headers { it.setBasicAuth(username, password) }
.retrieve()
.bodyToMono(ExampleResponse::class.java)
.block()
webClient.get()
.uri { it.pathSegment("api", "secured", "hello").build() }
.headers { it.setBearerAuth(token) }
.retrieve()
.bodyToMono(ExampleResponse::class.java)
.block()

6. Send the Request Body

6.1. Send JSON Request Body

webClient.post()
.uri { it.pathSegment("api", "hello").build() }
.body(BodyInserters.fromValue(requestBody))
.retrieve()
.bodyToMono(ExampleResponse::class.java)
.block()

6.2. Send x-www-form-urlencoded Request Body

webClient.post()
.uri { it.pathSegment("api", "hello").build() }
.body(BodyInserters.fromFormData(name, value))
.retrieve()
.bodyToMono(ExampleResponse::class.java)
.block()

7. Create filters

builder
.filter(requestLoggerFilter())
.filter(responseLoggerFilter())

7.1. Create Request Logger

As you can see we are using ofRequestProcessor() static method of ExchangeFilterFunction which allows us to pass the request processor to it. Processor is a Function with ClientRequest class as an input and Mono<ClientRequest> as an output.

7.2. Create Response logger

fun responseLoggerFilter() = ExchangeFilterFunction.ofResponseProcessor {
logger.info("Response status code: ${it.statusCode()}")

Mono.just(it)
}

8. Conclusion

Hi, my name is Piotr and I am the founder of Codersee- a technical blog, where I am teaching programming by practical step by step tutorials.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store