docs: add OpenAPI-first wiki (overview, components, use cases for templates/client/codegen, design, security, error handling, testing) and refresh lib docs index

This commit is contained in:
2026-09-15 22:29:05 +05:30
parent adeb02e162
commit b559323dfe
26 changed files with 1590 additions and 86 deletions

View File

@@ -0,0 +1,167 @@
# Use Case 2: Templates — Copyable Reference Applications
`openapi-first` ships four runnable, copyable applications under `openapi_first/templates/`. They are **not part of the library API** — they are bundled scaffold examples you copy into your own project and build on.
---
## 🎬 1. What Templates Are
A template is a complete, self-contained OpenAPI-first service:
- A bundled directory inside `openapi_first/templates/<name>/`
- Copyable **verbatim** — no code generation, no mutation — via the CLI
- Each one demonstrates a specific set of OpenAPI-first behaviors and FastAPI features
All templates share the same skeleton:
```
<name>_app/
├── __init__.py # explains the template + how to scaffold it
├── openapi.yaml # the contract (source of truth)
├── main.py # assembles OpenAPIFirstApp from the spec
├── routes.py # operationId-bound handler functions
└── data.py # in-memory data store (demo only)
```
---
## 📋 2. The Four Templates
### 2.1 `health_app` — minimal liveness probe
```bash
openapi-first scaffold health_app
# or into a custom directory:
openapi-first scaffold health_app my-health-service
```
| File | Purpose |
|------|---------|
| `openapi.yaml` | `GET /health``operationId: get_health` |
| `routes.py` | `get_health()` returns `{"status": "ok"}` |
| `main.py` | `OpenAPIFirstApp(openapi_path="openapi.yaml", routes_module=routes)` |
**Why it exists:** the absolute minimal OpenAPI-first round trip — one operation, one handler, zero moving parts. The best starting point to internalize the mental model.
**Smoke test:**
```bash
pip install -e .
uvicorn main:app
curl http://localhost:8000/health
# → {"status": "ok"}
```
### 2.2 `crud_app` — dict-based CRUD
```bash
openapi-first scaffold crud_app my-crud-service
```
| File | Purpose |
|------|---------|
| `openapi.yaml` | Full CRUD over `/items` (list/get/create/update/delete) |
| `routes.py` | Handlers bound via `operationId`s `list_items`, `get_item`, `create_item`, `update_item`, `delete_item` |
| `data.py` | In-memory dict store with auto-incrementing `id` |
Behaviors you learn:
- **Explicit status codes** — `create_item`/`delete_item` take `response: Response` and set `201`/`204`; `get_item`/`update_item` raise `HTTPException(404)` on `KeyError`
- **Handlers as plain callables** — no FastAPI decorators, routing comes solely from the spec
- **Mock data store** — `data.py` is a copyable in-memory store, explicitly **not** production-ready
### 2.3 `model_app` — Pydantic model CRUD
```bash
openapi-first scaffold model_app my-model-service
```
| File | Purpose |
|------|---------|
| `openapi.yaml` | Same CRUD surface, schemas reference models |
| `models.py` | Pydantic `Item`, `ItemCreate`, `ItemBase` (request/response models) |
| `routes.py` | Handlers type-annotated with the models; `create_item` sets `201` |
| `data.py` | In-memory store returning real model instances |
Behaviors you learn:
- **Pydantic request/response models** — payloads validated and serialized via FastAPI
- **Same handler contracts** — identical `operationId` set as `crud_app`, so the two are interchangeable
- **Models in the client too** — the same spec drives `OpenAPIClient` body handling
### 2.4 `vet_app` — the full-featured demo
```bash
openapi-first scaffold vet_app my-vet-clinic
```
| File | Purpose |
|------|---------|
| `openapi.yaml` | Five resources (parents, vets, treatments, pets, appointments) + SSE + upload + discriminated unions |
| `models.py` | Pydantic models incl. **discriminated unions** (`noteType` literal fields) |
| `routes.py` | ~20 handlers across all resources, incl. pagination, filtering, photo upload, SSE streaming |
| `sse.py` | Server-Sent Events helper (`StreamingResponse`, per-pet subscriber queues, background `asyncio` workers) |
| `data.py` | Larger in-memory store (parents → vets → treatments → pets → appointments) |
| `main.py` | App + CORS + lifespan example |
Behaviors you learn — the *advanced* tier:
- **Discriminated unions** — `ProcedureNotes` uses `oneOf` + `discriminator.noteType` mapping; Pydantic models use `Literal[...]` discriminator fields
- **SSE streaming** — a `GET /pets/{id}/actions` operation streaming `text/event-stream` via `StreamingResponse` with background task workers
- **File upload** — `UploadFile` handler setting a multi-part body
- **CORS + middleware** — `add_middleware(CORSMiddleware, ...)` alongside the spec-driven setup
- **Response injection** — handlers set `201`/`204` explicitly via injected `Response`
---
## 🚀 3. CLI Reference
```bash
# List available templates
openapi-first scaffold --list
# Copy a template into its default directory (template name, dashes)
openapi-first scaffold health_app
# Copy into a custom target directory
openapi-first scaffold crud_app my-project/crud
```
> **Protip:** `DEFAULT_TEMPLATE` is `health_app`, so `openapi-first scaffold` with no template name scaffolds the health app.
---
## 🧩 4. Anatomy of a Scaffolded Service
After `openapi-first scaffold health_app my-health-service`, your directory contains a drop-in FastAPI service:
```
my-health-service/
├── openapi.yaml # THE contract
├── main.py # `app = OpenAPIFirstApp(openapi_path=..., routes_module=routes)`
└── routes.py # `def get_health(): ...`
```
Run it:
```bash
cd my-health-service
pip install -e .
uvicorn main:app --reload
```
`/docs`, `/openapi.json`, and every declared route now exist — all derived from `openapi.yaml`.
---
## ⚠️ 5. Production Disclaimer
Templates use **in-memory, non-persistent, non-concurrency-safe** data stores. They are learning scaffolds — **not** production references. Swap in a real data layer (SQL/REDIS/object store) the moment you go beyond a demo.
See the `__init__.py` of each template for detailed client examples, CLI examples, and design notes.
---
## Related
- [01 Quickstart](01_quickstart.md) · [04 Codegen](04_codegen.md) · [02 Components](../02_components.md)