WebFlux
The WebFlux extension provides support for Spring WebFlux, depending on the routing specifications generated by the wow-openapi module, automatically registering command route handlers to implement declarative REST APIs.
Installation
implementation("me.ahoo.wow:wow-webflux")implementation 'me.ahoo.wow:wow-webflux'<dependency>
<groupId>me.ahoo.wow</groupId>
<artifactId>wow-webflux</artifactId>
<version>${wow.version}</version>
</dependency>Automatic Route Registration
The WebFlux extension automatically generates REST API endpoints for all commands:
Route Patterns
Supports multiple route patterns:
Aggregate Route Pattern
@StaticTenantId
@AggregateRoot
@AggregateRoute(owner = AggregateRoute.Owner.AGGREGATE_ID)
class Cart(private val state: CartState)
// Generated route: POST /owner/{ownerId}/cart/add_cart_itemOwner Route Pattern
@AggregateRoot
@AggregateRoute(
resourceName = "sales-order",
spaced = true,
owner = AggregateRoute.Owner.ALWAYS,
)
class Order(private val state: OrderState)
@CommandRoute(action = "")
@CreateAggregate
data class CreateOrder(/* ... */)
// Generated route: POST /tenant/{tenantId}/owner/{ownerId}/sales-order
// Wow-Space-Id is optional; omit it to use the default space.HTTP Method Mapping
| Command Annotation | HTTP Method | Default Path |
|---|---|---|
@CreateAggregate | POST | /{resource} |
@CommandRoute(method = POST) | POST | /{resource}/{command} |
@CommandRoute(method = PUT) | PUT | /{resource}/{command} |
@CommandRoute(method = DELETE) | DELETE | /{resource}/{command} |
Configuration
Prerequisite
WebFluxProperties and WebFluxAutoConfiguration live in wow-spring-boot-starter, not wow-webflux. You need wow-spring-boot-starter (with the webflux-support capability) plus wow-webflux for these properties to be bound.
- Configuration class: WebFluxProperties
- Prefix:
wow.webflux.
| Name | Data Type | Default Value | Description |
|---|---|---|---|
enabled | Boolean | true | Whether to enable the WebFlux extension (route registration) |
global-error.enabled | Boolean | true | Whether to install the global exception handler that maps errors to the unified ErrorInfo response |
batch.concurrency | Int | 1 | Maximum concurrent requests processed in a single batch execution |
batch.prefetch | Int | 1 | Prefetch window for batch request processing |
wow:
webflux:
enabled: true
global-error:
enabled: true
batch:
concurrency: 4
prefetch: 4When wow-spring-boot-starter is used, WebFlux is included as the webflux-support feature capability. The global error handler is enabled by default; disable it only if you provide your own WebExceptionHandler.
Wait Plan Integration
The WebFlux extension supports specifying wait plans through HTTP headers:
POST /owner/cart-123/cart/add_cart_item
Content-Type: application/json
Command-Wait-Stage: PROCESSED
Command-Wait-Timeout: 30000
{
"productId": "product-456",
"quantity": 2
}Supported Wait Plans
All six command stages are selectable as wait plans (see Command Gateway for prerequisites and semantics):
SENT: Command accepted by the busPROCESSED: Aggregate has executed the commandSNAPSHOT: Aggregate snapshot persistedPROJECTED: Read-model projections updated (function-aware)EVENT_HANDLED: External event processors finished (function-aware)SAGA_HANDLED: Saga finished processing the events (function-aware)
When Accept: text/event-stream is sent, the handler streams CommandResult events (one per stage) over SSE instead of returning a single JSON response.
Error Handling
The WebFlux extension provides unified error response format:
{
"errorCode": "VALIDATION_ERROR",
"errorMsg": "Product not found",
"requestId": "req-123"
}The response HTTP status is derived from the error: Wow ErrorInfoCapable / ErrorInfo exceptions and Spring ErrorResponse carry their own status; binding and validation errors map to 400; IllegalArgumentException/IllegalStateException map to 400; TimeoutException maps to 408 (REQUEST_TIMEOUT); FileNotFoundException to 404; otherwise the framework falls back to 500. Only specialized errors such as BiDeploymentInspectionException.Timeout map to 504 (gateway timeout). The Wow-Error-Code response header carries the Wow errorCode for machine-readable handling.
OpenAPI Integration
Automatically generates OpenAPI documentation:
paths:
/owner/{ownerId}/cart/add_cart_item:
post:
summary: "Add item to cart"
parameters:
- name: ownerId
in: path
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/AddCartItem'Performance Optimization
Reactive Processing
All endpoints use reactive programming:
@RestController
class CustomController(
private val commandGateway: CommandGateway
) {
@PostMapping("/custom/{id}")
fun customCommand(@PathVariable id: String): Mono<CommandResult> {
val command = CustomCommand(id = id).toCommandMessage()
return commandGateway.sendAndWait(
command,
CommandWait.processed(command.commandId)
)
}
}Wow's handlers remain non-blocking. Configure codecs, Reactor Netty resources, and server timeouts through the corresponding Spring Boot facilities; the Wow WebFlux extension does not define its own connection-pool or session-timeout properties.
Monitoring and Debugging
Request Logging
logging:
level:
me.ahoo.wow.webflux: DEBUGWow-specific runtime metrics are provided by the observability integration, not automatically by wow-webflux. See OpenTelemetry for the supported instrumentation.
Best Practices
- Use Wait Plans: Choose appropriate wait plans based on business requirements
- Error Handling: Implement global exception handlers
- Security: Enable authentication and authorization checks
- Observability: Add the OpenTelemetry capability when Wow runtime traces and metrics are required
- Runtime tuning: Configure Reactor Netty and Spring Boot server limits at the application boundary