The Manifest and Compatibility
A service's Manifest is its contract in one document: its contexts, aggregates, commands, events, state schemas, subscriptions, published streams and error codes. The routes, the OpenAPI document, the generated clients, wait plans and query admission are all derived from it. This page follows it from the compiler to the service, to its peers and to the compatibility check. One Contract: the Manifest explains why it exists.
From fragments to the service's Manifest
- The compiler writes each domain module's fragment,
META-INF/wow/manifest/<module>.json(What the Compiler Generates). - The Gradle plugin (
generateWowManifestFragment) completes the fragment with the JSON Schemas of its types, the query keywords and the state's fingerprint. The completed fragment replaces the compiler's in the module's resources. - At build time,
mergeWowManifestmerges the fragments of the service's runtime class path intobuild/wow/manifest.json. - At startup, the host merges the same fragments, adds the framework's error codes, and serves the result at
GET /wow/manifest.
The snapshot queries read the state schema from the completed fragment: a state field can be filtered and sorted only once the plugin has completed it.
Peers get their part
A service that sends another context's commands, or reads its published stream, needs that context's commands, events, state and errors. The plugin selects them from the other context's fragment and puts them in its api module's jar, as META-INF/wow/contract.json. A service that depends on the api module finds the contract on its class path, and uses it to name the commands it sends, check the wait plans that cross into the other context, and decode its published events. Nothing is configured: depending on the api is enough.
A tool that cannot take the api jar, such as a console or a gateway, reads the peer's Manifest from its GET /wow/manifest instead (Call Other Services).
The compatibility check
Each service commits its merged Manifest as a baseline, manifest/baseline.json. checkManifestCompatibility, part of check, compares every build's merged Manifest with it and sorts each difference:
| Kind | Examples | Within the baseline's major version |
|---|---|---|
| Additive | A new command, event or aggregate; a new optional field | Allowed |
| Breaking | A removed command or event; a new required field; a field removed or retyped; an event's schema changed without a new revision and upgrade | Fails the build, listing each change and its path |
build/wow/manifest-compatibility.txt lists every change, additive ones too. After an intended change, updateManifestBaseline records the new baseline: commit it with the change, so its review shows what clients and peers will see. The eShop regenerates its TypeScript clients from the baselines, so a client and its service never drift apart unnoticed.
A breaking change needs a new major version of the service's contract, or a new command or event beside the old one, the old one retired once its last client has moved.
What reads the Manifest
| Reader | Uses it for |
|---|---|
| The host | Its routes, wait plans, query admission (ownership, schemas), the internal port's call permissions |
| The OpenAPI document | Every route, its request and response schemas (OpenAPI and springdoc) |
| The TypeScript generator | Typed command and query clients |
| The view engine | The fields and capabilities a view may use |
| Peers | Their contract with this context, through its api jar |
| The ops console and migrate-data | Commands, subscriptions and types by name |