# 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//` - 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: ``` _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)