Spring WebFlux Filters

1. Overview

The use of filters is widespread in web applications since they give us a way to modify a request or response without changing our endpoints.

In this quick tutorial, we’ll describe possible ways of implementing them with the WebFlux Framework.

As we won’t go into details about the WebFlux framework itself, you might want to check out this article for more details.

2. Maven Dependency

First of all, let’s declare the WebFlux Maven dependency:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

3. Endpoints

We have to create some endpoints first. One for each method: annotation-based and functional-based.

Let’s start with the annotation-based controller:

@GetMapping(path = "/users/{name}")
public Mono<String> getName(@PathVariable String name) {
    return Mono.just(name);
}

For the functional endpoint we have to create a handler first:

@Component
public class PlayerHandler {
    public Mono<ServerResponse> getName(ServerRequest request) {
        Mono<String> name = Mono.just(request.pathVariable("name"));
        return ok().body(name, String.class);
    }
}

And also a router configuration mapping:

@Bean
public RouterFunction<ServerResponse> route(PlayerHandler playerHandler) {
    return RouterFunctions
      .route(GET("/players/{name}"), playerHandler::getName)
      .filter(new ExampleHandlerFilterFunction());
}

4. Types of WebFlux Filters

The WebFlux framework provides two types of filters: WebFilters and HandlerFilterFunctions.

The main difference between them is that WebFilter implementations work for all endpoints and HandlerFilterFunction implementations will only work for Router-based ones.

4.1. WebFilter

We’ll implement a WebFilter to add a new header to the response. As a result, all responses should have this behavior:

@Component
public class ExampleWebFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange serverWebExchange,
      WebFilterChain webFilterChain) {

        serverWebExchange.getResponse()
          .getHeaders().add("web-filter", "web-filter-test");
        return webFilterChain.filter(serverWebExchange);
    }
}

4.2. HandlerFilterFunction

For this one, we implement a logic that sets the HTTP status to FORBIDDEN when the “name” parameter is equal to “test”.

public class ExampleHandlerFilterFunction
  implements HandlerFilterFunction<ServerResponse, ServerResponse> {

    @Override
    public Mono<ServerResponse> filter(ServerRequest serverRequest,
      HandlerFunction<ServerResponse> handlerFunction) {
        if (serverRequest.pathVariable("name").equalsIgnoreCase("test")) {
            return ServerResponse.status(FORBIDDEN).build();
        }
        return handlerFunction.handle(serverRequest);
    }
}

5. Testing

In WebFlux Framework there’s an easy way to test our filters: the WebTestClient. It allows us to test HTTP calls to our endpoints.

Here are examples of the annotation-based endpoint:

@Test
public void whenUserNameIsBaeldung_thenWebFilterIsApplied() {
    EntityExchangeResult<String> result = webTestClient.get()
      .uri("/users/baeldung")
      .exchange()
      .expectStatus().isOk()
      .expectBody(String.class)
      .returnResult();

    assertEquals(result.getResponseBody(), "baeldung");
    assertEquals(
      result.getResponseHeaders().getFirst("web-filter"),
      "web-filter-test");
}

@Test
public void whenUserNameIsTest_thenHandlerFilterFunctionIsNotApplied() {
    webTestClient.get().uri("/users/test")
      .exchange()
      .expectStatus().isOk();
}

And for the functional endpoint:

@Test
public void whenPlayerNameIsBaeldung_thenWebFilterIsApplied() {
    EntityExchangeResult<String> result = webTestClient.get()
      .uri("/players/baeldung")
      .exchange()
      .expectStatus().isOk()
      .expectBody(String.class)
      .returnResult();

    assertEquals(result.getResponseBody(), "baeldung");
    assertEquals(
      result.getResponseHeaders().getFirst("web-filter"),
      "web-filter-test");
}

@Test
public void whenPlayerNameIsTest_thenHandlerFilterFunctionIsApplied() {
    webTestClient.get().uri("/players/test")
      .exchange()
      .expectStatus().isForbidden();
}

6. Conclusion

We’ve covered both types WebFlux filters in this tutorial and had a look at some code examples.

For more information about the WebFlux Framework, have a look at the documentation.

As always, the full source code for the examples can be found over on GitHub.

Leave a Reply

Your email address will not be published.