005. OpenAPI spec governance: committed file plus CODEOWNERS
- Date: 2026-05-28
- Status: Accepted
Decision
Section titled “Decision”In the context ofa FastAPI backend with one or more consumers (currently the React frontend) that depend on a stable, documented API surface,facingthe need to keep the OpenAPI contract visible, reviewable, and enforced without allowing it to drift from the implementation or to change without affected consumers knowing,we decided forcommitting a generatedbackend/openapi.yamlto the app repo, regenerating it in CI and failing the build if it drifts from what FastAPI produces, with aCODEOWNERSrule requiring sign-off from both the API author and one designated representative per consumer on any PR that changes the spec,- FastAPI annotations are the source of truth; the committed file is the diffable artifact that makes API surface changes visible in PRs
- A CI job exports the spec (
python -m scripts.export_openapi), diffs it against the committed file, and fails if they diverge — making “update the spec” a required step, not a courtesy CODEOWNERSmapsbackend/openapi.yaml(and the FastAPI route/schema files) to the frontend owner; as new consumers are added, their designated rep is added to the same rule- For rag-sample, the frontend owner is the sole consumer rep at this time; the same person may be the API author — that is a self-review, but the process is in place for when roles diverge
and neglected- Runtime-only spec (no committed file) — diffs are invisible in PRs and consumers have no stable artifact to work against without running the server
- Manual spec maintenance (hand-authored YAML) — diverges from the implementation silently; eliminated by the CI diff check
- Review by any team member — diffuses accountability; named consumer reps make “who should have caught this” unambiguous
to achieve- a single enforced source of truth for the API contract that is visible in version history and PR diffs
- a guarantee that no API surface change ships without explicit acknowledgement from every consumer
accepting- the CI job adds a step to every backend PR
- the committed
openapi.yamlmust be regenerated and re-committed whenever FastAPI annotations change, which is a manual step developers must remember (the CI diff check catches omissions but does not auto-commit) - consumer reps must be kept current in
CODEOWNERSas the team changes
Consequences
Section titled “Consequences”A scripts/export_openapi.py helper must be written and documented so developers know how to regenerate the spec locally. The CI workflow gains an openapi-check job. The initial backend/openapi.yaml is generated when the FastAPI skeleton lands (issue #12). As new consumers are onboarded, their owner is added to the CODEOWNERS entry for the spec and route files — this is the ongoing maintenance burden of this decision.
The FastAPI export idiom:
import jsonfrom rag_sample.api.app import appprint(json.dumps(app.openapi(), indent=2))Piped to backend/openapi.yaml (or .json) as part of the CI check and as the local regen command.
© 2026 Benjamin Arunski