Generate TypeScript contracts from a versioned FastAPI OpenAPI artifact, pin the generator and fail the build when regeneration exposes incompatible consumer code. Keep generated files separate from hand-written authentication and runtime validation. Types help only when the schema is current and the consumer uses them; they do not verify an arbitrary JSON response at runtime.
Freeze the input before generating
Export OpenAPI from the intended application revision in a controlled build or test process. Record the schema digest, framework version, generator version and generation command. Production documentation can be disabled without preventing a controlled schema export; do not enable a public schema endpoint solely for code generation. Review stable unique operation IDs so routine route refactoring does not unexpectedly rename client methods.
FastAPI's client-generation guide explains how OpenAPI and operation IDs feed TypeScript generation. Choose a generator according to the needed output: some produce types, others produce runtime SDK code. The executed experiment here uses openapi-typescript for runtime-free declarations, not a full generated HTTP SDK. Authentication injection and response validation remain hand-written integration decisions.
FastAPI: OpenAPI client generation and operation IDs
openapi-typescript: generated declarations and CLI usage
Executed synthetic breaking change
Two local OpenAPI 3.1 schemas expose GET /profile with operationId getProfile. Version one requires displayName; version two replaces it with name. We generated declarations using openapi-typescript 7.13.0 on Node v22.16.0, then compiled the same old consumer expression against both schemas with TypeScript 5.9.3. The v1 consumer had no diagnostics. The v2 consumer failed with TS2339 because displayName no longer exists.
import type { operations } from './schema-v1';
type Profile = operations['getProfile']['responses'][200]
['content']['application/json'];
declare const result: Profile;
const label: string = result.displayName;
// Switch to schema-v2: TS2339 for displayName.The snippet illustrates the generated indexed type; the saved consumer files contain the exact compilable formatting. The experiment used synthetic local schemas rather than importing the private application's FastAPI process. It proves the generator-and-consumer drift mechanism for one field rename, not live endpoint behavior or compatibility with every installed app version.
| Input | Consumer expression | Observed result |
|---|---|---|
| v1: displayName required | result.displayName | No diagnostics |
| v2: name replaces displayName | result.displayName | TS2339 |
| Unchecked runtime v2 JSON | payload.displayName | undefined |
| Execution boundary | Local schemas and declarations | No live FastAPI or HTTP SDK |
Regenerate in a reviewable gate
Keep schema generation deterministic and run it with the lockfile's tools. Compare the regenerated output with the committed artifact, then type-check consumers. Do not hand-edit a generated field to make the diff disappear; fix the server contract, regenerate or intentionally migrate the caller. Review changes in requiredness, nullability, enums, status codes and security definitions as well as field names.
If the service supports older clients, compilation of the newest frontend is insufficient. Maintain representative old-consumer fixtures or a compatibility contract. A server can emit a new shape while a previously released mobile client still expects the old one. Versioning and deprecation decisions remain product responsibilities even when the generator faithfully reflects the newest schema.
Validate unknown runtime data separately
The local experiment also parsed a synthetic v2 payload in JavaScript and read the old displayName field without validation; the result was undefined. No runtime type check appeared simply because declarations existed. TypeScript documents that its type annotations are erased. Validate at the response boundary when the application needs runtime assurance, and apply domain checks for identifiers and business rules after shape validation.
TypeScript: types are erased from runtime JavaScript
Keep authentication, retries, cancellation and base-URL configuration in reviewed wrapper code or the generated SDK's supported extension points. Avoid storing credentials in generated fixtures. The retained result includes the actual compiler diagnostic, generator version and both schemas. It deliberately does not claim a network request, live FastAPI export or full SDK generation. Add those integration checks for the selected endpoint before presenting the generated client as a verified release boundary.
Mobile app API backward compatibility
Observability for small teams: start with the failed customer task
Bring one API or data workflow and a sanitized failure example for a bounded implementation assessment.
How should you generate a TypeScript client contract from FastAPI?
Freeze the OpenAPI artifact, pin generation tools and operation IDs, regenerate in CI and type-check consumers while testing runtime responses separately.
Should generated output be edited by hand?
No. Change the source contract or supported generator configuration, regenerate and review the resulting consumer migration.
Do generated TypeScript declarations validate HTTP JSON?
No. Runtime response validation and domain checks remain separate; type annotations are erased.
