API Client
wow-apiclient provides hand-maintained CoApi interfaces for Wow's generic command facade and snapshot query routes. It is a transport adapter:
CommandRequest / Query DTO
-> CoApi HTTP exchange
-> generated WebFlux route
-> command or guarded query pipelineIt does not generate server routes, discover aggregate-specific fields, create authorization headers, or turn a projection into a server-side QueryGateway. The running server's OpenAPI document remains the source of truth for the path and wire contract.
For command-client registration, CommandRequest, target-service resolution, reactive/synchronous invocation, wait capabilities, and error mapping, use the authoritative Command API Client. This page retains extension installation and snapshot-query contracts.
Features
- Reactive command and query APIs using
MonoandFlux. - Blocking synchronous variants for callers that deliberately use synchronous I/O.
- Generic command sending through
/wow/command/sendwith wait-plan headers. - Typed, state-only, and dynamic snapshot query response shapes.
- Single, list, paged, exact count, and separately opted-in aggregation calls.
- CoApi load-balanced command gateway support.
wow-apiclient is not an OpenAPI code generator. Fetcher or another downstream tool may generate a separate client from /v3/api-docs; review that generated diff independently.
Installation
Add the Wow client and CoApi Spring Boot starter:
implementation("me.ahoo.wow:wow-apiclient")
implementation("me.ahoo.coapi:coapi-spring-boot-starter")Register the exact interfaces CoApi should materialize:
@EnableCoApi(
clients = [
CartQueryClient::class,
],
)
@SpringBootApplication
class ClientApplicationGetting Started
1. Declare a Query Client
Bind a query interface to the aggregate route base. This example targets the unscoped /cart/... routes:
@CoApi(baseUrl = "http://order-service:8080")
@HttpExchange("cart")
interface CartQueryClient : ReactiveSnapshotQueryApi<CartData>ReactiveSnapshotQueryApi<S> composes single, list, paged, and count interfaces. Their inherited @PostExchange paths are relative to @HttpExchange: snapshot/single, snapshot/list, snapshot/paged, and snapshot/count, plus state-only variants.
When CoApi or application conventions require concrete generic metadata, redeclare methods with the concrete return type and @RequestBody, as the repository example clients do. Do not duplicate the route path on every method.
@HttpExchange("cart") calls the base, unscoped snapshot-query variant. To call a tenant- or owner-scoped variant, bind an application-owned interface or routing layer to that generated path and supply the required values. Protect the base route explicitly; choosing the scoped client path is not authorization. Do not guess a context-prefixed URL—inspect the server OpenAPI.
2. Declare a Command Client
See the Command API Client for command-client registration and invocation.
3. Inject and Use
@Service
class CartApplicationService(
private val carts: CartQueryClient,
) {
fun getCart(id: String): Mono<CartData> = carts.getStateById(id)
}getStateById turns HTTP 404 into an empty Mono; other query errors propagate.
Service Discovery
Query clients are different: their @CoApi(baseUrl) and @HttpExchange base determine the target. Service discovery and route scoping are application configuration, not inferred from the query DTO. Command target resolution belongs to the Command API Client.
Snapshot Query
See Query API Client for snapshot data queries, state-only/dynamic results, 404 semantics, and the separate aggregation API.
Error Handling
Query clients only normalize single-query 404 as empty/null; validation, authorization, rate-limit, timeout, and backend errors remain transport errors for the application to handle. For queries, retry only errors the application's policy classifies as transient; a query-schema validation or HTTP guard rejection will not become valid by repetition. See Command API Client and Failures and Idempotency for command error and retry boundaries.