or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdfunctional-programming.mdhttp-client.mdindex.mdrequest-processing.mdview-resolution.mdwebsocket.md

functional-programming.mddocs/

0

# Functional Web Programming

1

2

Spring WebFlux provides a functional programming model using RouterFunction and HandlerFunction for composable request handling without annotations. This approach offers fine-grained control over request routing and processing with a declarative, functional style.

3

4

## Capabilities

5

6

### Router Functions

7

8

Core interface for routing requests to handler functions in the functional programming model.

9

10

```java { .api }

11

@FunctionalInterface

12

interface RouterFunction<T extends ServerResponse> {

13

/**

14

* Route the given request to a handler function.

15

* @param request the request to route

16

* @return an optional handler function

17

*/

18

Mono<HandlerFunction<T>> route(ServerRequest request);

19

20

// Composition methods

21

RouterFunction<T> and(RouterFunction<T> other);

22

RouterFunction<?> andOther(RouterFunction<?> other);

23

RouterFunction<T> andRoute(RequestPredicate predicate, HandlerFunction<T> handlerFunction);

24

RouterFunction<T> andNest(RequestPredicate predicate, RouterFunction<T> routerFunction);

25

}

26

```

27

28

**Usage Examples:**

29

30

```java

31

import static org.springframework.web.reactive.function.server.RouterFunctions.*;

32

import static org.springframework.web.reactive.function.server.RequestPredicates.*;

33

34

// Simple route

35

RouterFunction<ServerResponse> helloRoute = route(

36

GET("/hello"),

37

request -> ServerResponse.ok().bodyValue("Hello World!")

38

);

39

40

// Combined routes

41

RouterFunction<ServerResponse> userRoutes = route()

42

.GET("/users", this::getAllUsers)

43

.GET("/users/{id}", this::getUser)

44

.POST("/users", this::createUser)

45

.PUT("/users/{id}", this::updateUser)

46

.DELETE("/users/{id}", this::deleteUser)

47

.build();

48

```

49

50

### RouterFunctions Factory

51

52

Factory class providing static methods for creating router functions and serving resources.

53

54

```java { .api }

55

class RouterFunctions {

56

// Basic routing

57

static <T extends ServerResponse> RouterFunction<T> route(

58

RequestPredicate predicate,

59

HandlerFunction<T> handlerFunction

60

);

61

62

// Nested routing

63

static <T extends ServerResponse> RouterFunction<T> nest(

64

RequestPredicate predicate,

65

RouterFunction<T> routerFunction

66

);

67

68

// Static resources

69

static RouterFunction<?> resources(String pattern, Resource location);

70

static RouterFunction<?> resources(Function<ServerRequest, Mono<Resource>> lookupFunction);

71

}

72

```

73

74

**Usage Examples:**

75

76

```java

77

// Nested routes with path prefix

78

RouterFunction<ServerResponse> apiRoutes = nest(

79

path("/api/v1"),

80

route()

81

.GET("/users", userHandler::getAllUsers)

82

.POST("/users", userHandler::createUser)

83

.nest(path("/users/{id}"),

84

route()

85

.GET("", userHandler::getUser)

86

.PUT("", userHandler::updateUser)

87

.DELETE("", userHandler::deleteUser)

88

.build()

89

)

90

.build()

91

);

92

93

// Static resource serving

94

RouterFunction<?> staticResources = resources("/static/**",

95

new ClassPathResource("static/"));

96

```

97

98

### Handler Functions

99

100

Functional interface for handling HTTP requests and producing responses.

101

102

```java { .api }

103

@FunctionalInterface

104

interface HandlerFunction<T extends ServerResponse> {

105

/**

106

* Handle the given request.

107

* @param request the request to handle

108

* @return the response

109

*/

110

Mono<T> handle(ServerRequest request);

111

}

112

```

113

114

**Usage Examples:**

115

116

