Files
2026-09-08 11:00:05 +05:30

71 lines
2.4 KiB
Python

"""
B0.3.3 — export the API contract.
Writes openapi.json at the repository root. It is committed, and CI fails when
the exported document differs from the committed one, so a change to a request
or response shape has to be admitted in a diff rather than discovered by the
frontend at runtime.
APP_ENV=rework_test python scripts/export_openapi.py # write
APP_ENV=rework_test python scripts/export_openapi.py --check # verify
The contract is exported now, at 31% `response_model` coverage, rather than
after B0.3.1/B0.3.2 fill the remaining 166. An incomplete contract that cannot
silently change is worth considerably more than a complete one that arrives in
three weeks, and every endpoint that gains a `response_model` shows up as a diff
here — which makes progress visible instead of merely claimed.
"""
import json
import os
import sys
from pathlib import Path
os.environ.setdefault("APP_ENV", "rework_test")
os.environ.setdefault("PYTHONIOENCODING", "utf-8")
sys.path.insert(0, str(Path(__file__).parent.parent))
OUTPUT = Path(__file__).parent.parent / "openapi.json"
def build() -> str:
from app.main import app
schema = app.openapi()
# sort_keys so the file is diffable: FastAPI does not guarantee key order,
# and an unordered dump would churn on every export.
return json.dumps(schema, indent=2, sort_keys=True, ensure_ascii=False) + "\n"
def main() -> int:
generated = build()
check = "--check" in sys.argv
if check:
if not OUTPUT.exists():
print("openapi.json is missing. Run scripts/export_openapi.py", file=sys.stderr)
return 1
committed = OUTPUT.read_text(encoding="utf-8")
if committed != generated:
print(
"openapi.json is stale — the API has changed since it was exported.\n"
"Regenerate and commit the diff:\n"
" APP_ENV=rework_test python scripts/export_openapi.py",
file=sys.stderr,
)
return 1
print("openapi.json is current")
return 0
OUTPUT.write_text(generated, encoding="utf-8")
schema = json.loads(generated)
print(f"wrote {OUTPUT.name}")
print(f" paths {len(schema.get('paths', {}))}")
print(f" schemas {len(schema.get('components', {}).get('schemas', {}))}")
return 0
if __name__ == "__main__":
raise SystemExit(main())