Home » Reactive Programming » Router Functions

Router Functions

Last Updated on September 22, 2024 by KnownSense

Before diving into Router Functions and their implementation, we recommend reading our in-depth articles on Reactive Programming, Reactive Streams, Project Reactor, and Spring WebFlux. This will help you better understand the code snippets we’ll use to implement router functions in a Spring Reactive program.

Router Functions offer an alternative to the annotation-based Spring MVC programming model. Instead of using the traditional @RestController approach, where you handle web requests with annotations like @GetMapping and @PostMapping, Router Functions allow you to manage web requests through a series of fluent APIs. This functional programming paradigm provides a more flexible and composable way to define routes, enabling you to structure your application with greater clarity and modularity. By leveraging Router Functions, you gain the ability to create more maintainable and adaptable web applications.

FeatureRouter Functions@RestController
Programming ModelFunctionalAnnotation-based
FlexibilityHigh (programmatic routing, dynamic route composition)Moderate (static annotations)
Separation of ConcernsClearer (routing and logic separated)Mixed (routing and logic often in same class)
Dynamic RoutingSupports dynamic routes and conditional compositionMostly static
FiltersFlexible and declarative filters at route levelLess flexible (interceptors, AOP for global filtering)
TestabilityEasily testable without Spring contextMore setup required (e.g., MockMvc or full Spring context)
PerformancePotentially faster in some scenariosSlight overhead due to annotation processing

Understanding Handler Functions

Handler Functions manage incoming HTTP requests and generate the corresponding responses. These functions encapsulate the business logic needed to process requests and produce appropriate responses. When a request matches a route defined by a Router Function, the associated Handler Function is invoked to perform the actual processing, ensuring that the request is handled effectively and the correct response is returned.

Implementation

For Implementation of Router Functions in Spring Reactive, let’s create one simple spring reactive project.

Step 1: Create Project

Create a Spring Reactive project by using Spring Initializr and add the necessary dependencies.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
Step 2: Define a Handler

Now create one Service Handler class by using @Service Spring Annotation. This service class contains the actual logic for processing requests. Each method in the handler corresponds to a route in the router.

import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

@Component
public class SampleHandler {

    public Mono<ServerResponse> hello(ServerRequest request) {
        return ServerResponse.ok()
                .contentType(MediaType.TEXT_PLAIN)
                .body(Mono.just("Hello, Spring Reactive!"), String.class);
    }

    public Mono<ServerResponse> greet(ServerRequest request) {
        String name = request.queryParam("name").orElse("World");
        return ServerResponse.ok()
                .contentType(MediaType.TEXT_PLAIN)
                .body(Mono.just("Hello, " + name + "!"), String.class);
    }
}
3. Define Router Configuration

In the router configuration class, define the routes and link them to the corresponding handler methods.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;

@Configuration
public class RouterConfig {

    @Bean
    public RouterFunction<ServerResponse> router(SampleHandler handler) {
        return route(GET("/hello"), handler::hello)
                .andRoute(GET("/greet"), handler::greet);
    }
}
4. Run the Application

With this configuration, when you run your Spring Boot application, the routes /hello and /greet will be available. For example:
/hello will return “Hello, Spring Reactive!”
/greet?name=John will return “Hello, John!”

5. Testing the Application

You can test these routes using tools like Postman or simply in a browser:

  • Navigate to http://localhost:8080/hello to see the response.
  • Use http://localhost:8080/greet?name=John to pass query parameters.

When to Use Router Functions

  • Purely reactive applications: Router functions fit perfectly with fully reactive applications.
  • Complex routing logic: When you need dynamic, conditional, or composed routing.
  • Modular, testable components: When you prefer a clearer separation of routing and business logic.
  • Performance-sensitive systems: Where the annotation-based overhead could be an issue.

Conclusion

In this article, we demonstrated how to implement Router Functions in Spring WebFlux, offering a functional and flexible alternative to the traditional @RestController approach. By providing dynamic routing, better separation of concerns, and improved testability, Router Functions are well-suited for reactive applications, making them a powerful choice for developers looking to build modular and high-performance systems.

Scroll to Top