ucostyio

Functional Programming with Spring Reactive Web

Without going into too much backstory around reactive programming, the short explanation is that it is a technique for writing asynchronous, event driven, non-blocking applications.

I’m hoping to write a few posts about some of the techniques I’ve been playing around with. I’ve been really interested in keeping my services as functional as possible.

First Example: function chaining

Here is an example of a simple post request handler which takes some data, decodes it from Base64, uppercases the resultant string, and re-encodes it.

@Configuration
public class TestRouter {
    private String decode(String input) {
        return new String(Base64Utils.decodeFromString(input), StandardCharsets.UTF_8);
    }

    private String encode(String input) {
        return Base64Utils.encodeToString(input.getBytes());
    }

    @Bean
    public RouterFunction<ServerResponse> route() {
        return RouterFunctions.route(POST("/test"), req -> req.bodyToMono(String.class)
                .map(this::decode)
                .map(String::toUpperCase)
                .map(this::encode)
                .flatMap(e -> ok().body(BodyInserters.fromObject(e))));
    }
}

The real meat of it is within the route() method. The post request is chained through a sequence of methods using the map directive. Eventually this result is flatMapped into a ServerResponse object which the router function is expecting.

If I were to diagram out the flow of this HTTP request handler, it would look something like this

graph LR; req-->this::decode; this::decode-->String::toUpperCase; String::toUpperCase-->this::encode; this::encode-->response["return ok().body(BodyInserters.fromObject(e)"];

Why would you do this?

I like the idea of building functional blocks, which solve very specific problems, and then chaining them together to provide a service. In the above example, the encode and decode methods could be swapped out for data encryption routines. A good analogy would be to liken this to shell script pipes. The example code would look something like this

echo "ZXhhbXBsZSBzdHJpbmcK" | base64 -d | awk '{print toupper($0)}' | base64

A lot of the time, when I’m building microservices, they follow a very similar convention of taking in some data, transforming it a bit, or otherwise using it to get some more data, and then returning it. Being able to assemble these services out of existing functional units would save time and improve the testability of the code.

While this was always possible in the past, I like the minimalist expressive nature of the code. The entire code base, excluding import statements, for this example is about 24 lines of Java code.

Ultimately it comes down to the kind of problems you are trying to solve.

Comments

comments powered by Disqus
Powered by Disqus