```java

117

// Simple handler

118

HandlerFunction<ServerResponse> helloHandler = request ->

119

ServerResponse.ok().bodyValue("Hello, " + request.pathVariable("name"));

120

121

// Handler with request body

122

HandlerFunction<ServerResponse> createUserHandler = request ->

123

request.bodyToMono(User.class)

124

.flatMap(userService::save)

125

.flatMap(user -> ServerResponse.ok().bodyValue(user))

126

.onErrorResume(ex -> ServerResponse.badRequest().bodyValue("Invalid user data"));

127

128

// Handler class

129

@Component

130

public class UserHandler {

131

132

public Mono<ServerResponse> getAllUsers(ServerRequest request) {

133

return userService.findAll()

134

.collectList()

135

.flatMap(users -> ServerResponse.ok().bodyValue(users));

136

}

137

138

public Mono<ServerResponse> getUser(ServerRequest request) {

139

String id = request.pathVariable("id");

140

return userService.findById(id)

141

.flatMap(user -> ServerResponse.ok().bodyValue(user))

142

.switchIfEmpty(ServerResponse.notFound().build());

143

}

144

}

145

```

146

147

### Request Predicates

148

149

Interface for matching HTTP requests in functional routing with logical operations.

150

151

```java { .api }

152

@FunctionalInterface

153

interface RequestPredicate {

154

/**

155

* Evaluate this predicate on the given request.

156

* @param request the request to match against

157

* @return true if the request matches the predicate

158

*/

159

boolean test(ServerRequest request);

160

161

/**

162

* Return a composed predicate based on a nest operation.

163

* @param request the request to nest

164

* @return an optional nested request

165

*/

166

Optional<ServerRequest> nest(ServerRequest request);

167

168

// Logical operations

169

RequestPredicate and(RequestPredicate other);

170

RequestPredicate negate();

171

RequestPredicate or(RequestPredicate other);

172

}

173

```

174

175

### RequestPredicates Factory

176

177

Factory class providing static methods for creating request predicates.

178

179

```java { .api }

180

class RequestPredicates {

181

// Basic predicates

182

static RequestPredicate all();

183

static RequestPredicate method(HttpMethod httpMethod);

184

static RequestPredicate path(String pattern);

185

static RequestPredicate pathExtension(String extension);

186

static RequestPredicate pathExtension(Predicate<String> extensionPredicate);

187

188

// HTTP method predicates

189

static RequestPredicate GET(String pattern);

190

static RequestPredicate POST(String pattern);

191

static RequestPredicate PUT(String pattern);

192

static RequestPredicate DELETE(String pattern);

193

static RequestPredicate PATCH(String pattern);

194

static RequestPredicate HEAD(String pattern);

195

static RequestPredicate OPTIONS(String pattern);

196

197

// Parameter and header predicates

198

static RequestPredicate queryParam(String name, String value);

199

static RequestPredicate queryParam(String name, Predicate<String> predicate);

200

static RequestPredicate header(String name, String value);

201

static RequestPredicate header(String name, Predicate<String> predicate);

202

203

// Content negotiation predicates

204

static RequestPredicate contentType(MediaType... mediaTypes);

205

static RequestPredicate accept(MediaType... mediaTypes);

206

}

207

```

208

209

**Usage Examples:**

210

211

```java

212

// HTTP method predicates

213

RequestPredicate getUsersPredicate = GET("/users");

214

RequestPredicate createUserPredicate = POST("/users");

215

216

// Combined predicates

217

RequestPredicate jsonApiPredicate = GET("/api/**")

218

.and(accept(MediaType.APPLICATION_JSON))

219

.and(header("X-API-Version", "v1"));

220

221

// Query parameter predicates

222

RequestPredicate searchPredicate = GET("/search")

223

.and(queryParam("q", q -> !q.isEmpty()));

224

225

// Path extension predicates

226

RequestPredicate imagesPredicate = path("/images/**")

227

.and(pathExtension(ext -> ext.matches("jpg|png|gif")));

228

```

229

230

### Server Request

231

232

Interface representing server-side HTTP request in the functional model with comprehensive access to request data.

233

234

