Skip to main content
Blog

Spring WebFlux functional based

By 29 mei 2018No Comments

In my previous blog about WebFlux ‘Spring WebFlux annotation based‘, I discussed the annotation based reactive programming model for Spring WebFlux. In this blog I will use the example project introduced then and adapt it to the functional programming model.

The example project we have serves the names of planets in our solar system, optionally applying a filter, in plain text. Using curl on the running application gives:

$ curl http://localhost:8080/planets
Mercury
Venus
Earth
Mars
Jupiter
Saturn
Uranus
Neptune

$ curl http://localhost:8080/planets/e
Mercury
Venus
Earth
Jupiter
Neptune

The Spring WebFlux annotation based controller we are adapting looks like this:

@RestController
@AllArgsConstructor
public class PlanetController {

    private PlanetRepository planetRepository;

    @RequestMapping(path={"/planets/{substring}","/planets"})
    public Flux<String> getMatchingPlanets(@PathVariable(name = "substring", required=false) Optional<String> substring) {
        return planetRepository.getPlanets()
                .filter( p -> p.toLowerCase().contains(substring.orElse("").toLowerCase()))
                .map( p -> p + "\n");
    }
}

The functional model of WebFlux is quite different from the annotation based model. Where the annotation based model builds upon the already familiar @Controller,@RequestMapping and other web annotations, the functional model sets these aside and introduces concept of a RouterFunction and HandlerFunction.

RouterFunction

Router functions are the functional counterpart of the @RequestMapping annotation and used to match incomming requests to handler functions. A router function takes a ServletRequest as input and returns the appropriate handler function. The signature of a router function is as follows:

Mono<HandlerFunction<T>> route(ServerRequest request);

The router function definition for the @RequestMapping(path={"/planets/{substring}","/planets"}) annotation looks like this:

@Configuration
@AllArgsConstructor
public class PlanetRoutes {

    private PlanetHandler planetHandler;

    @Bean
    public RouterFunction<?> planetRouter() {
        return route(GET("/planets")
                .or(GET("/planets/{substring}")), planetHandler::getPlanets);
    }
}

HandlerFunction

Handler functions contain the actual business logic for processing the request. The signature of a handler function is as follows:

Mono<ServerResponse> handle(ServerRequest request);

The handler function implementation does not differ that much from the controller implementation, except that we now have to deal with a ServerRequest object that is our starting point for processing the request. The ServerRequest offers us reactive style access to request information. Transforming the controller logic to handler logic gives the following:

@Component
@AllArgsConstructor
public class PlanetHandler {

    private PlanetRepository planetRepository;

    public Mono<ServerResponse> getPlanets( ServerRequest request ) {
        String substring = request.pathVariables().getOrDefault("substring", "").toLowerCase();
        return ok().body(planetRepository.getPlanets()
                .filter( p -> p.toLowerCase().contains(substring)).map( p -> p + "\n"), String.class);
    }
}

There you go a fully reactive web application using the functional model of WebFlux. The full source code for the project can be found on github

This is a cross-post from my personal blog. Follow me on @acuriouscoder if you like what you’re reading or subscribe to my blog on https://acuriouscoder.net.