In 0202 we copied the shapes of the responses by hand. That holds until the API changes: then nobody notices a renamed field until a visitor sees an empty column. It is better to reverse the path: the API describes itself in an OpenAPI document (K2 2.3.10), this document is the contract (K2 2.12.2), and the client is generated from it. This lesson tries five tools on the same small document, decides on one with an ADR, switches the contact list over and builds a test that turns red when the contract breaks.

State of the checks. Everything ran in a throwaway project outside the repository (Node 24.22.3, Angular 22.2.6, TypeScript 6.0.3, Vitest 5.1.0, .NET SDK 10.0.400, Java 11). The document openapi/kladde.json is written by hand and matches the contract of the course plan (OpenAPI 3.1.1, 8 operations, 9 schemas); it does not come from a running API. What was run: ng-openapi-gen 1.1.0, @hey-api/openapi-ts 0.99.0, the Kiota command line 1.38.0, the OpenAPI Generator 7.27.0 (npm package @openapitools/openapi-generator-cli 2.42.2) and openapi-typescript 7.13.0. All results except that of openapi-typescript were compiled with tsc (exit code 0); ng-openapi-gen is built into the application (npm run build and ng test --no-watch, exit code 0; final state after 0204: 32 tests in 7 files). The Kiota client ran in Node against a small test server of our own (200 and a 409 with ProblemDetails). Not run: generation from the Kladde API itself, pipelines, calls of the clients of hey-api and OpenAPI Generator. Versions and licenses come from the npm registry on the day of writing; the license of the Kiota command line is open.

The contract first

The contract describes paths, parameters and responses, as the API offers them. It belongs to the API; the front end reads it and generates its types from it instead of maintaining a second truth. The document lives in the front end's repository as openapi/kladde.json (copied from the API's), the generated types do not live there. If the contract changes, the client changes with the next build, and the compiler shows every place that still misunderstands it. The contract describes the shape, not the behavior.