```java { .api }

235

interface ServerRequest {

236

// Basic request information

237

HttpMethod method();

238

URI uri();

239

UriBuilder uriBuilder();

240

String path();

241

RequestPath requestPath();

242

243

// Headers and cookies

244

Headers headers();

245

MultiValueMap<String, HttpCookie> cookies();

246

247

// Network information

248

Optional<InetSocketAddress> remoteAddress();

249

Optional<InetSocketAddress> localAddress();

250

251

// Body extraction

252

List<HttpMessageReader<?>> messageReaders();

253

<T> T body(BodyExtractor<T, ? super ServerHttpRequest> extractor);

254

<T> Mono<T> bodyToMono(Class<? extends T> elementClass);

255

<T> Mono<T> bodyToMono(ParameterizedTypeReference<T> elementTypeRef);

256

<T> Flux<T> bodyToFlux(Class<? extends T> elementClass);

257

<T> Flux<T> bodyToFlux(ParameterizedTypeReference<T> elementTypeRef);

258

259

// Path variables and query parameters

260

Optional<String> pathVariable(String name);

261

Map<String, String> pathVariables();

262

Optional<String> queryParam(String name);

263

MultiValueMap<String, String> queryParams();

264

265

// Session and security

266

Mono<WebSession> session();

267

Mono<? extends Principal> principal();

268

269

// Data binding

270

Mono<ServerRequest> bind(Object bean);

271

272

// Access to underlying exchange

273

ServerWebExchange exchange();

274

}

275

```

276

277

**Usage Examples:**

278

279

```java

280

// Extract path variables

281

HandlerFunction<ServerResponse> getUserHandler = request -> {

282

String userId = request.pathVariable("id");

283

return userService.findById(userId)

284

.flatMap(user -> ServerResponse.ok().bodyValue(user))

285

.switchIfEmpty(ServerResponse.notFound().build());

286

};

287

288

// Extract query parameters

289

HandlerFunction<ServerResponse> searchHandler = request -> {

290

String query = request.queryParam("q").orElse("");

291

int page = request.queryParam("page")

292

.map(Integer::parseInt)

293

.orElse(0);

294

295

return searchService.search(query, page)

296

.flatMap(results -> ServerResponse.ok().bodyValue(results));

297

};

298

299

// Extract request body

300

HandlerFunction<ServerResponse> createUserHandler = request ->

301

request.bodyToMono(User.class)

302

.flatMap(user -> {

303

// Validate user

304

if (user.getName() == null || user.getName().isEmpty()) {

305

return ServerResponse.badRequest()

306

.bodyValue("Name is required");

307

}

308

return userService.save(user)

309

.flatMap(savedUser -> ServerResponse

310

.created(URI.create("/users/" + savedUser.getId()))

311

.bodyValue(savedUser));

312

});

313

```

314

315

### Server Response

316

317

Interface representing server-side HTTP response with static factory methods for common response types.

318

319

```java { .api }

320

interface ServerResponse {

321

// Response information

322

HttpStatusCode statusCode();

323

HttpHeaders headers();

324

MultiValueMap<String, ResponseCookie> cookies();

325

326

// Write response

327

Mono<Void> writeTo(ServerWebExchange exchange, Context context);

328

329

// Static factory methods - Status codes

330

static BodyBuilder from(ServerResponse other);

331

static Mono<ServerResponse> from(ErrorResponse response);

332

static BodyBuilder status(HttpStatusCode status);

333

static BodyBuilder status(int status);

334

335

// 2xx Success

336

static BodyBuilder ok();

337

static BodyBuilder created(URI location);

338

static BodyBuilder accepted();

339

static BodyBuilder noContent();

340

341

// 3xx Redirection

342

static BodyBuilder seeOther(URI location);

343

static BodyBuilder notModified();

344

static BodyBuilder temporaryRedirect(URI location);

345

static BodyBuilder permanentRedirect(URI location);

346

347

// 4xx Client Error

348

static BodyBuilder badRequest();

349

static BodyBuilder notFound();

350

static BodyBuilder unprocessableEntity();

351

}

352

```

353

354

**Usage Examples:**

355

356

