Skip to content

API: OpenAPI spec + Scalar reference site + design refresh (0.5.0) - #18

Merged
jstjoe merged 3 commits into
mainfrom
jstjoe/api-reference-docs
May 13, 2026
Merged

jstjoe merged 3 commits into
mainfrom
jstjoe/api-reference-docs

Conversation

@jstjoe

@jstjoe jstjoe commented May 13, 2026

Copy link
Copy Markdown
Owner

Summary

Two goals, shipped together:

  1. API reference for new consumers — a committed, CI-verified OpenAPI spec at docs/api/openapi.json and a Scalar-powered reference site deployed to GitHub Pages from docs/. In-app /scalar route alongside /docs and /redoc.
  2. API surface cleanup for the same audience — enum'd categories, namespaced detector options, clearer endpoint names, and unversioned URL paths (Stripe-style header versioning planned).

Endpoints (after this PR)

Method Path Purpose
POST /api/find Find sensitive data. Returns spans, no rewriting.
POST /api/replace Find + replace each span under chosen mode.
GET /api/detectors List registered detector backends + canonical category coverage.
GET /api/health Liveness probe.

Old /v1/* paths return 404. Pre-1.0; nobody outside this repo consumes the API yet.

Notable changes

Docs / reference

  • opf-api-export-openapi console script regenerates docs/api/openapi.{json,yaml} from app.openapi() (cheap — no lifespan, no model loads).
  • /scalar route in api/src/opf_api/main.py via scalar-fastapi.
  • docs/index.html + docs/guides/*.md carry overview, detectors, labels, replace-modes, auth-and-env. Token vault guide stays at docs/token-vault-setup.md.
  • README API section trimmed; env-vars table kept inline for operators.

API design (breaking, in successive commits)

  • categories is now a closed CanonicalLabel enum mirroring opf_eval.taxonomy.CANONICAL_LABELS. [] = match nothing; null = no filter; bad value -> 422.
  • Detector-specific options moved into options.<detector> namespace. OpfOptions uses extra=\"forbid\" to catch typos like decod_mode. DetectorOptions itself keeps extra=\"ignore\" for forward-compat across new detectors.
  • schema_version payload field dropped — info.version is the only version surface (now 0.5.0).
  • Routes renamed for plain-language clarity: /v1/detect -> /api/find, /v1/sanitize -> /api/replace. Schemas renamed to match (FindRequest/Response, ReplaceRequest/Response, ReplacedSpan, ReplaceMode). sanitized_text response field is now replaced_text.
  • URL prefix /v1/ -> /api/. Future versioning will use API-Version: 2026-05-13 header once contract stabilizes.

CI

  • .github/workflows/openapi.yml — PR check: regen spec, diff against committed copy, fail on drift.
  • .github/workflows/pages.yml — deploy docs/ to Pages on push to main.
  • Both workflows clone openai/privacy-filter (gitignored workspace member) before uv sync.
  • openapi.yml scoped to contents: read.

Files

Test plan

  • uv run --package opf-api opf-api-export-openapi --out /tmp/fresh regenerates spec; diff against docs/api/openapi.json is empty
  • uvicorn opf_api.main:app boots; /api/health, /api/detectors, /scalar, /docs, /redoc, /openapi.json all 200
  • Old /v1/* paths return 404
  • pytest api/tests/test_routes.py — 21/21 passing, including: [] -> 0 spans, null -> all spans, bad enum -> 422, unknown OPF option -> 422 (extra_forbidden), valid options.opf.decode_mode -> 200
  • CI OpenAPI spec freshness job passes on latest push
  • After merge, one-time repo setup: Settings -> Pages -> Source = GitHub Actions, then verify Pages site renders at https://jstjoe.github.io/local-privacy/
  • After merge, freshness check fires on a follow-up PR that touches api/** without regenerating the spec

Versioning approach

API is pre-1.0. info.version is the only version surface today (bumps minor on breaking changes). When the API stabilizes, intent is to move to header-based date-string versioning in the style of Stripe: API-Version: 2026-05-13. URL paths stay unversioned (/api/...) so that switch is purely additive.

🤖 Generated with Claude Code

Generate a committed, CI-verified OpenAPI spec at docs/api/openapi.{json,yaml}
via an `opf-api-export-openapi` console script, enrich every route and
Pydantic field with descriptions and examples, and ship a Scalar-powered
reference UI both in-app (/scalar) and as a static site under docs/ that
GitHub Actions deploys to Pages.

- api/src/opf_api/scripts/export_openapi.py: console script entry that
  imports the app, calls app.openapi(), and writes JSON + YAML to --out.
  app.openapi() does not invoke lifespan, so this is cheap in CI.
- api/src/opf_api/main.py: extend FastAPI(title=..., description=...,
  contact=..., servers=..., openapi_tags=...) and mount /scalar.
- api/src/opf_api/routes.py: per-route tags, summary, description,
  response_description, and example bodies for 400 / 502 responses.
- api/src/opf_api/schemas.py: every Field gets description= and
  examples=; every request/response model gets json_schema_extra
  examples reused from the previous README examples.
- docs/index.html, docs/guides/*.md, docs/api/openapi.{json,yaml}:
  the published reference + narrative companion pages.
- README.md: trim the hand-written API reference section in favour of
  the hosted docs; keep the env-vars table inline for operators.
- .github/workflows/openapi.yml: PR check that diffs the committed spec
  against a fresh regen and fails on drift, with a remediation hint.
- .github/workflows/pages.yml: regen spec + deploy docs/ to Pages on
  pushes to main. Requires Settings -> Pages -> Source = GitHub Actions.
- detect.openapi.json: drop the unused Skyflow Detect API capture.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread .github/workflows/openapi.yml Fixed
privacy-filter/ is the workspace member that provides the `opf` package,
but it's gitignored — the README tells users to clone it as a sibling.
CI runners don't have it, so `uv sync --package opf-api` fails to resolve
the `opf = { workspace = true }` source.

Add a `git clone --depth 1 https://github.com/openai/privacy-filter
privacy-filter` step to both new workflows before `uv sync`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread .github/workflows/openapi.yml Fixed
Job only checks out the repo and runs uv. No write surface needed —
declare `permissions: contents: read` at workflow level to follow least
privilege.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jstjoe
jstjoe merged commit 095effa into main May 13, 2026
4 checks passed
@jstjoe jstjoe changed the title docs(api): publish OpenAPI spec + Scalar reference on GitHub Pages API: OpenAPI spec + Scalar reference site + design refresh (0.5.0) May 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants