Counterfact generates two directories from your OpenAPI document:
- 📂
types/— fully typed request/response interfaces, auto-regenerated whenever the OpenAPI document changes. Don't edit these by hand. - 📂
routes/— one TypeScript file per API path. These are yours to edit. Out of the box each file returns a random, schema-valid response. You can leave them as-is or customize as much as you like.
See the FAQ for common questions about source control, editing, and regeneration.
No OpenAPI document? See using Counterfact without OpenAPI.
When two or more versioned specs share the same operation path (e.g. GET /pets), Counterfact emits a version-mapped handler type in the shared types/paths/ file instead of a flat type.
// types/paths/pets.types.ts (generated — do not edit)
import type { Versioned } from "../../counterfact-types/index.js";
import type { MaybePromise, COUNTERFACT_RESPONSE } from "../../counterfact-types/index.js";
import type { HTTP_GET_$_v1 } from "../v1/paths/pets.types.js";
import type { HTTP_GET_$_v2 } from "../v2/paths/pets.types.js";
type HTTP_GET_$_Versions = { v1: HTTP_GET_$_v1; v2: HTTP_GET_$_v2 };
export type HTTP_GET = (
$: Versioned<HTTP_GET_$_Versions>,
) => MaybePromise<COUNTERFACT_RESPONSE>;Each version's strongly-typed $ argument lives in its own subdirectory
(types/v1/paths/pets.types.ts, types/v2/paths/pets.types.ts). The shared
file imports and combines them via Versioned<T>, which resolves to the union
of all version argument types (V1$ | V2$). Your route handler can then
narrow the type to the specific version using discriminant fields on $.
When only a single (unversioned) spec is configured the output is unchanged from the flat-type format.