```java

357

// Simple responses

358

return ServerResponse.ok().bodyValue("Success");

359

return ServerResponse.notFound().build();

360

return ServerResponse.created(URI.create("/users/123")).bodyValue(user);

361

362

// Response with headers

363

return ServerResponse.ok()

364

.header("X-Custom-Header", "value")

365

.contentType(MediaType.APPLICATION_JSON)

366

.bodyValue(data);

367

368

// Response with cookies

369

return ServerResponse.ok()

370

.cookie(ResponseCookie.from("session", sessionId)

371

.httpOnly(true)

372

.secure(true)

373

.build())

374

.bodyValue("Authenticated");

375

```

376

377

### Server Response Body Builder

378

379

Interface for building responses with body content and comprehensive header/cookie support.

380

381

```java { .api }

382

interface BodyBuilder extends ServerResponse.HeadersBuilder<BodyBuilder> {

383

// Headers

384

BodyBuilder header(String headerName, String... headerValues);

385

BodyBuilder headers(Consumer<HttpHeaders> headersConsumer);

386

BodyBuilder cookie(ResponseCookie cookie);

387

BodyBuilder cookies(Consumer<MultiValueMap<String, ResponseCookie>> cookiesConsumer);

388

389

// HTTP headers

390

BodyBuilder allow(HttpMethod... allowedMethods);

391

BodyBuilder allow(Set<HttpMethod> allowedMethods);

392

BodyBuilder contentType(MediaType contentType);

393

BodyBuilder contentLength(long contentLength);

394

BodyBuilder lastModified(ZonedDateTime lastModified);

395

BodyBuilder lastModified(Instant lastModified);

396

BodyBuilder location(URI location);

397

BodyBuilder cacheControl(CacheControl cacheControl);

398

BodyBuilder varyBy(String... requestHeaders);

399

400

// Build response

401

Mono<ServerResponse> build();

402

Mono<ServerResponse> build(Publisher<Void> voidPublisher);

403

404

// Body methods

405

Mono<ServerResponse> bodyValue(Object body);

406

<T, P extends Publisher<T>> Mono<ServerResponse> body(P publisher, Class<T> elementClass);

407

<T, P extends Publisher<T>> Mono<ServerResponse> body(P publisher, ParameterizedTypeReference<T> elementTypeRef);

408

Mono<ServerResponse> body(Object producer, Class<?> elementClass);

409

Mono<ServerResponse> body(Object producer, ParameterizedTypeReference<?> elementTypeRef);

410

Mono<ServerResponse> body(BodyInserter<?, ? super ServerHttpResponse> inserter);

411

412

// View rendering

413

Mono<ServerResponse> render(String name, Object... modelAttributes);

414

Mono<ServerResponse> render(String name, Map<String, ?> model);

415

}

416

```

417

418

**Usage Examples:**

419

420

```java

421

// JSON response with caching

422

return ServerResponse.ok()

423

.contentType(MediaType.APPLICATION_JSON)

424

.cacheControl(CacheControl.maxAge(Duration.ofMinutes(10)))

425

.bodyValue(data);

426

427

// Stream response

428

Flux<DataItem> dataStream = dataService.getDataStream();

429

return ServerResponse.ok()

430

.contentType(MediaType.APPLICATION_NDJSON)

431

.body(dataStream, DataItem.class);

432

433

// Template rendering

434

return ServerResponse.ok()

435

.render("user-profile", Map.of(

436

"user", user,

437

"posts", posts

438

));

439

```

440

441

### Specialized Responses

442

443

Specialized response types for strongly-typed entities and template rendering.

444

445

```java { .api }

446

interface EntityResponse<T> extends ServerResponse {

447

/**

448

* Return the entity that makes up this response.

449

*/

450

T entity();

451

452

// Static factory methods

453

static <T> Builder<T> fromObject(T t);

454

static <T> BodyBuilder fromPublisher(Publisher<T> publisher, Class<T> elementClass);

455

static <T> BodyBuilder fromPublisher(Publisher<T> publisher, ParameterizedTypeReference<T> elementTypeRef);

456

}

457

458

interface RenderingResponse extends ServerResponse {

459

/**

460

* Return the name of the template to be rendered.

461

*/

462

String name();

463

464

/**

465

* Return the unmodifiable model map.

466

*/

467

Map<String, Object> model();

468

469

// Static factory method

470

static Builder create(String name);

471

}

472

```

