11[[webflux-fn]]
22= Functional Endpoints
33
4- Spring WebFlux provides a lightweight, functional programming model where functions
5- are used to route and handle requests and where contracts are designed for immutability.
6- It is an alternative to the annotated-based programming model but runs on the same
7- <<web-reactive.adoc#webflux-reactive-spring-web>> foundation
4+ Spring WebFlux includes a lightweight, functional programming model in which functions
5+ are used to route and handle requests and contracts are designed for immutability.
6+ It is an alternative to the annotated-based programming model but otherwise running on
7+ the same <<web-reactive.adoc#webflux-reactive-spring-web>> foundation
88
99
1010
@@ -13,19 +13,19 @@ It is an alternative to the annotated-based programming model but runs on the sa
1313== HandlerFunction
1414
1515Incoming HTTP requests are handled by a **`HandlerFunction`**, which is essentially a function that
16- takes a `ServerRequest` and returns a `Mono<ServerResponse>`. The annotation counterpart to a
17- handler function is an `@RequestMapping` method.
16+ takes a `ServerRequest` and returns a `Mono<ServerResponse>`. If you're familiar with the
17+ annotation-based programming model, a handler function is the equivalent of an
18+ `@RequestMapping` method.
1819
1920`ServerRequest` and `ServerResponse` are immutable interfaces that offer JDK-8 friendly access
2021to the underlying HTTP messages with http://www.reactive-streams.org[Reactive Streams]
2122non-blocking back pressure. The request exposes the body as Reactor `Flux` or `Mono`
22- types; the response accepts any Reactive Streams `Publisher` as body (see
23- <<web-reactive.adoc#webflux-reactive-libraries,Reactive Libraries>>).
24-
23+ types; the response accepts any Reactive Streams `Publisher` as body. The rational for this
24+ is explained in <<web-reactive.adoc#webflux-reactive-libraries,Reactive Libraries>>.
2525
2626`ServerRequest` gives access to various HTTP request elements:
27- the method, URI, query parameters, and -- through the separate `ServerRequest.Headers` interface
28- -- the headers . Access to the body is provided through the `body` methods. For instance, this is
27+ the method, URI, query parameters, and headers (via a separate `ServerRequest.Headers`
28+ interface . Access to the body is provided through the `body` methods. For instance, this is
2929how to extract the request body into a `Mono<String>`:
3030
3131 Mono<String> string = request.bodyToMono(String.class);
@@ -36,11 +36,11 @@ contains JSON, or JAXB if XML).
3636
3737 Flux<Person> people = request.bodyToFlux(Person.class);
3838
39- The above -- `bodyToMono` and `bodyToFlux`, are, in fact, convenience methods that use the
39+ The `bodyToMono` and `bodyToFlux` used above are in fact convenience methods that use the
4040generic `ServerRequest.body(BodyExtractor)` method. `BodyExtractor` is
4141a functional strategy interface that allows you to write your own extraction logic, but common
4242`BodyExtractor` instances can be found in the `BodyExtractors` utility class. So, the above
43- examples can be replaced with :
43+ examples can also be written as follows :
4444
4545 Mono<String> string = request.body(BodyExtractors.toMono(String.class);
4646 Flux<Person> people = request.body(BodyExtractors.toFlux(Person.class);
@@ -103,7 +103,7 @@ public class PersonHandler {
103103 public Mono<ServerResponse> getPerson(ServerRequest request) { // <3>
104104 int personId = Integer.valueOf(request.pathVariable("id"));
105105 Mono<ServerResponse> notFound = ServerResponse.notFound().build();
106- Mono<Person> personMono = this. repository.getPerson(personId);
106+ Mono<Person> personMono = repository.getPerson(personId);
107107 return personMono
108108 .flatMap(person -> ServerResponse.ok().contentType(APPLICATION_JSON).body(fromObject(person)))
109109 .switchIfEmpty(notFound);
@@ -129,8 +129,9 @@ found. If it is not found, we use `switchIfEmpty(Mono<T>)` to return a 404 Not F
129129
130130Incoming requests are routed to handler functions with a **`RouterFunction`**, which is a function
131131that takes a `ServerRequest`, and returns a `Mono<HandlerFunction>`. If a request matches a
132- particular route, a handler function is returned; otherwise it returns an empty `Mono`. The
133- `RouterFunction` has a similar purpose as the `@RequestMapping` annotation in `@Controller` classes.
132+ particular route, a handler function is returned, or otherwise an empty `Mono` is returned.
133+ `RouterFunction` has a similar purpose as the `@RequestMapping` annotation in the
134+ annotation-based programming model.
134135
135136Typically, you do not write router functions yourself, but rather use
136137`RouterFunctions.route(RequestPredicate, HandlerFunction)` to
@@ -192,17 +193,71 @@ For instance, `RequestPredicates.GET(String)` is a composition of
192193[[webflux-fn-running]]
193194== Running a server
194195
195- How do you run a router function in an HTTP server? A simple option is to convert a
196- router function to an `HttpHandler` via `RouterFunctions.toHttpHandler(RouterFunction)`.
197- The `HttpHandler` can then be used with a number of servers adapters.
198- See <<web-reactive.adoc#webflux-httphandler,HttpHandler>> for server-specific
199- instructions.
200-
201- it is also possible to run with a
202- <<web-reactive.adoc#webflux-dispatcher-handler,DispatcherHandler>> setup -- side by side
203- with annotated controllers. The easiest way to do that is through the
204- <<web-reactive.adoc#webflux-config>> which creates the necessary configuration to
205- handle requests with router and handler functions.
196+ How do you run a router function in an HTTP server? A simple option is to convert a router
197+ function to an `HttpHandler` using one of the following:
198+
199+ * `RouterFunctions.toHttpHandler(RouterFunction)`
200+ * `RouterFunctions.toHttpHandler(RouterFunction, HandlerStrategies)`
201+
202+ The returned `HttpHandler` can then be used with a number of servers adapters by following
203+ <<web-reactive.adoc#webflux-httphandler,HttpHandler>> for server-specific instructions.
204+
205+ A more advanced option is to run with a
206+ <<web-reactive.adoc#webflux-dispatcher-handler,DispatcherHandler>>-based setup through the
207+ <<web-reactive.adoc#webflux-config>> which uses Spring configuration to declare the
208+ components process requests. The WebFlux Java config declares the following components
209+ related to functional endpoints:
210+
211+ * `RouterFunctionMapping` -- this detects one or more `RouterFunction<?>` beans in the
212+ Spring configuration, combines them via `RouterFunction.andOther`, and routes requests to
213+ the resulting, composed `RouterFunction`.
214+ * `HandlerFunctionAdapter` -- simple adapter to invoke a `HandlerFunction` selected to
215+ handle a request.
216+ * `ServerResponseResultHandler` -- invokes the `writeTo` method of the `ServerResponse`
217+ returned by the `HandlerFunction`.
218+
219+ The above allows functional endpoints to fit within the `DispatcherHandler` request
220+ processing lifecycle, and potentially to run side by side with annotated controllers, if
221+ any are declared. This is also the mechanism used in the Spring Boot WebFlux starter.
222+
223+ Below is example WebFlux Java config (see
224+ <<web-reactive.adoc#webflux-dispatcher-handler,DispatcherHandler>> for how to run):
225+
226+ [source,java,indent=0]
227+ [subs="verbatim,quotes"]
228+ ----
229+ @Configuration
230+ @EnableWebFlux
231+ public class WebConfig implements WebFluxConfigurer {
232+
233+ @Bean
234+ public RouterFunction<?> routerFunctionA() {
235+ // ...
236+ }
237+
238+ @Bean
239+ public RouterFunction<?> routerFunctionB() {
240+ // ...
241+ }
242+
243+ // ...
244+
245+ @Override
246+ public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
247+ // configure message conversion...
248+ }
249+
250+ @Override
251+ default void addCorsMappings(CorsRegistry registry) {
252+ // configure CORS...
253+ }
254+
255+ @Override
256+ public void configureViewResolvers(ViewResolverRegistry registry) {
257+ // configure view resolution for HTML rendering...
258+ }
259+ }
260+ ----
206261
207262
208263
0 commit comments