Spring WebFlux GET Request
September 11, 2020
This page will walk through Spring WebFlux GET request example. We can create GET request endpoint using functional programming as well as annotation based programming. The annotation based GET request endpoint is same as we do in Spring MVC using @GetMapping
and @Controller
. For the functional endpoint, we need to use Spring RouterFunction
API. Find the sample code to create GET request endpoint.
1. Using functional programming.
@Bean public RouterFunction<ServerResponse> root(BookHandler bookHandler) { return RouterFunctions.route() .GET("/books/{id}", accept(MediaType.TEXT_PLAIN), bookHandler::getBookById) .build(); }
@GetMapping("/books/{id}") public Mono<Book> getBookById(@PathVariable("id") Integer id) { return service.getBookById(id); }
Contents
Technologies Used
Find the technologies being used in our example.1. Java 11
2. Spring 5.2.8.RELEASE
3. Spring Boot 2.3.2.RELEASE
4. Maven 3.5.2
Creating GET Request Functional Endpoint
To create a method to accept HTTP GET using functional web framework, we need to useRouterFunctions.Builder
. The RouterFunctions
is central class to handle reactive functional web framework. The RouterFunctions
has inner class as RouterFunctions.Builder
that works as a builder for router functions. The RouterFunctions.Builder
has methods such as GET(), POST(), DELETE(), HEAD() etc. Find the GET()
method signature.
1.
RouterFunctions.Builder GET(String pattern, HandlerFunction<ServerResponse> handlerFunction)
pattern: URL pattern to match.
handlerFunction: handler function to be executed when given URL pattern matches.
2.
RouterFunctions.Builder GET(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction)
Find the below code to create GET request.
@Bean public RouterFunction<ServerResponse> root(BookHandler bookHandler) { return RouterFunctions.route() .GET("/books/{id}", bookHandler::getBookById) .GET("/books", accept(MediaType.TEXT_PLAIN), bookHandler::getAllBooks) .build(); }
Creating HandlerFunction
TheHandlerFunction
is a functional interface that handles a request. Spring Boot uses reactor API by default. Finds these two reactor APIs.
reactor.core.publisher.Mono: A reactive stream publisher API that completes successfully by emitting an element or with an error.
reactor.core.publisher.Flux: A reactive stream publisher API that completes successfully by emitting 0 to N element or with an error.
Find the sample use of
Mono
.
@Component public class BookHandler { public Mono<ServerResponse> getAllBooks(ServerRequest request) { return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(Book.getAllBooks())); } }
ServerResponse: Spring API that represents server-side HTTP response.
Complete Example using Spring Boot
pom.xml<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.2.RELEASE</version> <relativePath/> </parent> <properties> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> </dependencies>
package com.concretepage; import static org.springframework.web.reactive.function.server.RequestPredicates.accept; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.reactive.function.server.ServerResponse; @Configuration public class BookRouter { @Bean public RouterFunctionroot(BookHandler bookHandler) { return RouterFunctions.route() .GET("/books/{id}", accept(MediaType.TEXT_PLAIN), bookHandler::getBookById) .GET("/books", accept(MediaType.TEXT_PLAIN), bookHandler::getAllBooks) .build(); } }
package com.concretepage; import java.util.function.Predicate; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.BodyInserters; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; @Component public class BookHandler { public Mono<ServerResponse> getBookById(ServerRequest request) { int id = Integer.parseInt(request.pathVariable("id")); Predicate<Book> predicate = b -> b.getId() == id; Book book = Book.getAllBooks().stream().filter(predicate).findFirst().get(); return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(book)); } public Mono<ServerResponse> getAllBooks(ServerRequest request) { return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(Book.getAllBooks())); } }
package com.concretepage; import java.util.Arrays; import java.util.List; public class Book { private int id; private String name; public Book() {} public Book(int id, String name) { this.id = id; this.name = name; } //Sets and Gets public static List<Book> getAllBooks() { return Arrays.asList( new Book(101, "Spring Tutorials"), new Book(102, "Hibernate Tutorials"), new Book(103, "Angular Tutorials") ); } }
package com.concretepage; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Client Code with WebClient
BookWebClient.javapackage com.concretepage; import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; public class BookWebClient { private WebClient client = WebClient.create("http://localhost:8080"); public String fetchBookById(int id) { Mono<ClientResponse> result = client.get() .uri("/books/" + id) .exchange(); return result.flatMap(res -> res.bodyToMono(String.class)).block(); } public String fetchAllBooks() { Mono<ClientResponse> result = client.get() .uri("/books") .exchange(); return result.flatMap(res -> res.bodyToMono(String.class)).block(); } public static void main(String[] args) { BookWebClient bwc = new BookWebClient(); System.out.println("---Book by Id---"); System.out.println(bwc.fetchBookById(102)); System.out.println("---All books---"); System.out.println(bwc.fetchAllBooks()); } }
mvn spring-boot:run
BookWebClient.java
file. We can also access the URL.
http://localhost:8080/books

References
Spring RouterFunctionsReactor Mono