Contracts
Two things keep the API, the web app and the worker in agreement about data shapes:
packages/contracts: hand-written shared types, constants and Zod schemas.- The OpenAPI spec:
apps/api/openapi.json, generated from the API code, and the TypeScript types generated from it for the web app.
Shared package: @booking/contracts
packages/contracts is imported by apps/api, apps/web, apps/worker and packages/db. Put code here when more than one of them needs the same definition.
| Folder / file | Contents |
|---|---|
booking-status.ts | Lifecycle, payment and display status constants and types |
authz/ | The permission catalog, the system role bundles and RBAC request schemas |
analytics/ | GA4 event schemas, custom dimensions and the parseGaCookies() helper |
availability/validators.ts | Availability request validators |
product/ | Add-on groups and visibility, checkout offers, duration options |
pricing/, policies/ | Pricing and policy schemas |
events/ | Domain event and outbound webhook payload types |
The package has three entry points: @booking/contracts, @booking/contracts/analytics and @booking/contracts/availability/validators.
Other workspaces import the built output in packages/contracts/dist. After you change a file in packages/contracts/src, rebuild it:
pnpm -F @booking/contracts build
pnpm build:packages rebuilds all shared packages.
OpenAPI spec
apps/api/openapi.json is the committed description of every API route. It is generated from the @nestjs/swagger decorators on the controllers and DTOs, so the code is the source of truth. Do not edit the file by hand.
The web app gets TypeScript types from it: apps/web/lib/api/generated/openapi.d.ts, produced with openapi-typescript. The API clients in apps/web/lib/api/ use these types, so a DTO change that the frontend does not follow becomes a type error.
Regenerate after an API change
Whenever you add or change a route, a DTO or a Swagger description, run:
pnpm contracts:regen
It runs two steps:
pnpm -F api run spec:dumpboots the Nest app without a database or an HTTP listener and writesapps/api/openapi.json.pnpm -F web run types:genwritesapps/web/lib/api/generated/openapi.d.ts.
Commit both files with your change.
Drift check
pnpm contracts:check regenerates both files and fails if either differs from the committed copy. It runs in the pre-push hook and in CI. See Quality gates.
Swagger UI
When the API runs outside production, it serves interactive docs of the same spec at /api-docs, for example http://localhost:3001/api-docs in development. Use the Authorize button with a JWT to call admin routes. Swagger UI is turned off in production.
Related
- API overview for the public API conventions.
- Status field conventions for using the status constants.