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:
87
docs/wiki/04_design.md
Normal file
87
docs/wiki/04_design.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# Design — Guarantees, Startup Pipeline, and the Contract Model
|
||||
|
||||
This page is the architecture reference: the fail-fast startup surface, the guarantees that hold by construction, and the trade-offs baked into every decision.
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ 1. The Startup Pipeline
|
||||
|
||||
Everything happens **once, eagerly, at construction time** — for the app at `OpenAPIFirstApp(...)`, for the client at `OpenAPIClient(...)`. There is no lazy loading, no deferred binding, no "it'll work on first request".
|
||||
|
||||
```text
|
||||
openapi.yaml ──► loader.load_openapi
|
||||
├─ parse (json/yaml by extension)
|
||||
├─ validate (strict OpenAPI 3.x validator)
|
||||
└─► dict ──▶ OpenAPISpecLoadError
|
||||
│
|
||||
OpenAPIFirstApp(openapi_path=..., routes_module=routes)
|
||||
├─ 1. load + validate spec (loader)
|
||||
├─ 2. parse securitySchemes (security)
|
||||
├─ 3. make_security_dependencies (security)
|
||||
├─ 4. bind_routes: every operationId ──► routes.<operationId>
|
||||
│ └─ missing op / missing handler ──► MissingOperationHandler
|
||||
└─► FastAPI app: routes registry + /openapi.json + Swagger UI
|
||||
```
|
||||
|
||||
Client — same spec, same guarantees:
|
||||
|
||||
```text
|
||||
OpenAPIClient(spec)
|
||||
├─ require servers[]
|
||||
├─ require paths
|
||||
├─ one callable per operationId (client.<operationId>)
|
||||
│ └─ missing / duplicate opId ──► OpenAPIClientError
|
||||
└─► ready
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📜 2. Guarantees That Hold by Construction
|
||||
|
||||
These are not conventions — they are enforced at startup or client construction:
|
||||
|
||||
1. **Every route is spec-declared.** Routes are registered *only* from `paths`; there is no decorator-driven or implicit routing.
|
||||
2. **Every operation is handled.** Each `operationId` resolves to an exact handler name in `routes_module`; a missing one aborts bootstrap.
|
||||
3. **Every operation has an `operationId`.** An operation without one cannot be bound and fails fast.
|
||||
4. **Client and server use the same spec.** One document drives both sides, so they cannot drift.
|
||||
5. **Auth is spec-driven.** `security` dependencies come from `securitySchemes` + per-operation `security`; no manual middleware.
|
||||
6. **Spec is valid before use.** Invalid, malformed, or unloadable specs are rejected at load, not at first request.
|
||||
|
||||
### The startup "no half-states" property
|
||||
|
||||
Because binding, validation, and security resolution all run at construction, a booted app is a **provably-complete app**. If the contract is violated in any way, the process refuses to start — the failure is loud, immediate, and tells you exactly what to fix.
|
||||
|
||||
---
|
||||
|
||||
## 🧩 3. Component Responsibilities
|
||||
|
||||
| Module | Owns | Refuses to |
|
||||
|--------|------|------------|
|
||||
| `loader` | parse + validate the spec | modify or "fix" the spec |
|
||||
| `app` | assemble FastAPI from spec + handlers | routing decisions, decorators |
|
||||
| `binder` | `operationId` → handler mapping | infer handlers from paths |
|
||||
| `client` | build one callable per `operationId` | guess URLs, deserialize implicitly |
|
||||
| `security` | schemes → FastAPI `Depends` | manual middleware |
|
||||
| `errors` | the error hierarchy | swallow failures |
|
||||
| `codegen` | build-time model/routes generation | runtime codegen |
|
||||
| `templates` | copyable scaffolds | production data stores |
|
||||
|
||||
**Rule of thumb for contributors:** keep modules coercive (they raise if the contract is wrong) and narrow (one responsibility each). Pydoclint + the test suite keep that contract honest.
|
||||
|
||||
---
|
||||
|
||||
## ⚖️ 4. Design Trade-offs (Accepted)
|
||||
|
||||
| Decision | Chosen because | What you give up |
|
||||
|----------|----------------|------------------|
|
||||
| Handlers are plain callables | Framework-agnostic, testable, grep-able | No decorator sugar |
|
||||
| Fail-fast at startup | Drift caught in CI, not at 3am | Slightly heavier boot |
|
||||
| Raw `httpx.Response` from client | No hidden deserialization/validation | You read `.json()` yourself |
|
||||
| Build-time codegen | One-way generation, no runtime generator dep | Spec must already be spec-valid |
|
||||
| Templates copy verbatim | Scaffold, not magic | Templates never updated in place |
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Related
|
||||
|
||||
- [01 – Overview](01_overview.md) · [02 – Components](02_components.md) · [05 – Security](05_security.md) · [06 – Error Handling](06_error_handling.md) · [07 – Testing](07_testing.md)
|
||||
Reference in New Issue
Block a user