REST contract & codegen workflow
The backend owns the wire contract. The frontend consumes committed snapshots, generates REST type declarations, then exposes hand-maintained application types to the rest of the UI.
Files
contracts/rest/simulator.openapi.jsonis the OpenAPI input.src/api/generated/contains generated declarations only; it is not an HTTP client and must not be edited.src/api/types.tsis the application facade.contracts/signalr/simulator.signalr.jsondescribes live events.contracts/typescript/simulator.types.snapshot.jsonrecords selected application-facade shapes for backend parity tests.
Change sequence
- Change the backend DTO or endpoint, update its tests, regenerate its published snapshots, and land that backend change first.
- Copy the REST and SignalR snapshots into the frontend's
contracts/directory. - Run
npm run generate:rest-types. - Adapt
src/api/types.ts,src/api/signalrEvents.ts, and callers as needed. - Run
npm run snapshot-typesafter changing a supported facade type. - Validate the generated TypeScript snapshot at the backend parity seam.
- Run the frontend contract tests and both repositories' gates.
- Land the compatible frontend change.
Generated names are not the product API. Keep generated imports inside the facade and the few explicit contract tests. This limits generator churn and gives UI code one stable vocabulary.
Compatibility rules
Adding an optional response field is usually additive. Removing, renaming, changing requiredness, narrowing an enum, or changing nullability is breaking until every consumer moves. Property names are camelCase on the wire and must agree across DTOs, OpenAPI, generated types, and the snapshot.
SignalR events need the same discipline. src/api/signalrContract.test.ts compares handler payload types with the SignalR snapshot, so a REST-green change does not prove live payload compatibility.
Diagnose drift
If generation changes unexpectedly, diff the OpenAPI snapshot first. If backend parity fails, regenerate the frontend snapshot from the compatible facade rather than editing JSON by hand. If UI code imports generated modules directly, move that use behind src/api/types.ts before resolving the shape.
Never invent the frontend DTO first. The backend is authoritative, and its parity suite is designed to reject a frontend-only contract.
Updated 2026-09-10 · Edit on GitHub