https://spring.io/guides/gs/reactive-rest-service/
WebFlux와 WebClient를 이용해 RESTful한 service를 만들어본다.
우선 프로젝트 구성시에는 initializer를 사용하며 Spring Reactive Web, Spring JPA, H2 Database를 dependencies로 하여 만들어주면 된다.
Entity는 제외하고 Handler, Router, Controller 세 코드를 살펴보자
## Handler.kt
@Component
class GreetingHandler {
fun hello(request: ServerRequest): Mono<ServerResponse> {
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(Greeting("Hello, Spring!")))
}
}
![](https://velog.velcdn.com/images/heyday_7/post/36f34f60-64ab-486b-a9f0-4ccdc4671465/image.png)
## Router.kt
@Configuration(proxyBeanMethods = false)
class GreetingRouter {
@Bean
fun route(greetingHandler: GreetingHandler): RouterFunction<ServerResponse> {
return RouterFunctions
.route(
GET("/hello").and(accept(MediaType.APPLICATION_JSON)),
greetingHandler::hello
)
}
}
## Controller.kt
@Component
class GreetingClient {
private val client: WebClient = WebClient.create("http://localhost:8080")
fun getMessage(): Mono<String> {
return client.get().uri("/hello").accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(Greeting::class.java)
.map(Greeting::message)
}
}
사실 이 코드들은 WebFlux를 통해 client를 구성하는 기초 방식 정도로 이해하고 받아들인 부분이 많다. 그럼에도 가볍게 정리를 해본다.
실제 Client의 사용은 Application.kt에서 CommandLineRunner를 이용해서 구현했다.
## ~Application.kt
@SpringBootApplication
class BuildingAReactiveRestfulWebServiceApplication {
@Bean
fun startRunner(
greetingClient: GreetingClient
): CommandLineRunner = CommandLineRunner {
println(">> message = " + greetingClient.getMessage().block())
}
}
.block()을 통해서 Mono 내부에 있는 object만을 꺼내서 출력해보면 예상한대로 출력되는 것을 볼 수 있다.
가이드에서 테스트까지 진행하기에 따라가봤다.
## GreetingRouterTest.kt
@ExtendWith(SpringExtension::class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class GreetingRouterTest(
@Autowired private val webTestClient: WebTestClient
) {
@Test
fun testHello() {
webTestClient
.get()
.uri("/hello")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus().isOk
.expectBody(Greeting::class.java).value { greeting ->
assert(greeting.message == "Hello, Spring!")
}
}
}
이 테스트의 경우 이전 가이드를 통해 익혔던 Intergation test 방식(?)으로 작성되어 있다. client를 활용하기에 실제 user가 client를 통해 통신하는 것과 비슷한 테스트 환경을 구축한 것으로 보인다. 가볍게 따라쓰고 돌려보면 된다.
reactive한 service, 결국 비동기 프로그래밍을 의미하며 간단히 non-blocking 한 서비스와 api들을 제공해줄 수 있느냐의 문제인 것이다. WebFlux는 나에게는 꽤나 생소한 개념이기에 아마 후에 관련해서 더 파보지 않을까 싶다. 다만 이런 생각도 들었다.
안드로이드 일을 하며 kotlin의 coroutine을 활용했었는데, 이를 활용해서 spring project를 만들려면 어떤식이 되어야 할까? 그리고 뭐가 더 좋은 선택지일까?
그래서 한번 찾아봤더니, 나름 대박(?)을 하나 건졌다.
Going Reactive with Spring, Coroutines and Kotlin Flow라고 무려 Spring 공식 Blog에 있는 글이다.(물론 작성 시기가 2019년이긴 하다.) Coroutine을 활용하려는 시도가 있었단 것이고 추가적으로 찾아보니 여러 포스트들이 나온다. 결국 무엇이 좋은지는 추가적인 학습이 필요할 것 같다.
그래서 Spring MVC 와 WebFlux와 Coroutine 세가지 개념을 엮어서 딥하게 파보겠다는 목표를 하나 세우고 이 가이드를 마친다.
코드는 여기서 확인할 수 있다.