HTTP and TypeScript Clients
V10 changes the routes, the headers, the errors and the client packages, and keeps no compatibility layer: every caller of a service moves with it. The order is fixed. The service's source migration produces its V10 Manifest first; the TypeScript clients are generated again from that Manifest; then the application is fixed by what the type check reports. The wow-migrate Skill does this part too, from its reference http-and-clients.md.
Routes
| 9.x | V10 |
|---|---|
POST /<context>/[tenant/{tenantId}/][owner/{ownerId}/]<aggregate>/{id}/<action>, with PUT, PATCH and custom actions | POST /<context>/<aggregate>/{id}/<command>, the command in kebab case; a creating command also without {id}. The tenant and owner come from the caller, never the path |
DELETE …/{id}, PUT …/{id}/recover, PUT …/{id}/tags | DELETE /<context>/<aggregate>/{id}, POST …/{id}/wow.lifecycle.restore-aggregate, POST …/{id}/wow.lifecycle.apply-tags |
…/snapshot/{single,list,paged,cursor,count,aggregation}, their /state forms, …/event/… | POST /<context>/<aggregate>/snapshot/query and …/events/query, the operation in the body's kind |
GET …/snapshot/schema | GET on the same query route: the capability descriptor, with its ETag |
GET …/{id}/state/{version}, …/state/tracing | GET /<context>/<aggregate>/{id}/state with ?version=, ?at= or ?minVersion=, and …/state/trace |
PUT …/{id}/snapshot (regenerate) | POST /<context>/snapshot/<aggregate>/wow.snapshot.rebuild with {"ids": [...]} |
| State-event resend, per-version re-dispatch | None until 10.x; a failed version is a parked entry, resumed under /wow/ops/parked |
/wow/command/send, /wow/command/wait | The per-command routes |
/dataset/… | GET /wow/dataset, POST /wow/dataset/<context>/<dataset>/query |
Read the 9.x paths from the service's generated 9.x OpenAPI, not from its annotations. Every gateway rule, CoSec policy and API document that names a 9.x path changes with it. HTTP API lists the V10 routes.
Headers
| 9.x | V10 |
|---|---|
Command-Wait-Stage, -Context, -Processor, -Function, Command-Wait-Tail-* | Wow-Wait: a plan of hops, accepted, committed, snapshot, handled([context/]Processor.function), joined with >; snapshot by default |
Command-Wait-Timeout | Wow-Wait-Timeout: 500ms, 10s or ISO-8601 |
Command-Request-Id | Wow-Request-Id |
Command-Aggregate-Version | If-Match: "<version>"; reads answer ETag |
Command-Tenant-Id, Command-Owner-Id, Command-Aggregate-Id | The caller and the route; a caller allowed to act elsewhere sends Wow-Scope; Wow-Space picks one of the caller's spaces |
Command-Local-First, Command-Type, Command-Header-* | Gone; the headers a service keeps as request facts are listed in wow.http.request-facts |
CoSec-Request-Id, CoSec-Space-Id read as aliases | Not read: a gateway rewrites them to Wow-Request-Id and Wow-Space |
9.x wait stages map by meaning: SENT is accepted, PROCESSED is committed, SNAPSHOT is snapshot, and PROJECTED, EVENT_HANDLED and SAGA_HANDLED are a handled hop that names the subscription.
Errors
A 9.x error body, errorCode, errorMsg and bindingErrors, is an RFC 9457 problem in V10, application/problem+json: type urn:wow:error:<code>, title, status, detail, code, violations, and the command's whole result once it reached its aggregate. Every code changed: the framework's are wow.* (wow.aggregate.not-found, wow.aggregate.version-mismatch, wow.command.busy), and a domain rejection is <context>.<aggregate>.<code>, 422 unless the service declares another status. Search the application for every 9.x code it matches, and map each (Error Codes).
TypeScript packages
| 9.x | V10 |
|---|---|
@ahoo-wang/fetcher-wow, or a 9.x @ahoo-wang/wow-client | @ahoo-wang/wow-client of the V10 version, with the peers @ahoo-wang/fetcher and @ahoo-wang/fetcher-eventstream |
@ahoo-wang/fetcher-generator, or a 9.x wow-generator reading /v3/api-docs | @ahoo-wang/wow-generator of the V10 version, reading the service's Manifest: GET /wow/manifest or its committed manifest/baseline.json. The OpenAPI-to-Wow path, the fetcher-generator command and fetcher-generator.config.json are gone |
@ahoo-wang/fetcher-react's Wow hooks, or a 9.x wow-react | @ahoo-wang/wow-react of the V10 version |
@ahoo-wang/fetcher-viewer (frozen at 5.x), and fetcher-react's data monitor it used | @ahoo-wang/wow-view-engine, rebuilt with a definition and a host |
| The 9.x view store's routes | @ahoo-wang/wow-view-store's WowViewStore on the V10 view store service |
Keep every Wow package on one V10 minor (Compatibility and Versions). The fetcher repository's agent Skills for these packages, fetcher-wow-cqrs and fetcher-openapi-generator, became Wow's wow-client Skill. The @ahoo-wang/fetcher core packages stay in their own repository and are peers of every Wow package; no fetcher package depends on a Wow one.
Client code
| 9.x | V10 |
|---|---|
CommandClient.send(…) with commandHeaders and waitStrategy({ stage: CommandStage.SNAPSHOT }) | The generated <Aggregate>CommandClient.<command>(body, { id, wait: { plan: [wait.snapshot()] } }) |
sendAndWaitStream | The generated …Stream method |
QueryClientFactory, <aggregate>QueryClientFactory | The generated <Aggregate>SnapshotQueryClient, <Aggregate>EventQueryClient and <Aggregate>StateClient |
pagedState, listState, singleState | paged, list, single, answering whole records: read record.state, or project with a literal include |
getStateById(id) | <Aggregate>StateClient.get(id), with minVersion after a command |
EventStreamQueryClient, records of body[] with bodyType | EventQueryClient: commits with events[] of { name, revision, body }, name being <context>.<aggregate>.<Event> |
@ahoo-wang/wow-client/legacy (Condition) | Gone: filter.* from @ahoo-wang/wow-client/dsl |
urlParams.path.{ tenantId, ownerId }, contextAlias | Nothing, the caller decides them; basePath for a gateway prefix |
toWowError, ErrorCodes, errorCode, bindingErrors | error instanceof WowProblemError: code, status, violations, retry; FrameworkErrorCodes and the generated <Context>ErrorCodes |
| A failed command resolving with its error code | Every refusal and every command that did not succeed rejects; resolveRejected: true resolves instead |
TypeScript describes the V10 clients.
What changes without a type error
- Error codes are strings the compiler cannot check: grep for each 9.x code.
- Exact numbers. A
Long,BigIntegerorBigDecimalfield is astringin V10's types, read exactly. Code that did arithmetic on anumbernow concatenates strings unless it is fixed. - Time zones. A relative-time filter without
zoneIdreads its days in UTC, where 9.x used the server's zone: passzoneIdwhere a local day was meant. - Event names. 9.x
bodyTypeclass names becomenamevalues; saved filters and screens keyed on them change. - Snapshot fields. 9.x
eventIdandsnapshotTimeare gone;firstEventTime,lastEventTime,operator,firstOperatorandtagsremain.
Steps
- The service's V10 Manifest exists and passes its compatibility baseline.
- Replace the packages, generate the clients from the Manifest into the same directory, commit
.wow-generator.json, and delete the 9.x generator configuration and scripts (Generate a Client). - Run
tscand fix each error by the tables above, never with a cast orany; then the linter and the application's tests. - Search for what the type check cannot see: 9.x error codes,
bodyType, 9.x paths in fetches, gateway rules and CoSec policies, relative times withoutzoneId, arithmetic on exact numbers. - Run the application against the V10 service, in development or staging: a command with its wait, a state read, a query, and a refusal shown to the user.
Kotlin and Java callers of a 9.x service's routes, wow-apiclient and CommandGateway, move to the CommandClient and QueryApi clients (Calling Other Services).