api: make the OpenAPI spec usable as documentation
ci / lint (push) Failing after 56s
ci / types (push) Has been skipped
ci / unit (push) Has been skipped
ci / integration (push) Has been skipped
ci / security (push) Has been skipped
ci / dockerfile (push) Has been skipped
ci / chart (push) Has been skipped
ci / image (api) (push) Has been skipped
ci / image (reconciler) (push) Has been skipped
ci / image (worker) (push) Has been skipped
ci / bump (push) Has been skipped
ci / lint (push) Failing after 56s
ci / types (push) Has been skipped
ci / unit (push) Has been skipped
ci / integration (push) Has been skipped
ci / security (push) Has been skipped
ci / dockerfile (push) Has been skipped
ci / chart (push) Has been skipped
ci / image (api) (push) Has been skipped
ci / image (reconciler) (push) Has been skipped
ci / image (worker) (push) Has been skipped
ci / bump (push) Has been skipped
FastAPI already served /docs, /redoc and /openapi.json, and the ingress already
passed them through — the mechanism was there, the content was not. The schema
alone cannot tell a caller the three things they most need to know, and the
route docstrings explain implementation reasoning to a maintainer rather than
usage to a consumer.
Added to the spec itself, so it travels with the API rather than living in a
README the caller does not have:
- An app description covering bearer auth, that every write is 202 + poll,
the instance lifecycle, and the uniform {"code", "message"} error body.
- Tag descriptions for `instances` and `ops`.
- Field descriptions and worked examples on CreateInstanceRequest,
InstanceResponse and ErrorBody, so /docs shows a valid payload instead of
leaving callers to infer one.
The bearer scheme was already exposed via HTTPBearer, which is what makes the
Authorize button in /docs work; there is now a test asserting it stays, along
with the description, the tags and the request example. Docs that are not
tested rot silently, and this is the artifact other teams integrate against.
README documents the three URLs and how to generate a client from the spec.
This commit is contained in:
@@ -78,6 +78,39 @@ uv run pytest -q -m slow
|
||||
uv run python -m scripts.redis_budget # projects month-end burn, exits 1 if over
|
||||
```
|
||||
|
||||
## Using the API
|
||||
|
||||
The API documents itself. FastAPI generates OpenAPI from the same models and routes it
|
||||
serves, so the spec cannot drift from the implementation the way a hand-written one does.
|
||||
|
||||
| What | Where |
|
||||
|---|---|
|
||||
| Swagger UI (try requests in the browser) | `https://svcforge.oci-oci.duckdns.org/docs` |
|
||||
| ReDoc (nicer to read) | `https://svcforge.oci-oci.duckdns.org/redoc` |
|
||||
| Raw spec, for generating clients | `https://svcforge.oci-oci.duckdns.org/openapi.json` |
|
||||
|
||||
Locally, `uv run uvicorn services.api.main:app --factory` then <http://127.0.0.1:8000/docs>.
|
||||
|
||||
Three things a caller needs that a schema cannot state on its own, so they are written into
|
||||
the spec's description and rendered at the top of `/docs`:
|
||||
|
||||
- **Every write is asynchronous.** `POST` and `DELETE` return `202 Accepted` and enqueue
|
||||
work. Poll `GET /v1/instances/{id}` and watch `state`; only `ready` carries an endpoint.
|
||||
- **Authorisation is a WHERE clause.** Another team's instance returns `404`, not `403`, so
|
||||
the API never confirms that an id you cannot access exists.
|
||||
- **Every non-2xx body is `{"code", "message"}`**, including the 404s and 405s raised by
|
||||
the framework itself, so clients never branch on the body's shape.
|
||||
|
||||
Generate a client from the spec rather than hand-rolling one:
|
||||
|
||||
```bash
|
||||
curl -s https://svcforge.oci-oci.duckdns.org/openapi.json > openapi.json
|
||||
# e.g. openapi-generator-cli generate -i openapi.json -g python -o ./client
|
||||
```
|
||||
|
||||
`tests/integration/test_api.py` pins the description, the tags and the bearer security
|
||||
scheme, so the docs fail CI if they rot.
|
||||
|
||||
## Where things live
|
||||
|
||||
| Module | Teaches | Read here |
|
||||
|
||||
Reference in New Issue
Block a user