1
1
[[webflux-fn]]
2
- = Functional Programming Model
2
+ = Functional Endpoints
3
+
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
8
+
3
9
4
10
[[webflux-fn-handler-functions]]
5
- == HandlerFunctions
11
+ == HandlerFunction
6
12
7
13
Incoming HTTP requests are handled by a **`HandlerFunction`**, which is essentially a function that
8
14
takes a `ServerRequest` and returns a `Mono<ServerResponse>`. The annotation counterpart to a
9
- handler function would be a method with `@RequestMapping`.
15
+ handler function is an `@RequestMapping` method .
10
16
11
17
`ServerRequest` and `ServerResponse` are immutable interfaces that offer JDK-8 friendly access
12
- to the underlying HTTP messages. Both are fully reactive by
13
- building on top of Reactor: the request expose the body as `Flux` or `Mono`; the response accepts
14
- any http://www.reactive-streams.org[Reactive Streams] `Publisher` as body.
18
+ to the underlying HTTP messages with http://www.reactive-streams.org[Reactive Streams]
19
+ non-blocking back pressure. The request exposes the body as Reactor `Flux` or `Mono`
20
+ types; the response accepts any Reactive Streams `Publisher` as body (see
21
+ <<web-reactive.adoc#webflux-reactive-libraries,Reactive Libraries>>).
22
+
15
23
16
24
`ServerRequest` gives access to various HTTP request elements:
17
25
the method, URI, query parameters, and -- through the separate `ServerRequest.Headers` interface
@@ -26,7 +34,7 @@ contains JSON, or JAXB if XML).
26
34
27
35
Flux<Person> people = request.bodyToFlux(Person.class);
28
36
29
- The two methods above ( `bodyToMono` and `bodyToFlux`) are, in fact, convenience methods that use the
37
+ The above -- `bodyToMono` and `bodyToFlux`, are, in fact, convenience methods that use the
30
38
generic `ServerRequest.body(BodyExtractor)` method. `BodyExtractor` is
31
39
a functional strategy interface that allows you to write your own extraction logic, but common
32
40
`BodyExtractor` instances can be found in the `BodyExtractors` utility class. So, the above
@@ -43,7 +51,8 @@ a JSON content-type, and a body:
43
51
Mono<Person> person = ...
44
52
ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(person);
45
53
46
- And here is how to build a response with a 201 Created status, Location header, and empty body:
54
+ And here is how to build a response with a 201 CREATED status, a `"Location"` header, and
55
+ empty body:
47
56
48
57
URI location = ...
49
58
ServerResponse.created(location).build();
@@ -111,7 +120,7 @@ variable `id`. We retrieve that `Person` via the repository, and create a JSON r
111
120
found. If it is not found, we use `switchIfEmpty(Mono<T>)` to return a 404 Not Found response.
112
121
113
122
[[webflux-fn-router-functions]]
114
- == RouterFunctions
123
+ == RouterFunction
115
124
116
125
Incoming requests are routed to handler functions with a **`RouterFunction`**, which is a function
117
126
that takes a `ServerRequest`, and returns a `Mono<HandlerFunction>`. If a request matches a
@@ -172,43 +181,23 @@ Most of the predicates found in `RequestPredicates` are compositions.
172
181
For instance, `RequestPredicates.GET(String)` is a composition of
173
182
`RequestPredicates.method(HttpMethod)` and `RequestPredicates.path(String)`.
174
183
175
- [[webflux-fn-running]]
176
- === Running a Server
177
-
178
- Now there is just one piece of the puzzle missing: running a router function in an HTTP server.
179
- You can convert a router function into a `HttpHandler` by using
180
- `RouterFunctions.toHttpHandler(RouterFunction)`.
181
- The `HttpHandler` allows you to run on a wide variety of reactive runtimes: Reactor Netty,
182
- Servlet 3.1+, and Undertow.
183
- Here is how we run a router function in Reactor Netty, for instance:
184
184
185
- [source,java,indent=0]
186
- [subs="verbatim,quotes"]
187
- ----
188
- RouterFunction<ServerResponse> route = ...
189
- HttpHandler httpHandler = RouterFunctions.toHttpHandler(route);
190
- ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);
191
- HttpServer server = HttpServer.create(HOST, PORT);
192
- server.newHandler(adapter).block();
193
- ----
185
+ [[webflux-fn-running]]
186
+ == Running a server
194
187
195
- For Tomcat it looks like this:
188
+ How do you run a router function in an HTTP server? A simple option is to convert a
189
+ router function to an `HttpHandler` via `RouterFunctions.toHttpHandler(RouterFunction)`.
190
+ The `HttpHandler` can then be used with a number of servers adapters.
191
+ See <<web-reactive.adoc#webflux-httphandler,HttpHandler>> for server-specific
192
+ instructions.
196
193
197
- [source,java,indent=0]
198
- [subs="verbatim,quotes"]
199
- ----
200
- RouterFunction<ServerResponse> route = ...
201
- HttpHandler httpHandler = RouterFunctions.toHttpHandler(route);
202
- HttpServlet servlet = new ServletHttpHandlerAdapter(httpHandler);
203
- Tomcat server = new Tomcat();
204
- Context rootContext = server.addContext("", System.getProperty("java.io.tmpdir"));
205
- Tomcat.addServlet(rootContext, "servlet", servlet);
206
- rootContext.addServletMapping("/", "servlet");
207
- tomcatServer.start();
208
- ----
194
+ it is also possible to run with a
195
+ <<web-reactive.adoc#webflux-dispatcher-handler,DispatcherHandler>> setup -- side by side
196
+ with annotated controllers. The easiest way to do that is through the
197
+ <<web-reactive.adoc#webflux-config>> which creates the necessary configuration to
198
+ handle requests with router and handler functions.
209
199
210
200
211
- // TODO: DispatcherHandler
212
201
213
202
[[webflux-fn-handler-filter-function]]
214
203
== HandlerFilterFunction
0 commit comments