Spring WebFlux PUT and DELETE Request
September 19, 2020
This page will walk through Spring WebFlux PUT and DELETE request example. The Spring REST reactive endpoints can be created by using annotation based web framework as well as functional web framework. In functional web framework, the Spring RouterFunctions
is the central entry point. The inner class RouterFunctions.Builder
provides methods such as GET(), POST(), PUT(), DELETE() etc. The RouterFunctions.Builder
is obtained via RouterFunctions.route()
method.
On this page we will create a Spring Boot application to serve HTTP PUT and DELETE request using functional web framework. By default Spring Boot uses Reactor as reactive library and Netty as server.
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
Create PUT Request Entry Point
Find thePUT()
method syntax from The RouterFunctions.Builder
.
1.
RouterFunctions.Builder PUT(String pattern, HandlerFunction<ServerResponse> handlerFunction)
PUT()
method adds a route to the specified handlerFunction that handles all HTTP PUT requests matching the specified URL pattern.
2.
RouterFunctions.Builder PUT(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction)
PUT()
method adds a route to the specified handlerFunction that handles all HTTP PUT requests matching the specified URL pattern and predicate.
Find the sample code.
@Bean public RouterFunction<ServerResponse> root(BookHandler bookHandler) { return RouterFunctions.route() .PUT("/updateBook", bookHandler::updateBook) .PUT("/updateWriter", RequestPredicates.contentType(MediaType.APPLICATION_JSON), bookHandler::updateWriter) .build(); }
Create DELETE Request Entry Point
Find theDELETE()
method syntax from The RouterFunctions.Builder
.
1.
RouterFunctions.Builder DELETE(String pattern, HandlerFunction<ServerResponse> handlerFunction)
DELETE()
method adds a route to the specified handlerFunction that handles all HTTP DELETE requests matching the specified URL pattern.
2.
RouterFunctions.Builder DELETE(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction)
DELETE()
method adds a route to the specified handlerFunction that handles all HTTP DELETE requests matching the specified URL pattern and predicate.
Find the sample code.
@Bean public RouterFunction<ServerResponse> root(BookHandler bookHandler) { return RouterFunctions.route() .DELETE("/books/{id}", bookHandler::deleteBookById) .DELETE("/writers/{id}", RequestPredicates.accept(MediaType.TEXT_PLAIN), bookHandler::deleteWriterById) .build(); }
Create Handler
1. Find the handler code to handle HTTP PUT request.public Mono<ServerResponse> updateBook(ServerRequest request) { return request.bodyToMono(Book.class) .flatMap(book -> Mono.just(bookService.updateBook(book))) .flatMap(book -> ServerResponse.ok() .contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(book))); }
ServerRequest
and ServerResponse
are Spring APIs that represents server-side HTTP request and response respectively.
2. Find the handler code to handle HTTP DELETE request.
public Mono<ServerResponse> deleteBookById(ServerRequest request) { return Mono.just(bookService.deleteBookById(Integer.parseInt(request.pathVariable("id")))) .flatMap(val -> { return ServerResponse.noContent().build(); }); }
Create Client with WebClient
Spring providesWebClient
that is non-blocking, reactive client to perform HTTP requests. To create the instance of WebClient
, we need to use WebClient.create()
method. To perform the HTTP requests, WebClient
provides the methods such as get(), post(), put(), delete() and head() etc.
Find the client code used in our demo application.
BookWebClient.java
package com.concretepage; import org.springframework.web.reactive.function.client.WebClient; public class BookWebClient { private WebClient client = WebClient.create("http://localhost:8080"); public void updateBookDemo() { client.put() .uri("/update") .bodyValue(new Book(101, "Android")) .exchange() .flatMap(res -> res.bodyToMono(Book.class)) .subscribe(book -> System.out.println("PUT: " + book.getId() + ", " + book.getName())); } public void deleteBookByIdDemo() { int id = 102; client.delete() .uri("/books/" + id) .exchange() .subscribe(res -> System.out.println("DELETE: " + res.statusCode())); } }
Server Code 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 org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.web.reactive.function.server.RequestPredicates; 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 RouterFunction<ServerResponse> root(BookHandler bookHandler) { return RouterFunctions.route() .PUT("/update", RequestPredicates.contentType(MediaType.APPLICATION_JSON), bookHandler::updateBook) .DELETE("/books/{id}", RequestPredicates.accept(MediaType.TEXT_PLAIN), bookHandler::deleteBookById) .build(); } }
package com.concretepage; import org.springframework.beans.factory.annotation.Autowired; 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 { @Autowired private BookService bookService; public Mono<ServerResponse> updateBook(ServerRequest request) { return request.bodyToMono(Book.class) .flatMap(book -> Mono.just(bookService.updateBook(book))) .flatMap(book -> ServerResponse.ok() .contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(book))); } public Mono<ServerResponse> deleteBookById(ServerRequest request) { return Mono.just(bookService.deleteBookById(Integer.parseInt(request.pathVariable("id")))) .flatMap(val -> { return ServerResponse.noContent().build(); }); } }
package com.concretepage; import org.springframework.stereotype.Service; @Service public class BookService { public Boolean deleteBookById(int id) { System.out.println("Book deleted with id " + id); return true; } public Book updateBook(Book book) { return new Book(book.getId(), book.getName() +" - updated"); } }
package com.concretepage; 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 }
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); BookWebClient bwc = new BookWebClient(); bwc.updateBookDemo(); bwc.deleteBookByIdDemo(); } }
mvn spring-boot:run

References
Spring RouterFunctionsSpring WebFlux