2.0 KiB
2.0 KiB
Spec-First Routing
Summary
The OpenAPI document is the single source of truth for the HTTP contract. Handlers are bound to it by name; there is no decorator router.
The contract
openapi.yaml(or.json) declares paths, schemas, parameters, responses, and security.- A custom
operationIdnames the handler function. - The framework (
openapi_first) validates requests/responses against the spec and dispatches to the handler whose name equalsoperationId.
App bootstrap
# main.py
from openapi_first.app import OpenAPIFirstApp
app = OpenAPIFirstApp(
openapi_path="openapi.yaml",
routes_module=interfaces.openapi, # module whose namespace holds handlers
title="<App> API",
version="0.1.0",
lifespan=lifespan,
)
lifespan calls the composition root:
@asynccontextmanager
async def lifespan(app):
app.state.resources = await init()
yield
await shutdown()
Handler registry
interfaces/openapi.py is a flat re-export of every handler, so the framework
can resolve operationId across the whole app:
from interfaces.item.routes import *
from interfaces.wallet.routes import *
from interfaces.progress.sse import *
Handler shape
Handlers are thin and synchronous with respect to business logic:
async def create_item(request: Request, body: dict):
svc = request.app.state.resources["item_svc"]
return await svc.create(Item.model_validate(body))
Conventions
operationIdnaming:list_<resource>,create_<resource>,get_<resource>,update_<resource>,delete_<resource>.- Read-only endpoints may use a cache decorator keyed on path + query + user.
- Validation errors ->
400; not found ->404; delete ->204. - Security is declared once in the spec and enforced by the framework; handlers contain no auth code.
Codegen
The openapi_first library can scaffold models and route stubs from the spec,
and ships app templates (CRUD app, model app, service). Prefer codegen over
hand-writing boilerplate.