Skip to content

Commit cdf2ab9

Browse files
committed
Expand docs on WebFlux.fn + @EnableWebFlux
Issue: SPR-16360
1 parent 19a1477 commit cdf2ab9

File tree

1 file changed

+82
-27
lines changed

1 file changed

+82
-27
lines changed

src/docs/asciidoc/web/webflux-functional.adoc

Lines changed: 82 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
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

1515
Incoming 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
2021
to the underlying HTTP messages with http://www.reactive-streams.org[Reactive Streams]
2122
non-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
2929
how 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
4040
generic `ServerRequest.body(BodyExtractor)` method. `BodyExtractor` is
4141
a 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

130130
Incoming requests are routed to handler functions with a **`RouterFunction`**, which is a function
131131
that 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

135136
Typically, 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

Comments
 (0)