473

474

### Handler Filters

475

476

Interface for filtering handler function execution with pre/post processing.

477

478

```java { .api }

479

@FunctionalInterface

480

interface HandlerFilterFunction<T extends ServerResponse, R extends ServerResponse> {

481

/**

482

* Filter the given handler function.

483

* @param request the request

484

* @param next the next handler or filter in the chain

485

* @return the filtered response

486

*/

487

Mono<R> filter(ServerRequest request, HandlerFunction<T> next);

488

489

/**

490

* Apply this filter to the given handler function.

491

* @param handlerFunction the handler function to filter

492

* @return a filtered handler function

493

*/

494

default HandlerFunction<R> apply(HandlerFunction<T> handlerFunction) {

495

return request -> filter(request, handlerFunction);

496

}

497

}

498

```

499

500

**Usage Examples:**

501

502

```java

503

// Logging filter

504

HandlerFilterFunction<ServerResponse, ServerResponse> loggingFilter =

505

(request, next) -> {

506

logger.info("Processing request: {} {}", request.method(), request.path());

507

return next.handle(request)

508

.doOnSuccess(response ->

509

logger.info("Response status: {}", response.statusCode()));

510

};

511

512

// Authentication filter

513

HandlerFilterFunction<ServerResponse, ServerResponse> authFilter =

514

(request, next) -> {

515

return request.headers().firstHeader("Authorization")

516

.map(authService::validateToken)

517

.filter(Boolean::booleanValue)

518

.map(valid -> next.handle(request))

519

.orElse(ServerResponse.status(HttpStatus.UNAUTHORIZED).build());

520

};

521

522

// Apply filters to routes

523

RouterFunction<ServerResponse> protectedRoutes = route()

524

.GET("/admin/**", adminHandler::handleAdminRequest)

525

.filter(authFilter)

526

.filter(loggingFilter)

527

.build();

528

```

529

530

### Handler Strategies

531

532

Configuration interface for HTTP message readers, writers, and other strategies used by handler functions.

533

534

```java { .api }

535

interface HandlerStrategies {

536

// Strategy components

537

List<HttpMessageReader<?>> messageReaders();

538

List<HttpMessageWriter<?>> messageWriters();

539

List<ViewResolver> viewResolvers();

540

541

// Configuration

542

Builder mutate();

543

544

// Factory methods

545

static HandlerStrategies withDefaults();

546

static Builder builder();

547

static Builder empty();

548

}

549

```

550

551

### Resource Handling

552

553

Handler function for serving static resources with lookup capabilities.

554

555

```java { .api }

556

class ResourceHandlerFunction implements HandlerFunction<ServerResponse> {

557

/**

558

* Create a new ResourceHandlerFunction with the given Resource.

559

* @param resource the resource to serve

560

*/

561

ResourceHandlerFunction(Resource resource);

562

563

/**

564

* Create a new ResourceHandlerFunction with the given lookup function.

565

* @param lookupFunction function to look up the Resource

566

*/

567

ResourceHandlerFunction(Function<ServerRequest, Mono<Resource>> lookupFunction);

568

569

@Override

570

Mono<ServerResponse> handle(ServerRequest request);

571

}

572

```

573

574

**Usage Examples:**

575

576

```java

577

// Single resource handler

578

ResourceHandlerFunction faviconHandler =

579

new ResourceHandlerFunction(new ClassPathResource("favicon.ico"));

580

581

// Dynamic resource lookup

582

ResourceHandlerFunction dynamicHandler =

583

new ResourceHandlerFunction(request -> {

584

String path = request.path().replaceFirst("/static", "");

585

return Mono.just(new ClassPathResource("static" + path));

586

});

587

588

// Register as route

589

RouterFunction<ServerResponse> staticRoutes = route()

590

.GET("/favicon.ico", faviconHandler)

591

.GET("/static/**", dynamicHandler)

592

.build();

593

```