Spring Webflux step.3 - Functional Endpoints

Functional Endpoints

WebfluxAPI 를 구현함에 있어 2가지 방식이 있다.

  • @Contoller 어노테이션을 사용하는 Annotated Contollers 방식
  • Router 를 활용한 Functional Endpoints 방식

Annotated Contollers 방식WebMVC 에서 자주 사용하고 있는 방식이기 때문에, 이왕 배워볼 Webflux 에서는 새로운 방식인 Functional Endpoints 방식 에 대해서 학습해볼 계획이다.
살짝 살펴봤을 때는, Router 라는 객체를 사용해서 매핑되는 URL 를 알맞는 Handler 로 라우팅해주는 것으로 보이고, 이러한 방식은 Front-end Framwork 들에서 자주 사용하는 구조로 생각된다.

Webflux 에서 경량화된 함수형 프로그래밍 모델인 Webflux.fn 을 지원한다. Webflux.fn 모델은 요청을 함수로 라우팅하고, 핸들링하기 때문에 불변성(immutablitity)를 보장한다.

Webflux.fn 모델에서는 요청으로 ServerRequest 객치를 받아 비동기 ServerResponse 를 반환하는 구조이며, RouterFunction 에서 요청에 대한 처리를 위해 HandlerFuction 에 라우팅한다. (RouterFunction@RequestMapping 과 동일한 역할)

Functional Endpoints 맛보기

Router Class
@Component
class StudentsRouter(private val handler: StudentsHandler) {
    @Bean
    fun routerFunction() = nest(path("/api"),
        router {
            listOf(
                POST("/student", handler::getOne),
                POST("/students", handler::save),
                GET("/students", handler::getAll)
            )
        }
    )
}
Handler Class
@Component
class StudentsHandler(private val repository: StudentsRepository) {

    fun getOne(request: ServerRequest): Mono<ServerResponse> =
        repository.findById(request.bodyToMono<Students>().mapNotNull { it.id }).flatMap { ok().body(fromValue(it)) }

    fun getAll(request: ServerRequest): Mono<ServerResponse> =
        repository.findAll().collect(toList()).flatMap { ok().body(fromValue(it)) }

    fun save(request: ServerRequest): Mono<ServerResponse> =
        repository.saveAll(request.bodyToMono<Students>()).flatMap { created(URI.create("/students")).build() }.next()

}

출처