88 lines
4.3 KiB
Markdown
88 lines
4.3 KiB
Markdown
# 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)
|