Wednesday, January 3, 2018

Spring Webflux - Part 3

Reactive Programming is the newest trend in programming world. In this article series of Spring Webflux I have been discussing on how to build a Reactive Application  using  Spring Webflux. In the Part 2 we have discussed how to build a simple reactive application using Spring Boot. Lets dig deep into more advanced routing methods and filter functions in this article.

Context Path for Application


In Spring MVC can give a context path to our application. In Spring Webflux we don't have a configuration for that. But we can set a context-path for multiple routes. Following is how we can do that. 

@Configuration
public class RouterWithContext {
    @Bean
    public RouterFunction<ServerResponse> routeWithContext(SampleHandler handler) {
        return nest(path("/context"),
                route(GET("/sample"), handler::handleNestedRoute));
    }
}

RouterFunctions.nest(...) will let you build nested routes in your application. It will take a RequestPredicate and a RouterFunction as arguments. Nested route is analogous to having a context path in Spring MVC.

Up to now we have just tried out HTTP GET Method in our application. What happen if we want to have request-body and we want to use it in our application. Lets do add a functionality to our application to accept a request-body and echo it back with some modifications. For this we will use a HTTP POST with a simple request body.

Our Request body should look as follows.

public class RequestBody {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

The handler function should first take out the request body and reshape the content and sends back the response. We can do it in imperative way using ServerRequest.bodyToMono(...).block() method which will give us the request-body. And the we can reshape it and generate the response. But since we are doing reactive programming using Mono.block() is an anti-pattern. What we can do is we can reshape the request-body in a more functional way.

    public Mono<ServerResponse> handleRequestWithABody(ServerRequest request) {
        return request
                .bodyToMono(RequestBody.class)
                .flatMap(requestBody -> {
                    ResponseBody responseBody = new ResponseBody();
                    responseBody.setStatus("Success");
                    responseBody.setDescription("Successfully Handled the request");
                    responseBody.setRequestBody(requestBody);
                    return ServerResponse.ok().body(fromObject(responseBody));
                })
                .switchIfEmpty(
                        ServerResponse.status(HttpStatus.BAD_REQUEST).build());
    }

We will first acquire the request-body as a stream using ServerRequest.bodyToMono(...). And then we can apply a 'flatmap' on that data-stream and reshape the content and get a data-stream. Finally there is some magic-code, the 'switchIfEmpty' which will check whether the data-stream is empty and send a default ServerResponse. Now we done with the handler-function. So, we have add the route now. This route has some specialty in it. This route consumes a request-body. So, it is preferable if we could mention the media-type which is accepted by this route. So, we can configure our route as follows.

route(POST("/echo").and(contentType(MediaType.APPLICATION_JSON)), handler::handleRequestWithABody);

As you can see here RequestPredicates can be concatenated and return a RequestPredicate. Here we have concatenated RequestPredicate which checks for HTTP Method and a RequestPredicate which checks for Content-Type Header.

Adding a Filter


Most often than not we want to secure our APIs. Spring Security has a more precise ways of securing an application, but here we want to have a simple key-base authentication for our application. For that we can use a simple filter function. First of all we have write an authenticator. Authenticator is a filter-function which will take ServerRequest and a HandlerFunction as arguments and return a ServerResponse.

@Component
public class Authenticator {
    @Value("${configuration.api.access-key}")
    private String apiKey;

    public Mono<ServerResponse> filterRoute(ServerRequest request, HandlerFunction<ServerResponse> handlerFunction){
        if (request.headers().asHttpHeaders().containsKey("x-api-key")) {
            if (request.headers().asHttpHeaders().get("x-api-key").get(0).equals(apiKey)) {
                return handlerFunction.handle(request);
            }
            return ServerResponse.status(HttpStatus.UNAUTHORIZED).build();
        } else {
            return ServerResponse.status(HttpStatus.UNAUTHORIZED).build();
        }
    }
}

Finally you can add the filter to the router.

    @Bean
    public RouterFunction<ServerResponse> routeWithContext(SampleHandler handler) {
        return nest(path("/context"),
                sampleRoute(handler)
                        .and(handleRequestBodyRoute(handler)))
                .filter(authenticator::filterRoute);
    }

You can find the sample code here.

Tuesday, January 2, 2018

Spring Webflux - Part 2

Reactive Programming is one of the most popular programming paradigms now a days. Spring Webflux is the newest flavor of Spring Framework with the taste of Reactive Programming. In my first article I have discussed about the building boxes of Spring Webflux. So, in this article we will build a simple application with Spring Webflux.

Application Structure


We will create a Spring-boot Application as a Maven Project. Add the following dependencies to Maven-POM. 

<dependencies>
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-webflux</artifactId>
 </dependency>
 <dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <optional>true</optional>
 </dependency>
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
  <scope>test</scope>
 </dependency>
 <dependency>
  <groupId>io.projectreactor</groupId>
  <artifactId>reactor-test</artifactId>
  <scope>test</scope>
 </dependency>
</dependencies>

Annotate the Spring-Boot-Application class with @EnableWebFlux. Adding this annotation to an '@Configuration class' or 'Spring-Boot-Application class' imports the Spring Web Reactive configuration from WebFluxConfigurationSupport.

@SpringBootApplication
@EnableWebFlux
public class WebfluxSampleApplication {

 public static void main(String[] args) {
  SpringApplication.run(WebfluxSampleApplication.class, args);
 }
}

Building the Application


Spring-Boot is so simple as you can use Spring-Webflux as you use Spring-MVC. You can just use Spring-Controllers. Following is a sample how to use controllers with Spring-Webflux.

@RestController
public class IndexController {
    @GetMapping("/index")
    public Mono<String> getIndex() {
        return Mono.just("Hello World!");
    }
}

If you run the application and access 'http://localhost:8080/index' in your browser you will get a response of 'Hello World!'. And it is what you have to do to say 'Hello World!' in Reactive. But this is the most traditional way you do in Spring. But Reactive Programming is always comes with Functional Programming.

You can use Webflux in more functional way. You can write your own router functions and handlers for those routes. Routes are more likely the resource-paths. When you do a request to the resource path with the correct HTTP method the handler will handle the request and respond.

First lets write the handler function. A handler function will take a ServerRequest and returns Mono<ServerResponse>.

@Component
public class SampleHandler {
    public Mono<ServerResponse> handleRequest(ServerRequest request) {
        return ServerResponse.ok().body(Mono.just("Sample Route Successful!"), String.class);
    }
}

Now we can write the router for the handler. Whenever a request comes to the resource-path of the router it will calls the handler function and respond to the request.

@Configuration
public class SampleRouter {
    @Bean
    public RouterFunction<ServerResponse> sampleRoute(SampleHandler handler) {
        return route(GET("/simple-route"), handler::handleRequest);
    }
}

Now if you run the application and access 'http://localhost:8080/simple-route' from your browser, you will get 'Sample Route Successful!' as the response. So, that is how we can be more functional in Spring Webflux. In the next article we will discuss about more advance routing functions. The complete source code for this article can be found here.