""" openapi_first.app ========================= OpenAPI-first application bootstrap for FastAPI. This module provides `OpenAPIFirstApp`, a thin but strict abstraction that enforces OpenAPI as the single source of truth for a FastAPI service. Core principles --------------- - The OpenAPI specification (JSON or YAML) defines the entire API surface. - Every operationId in the OpenAPI spec must have a corresponding Python handler function. - Handlers are plain Python callables (no FastAPI decorators). - FastAPI route registration is derived exclusively from the spec. - FastAPI's autogenerated OpenAPI schema is fully overridden. What this module does --------------------- - Loads and validates an OpenAPI 3.x specification. - Dynamically binds HTTP routes to handler functions using operationId. - Registers routes with FastAPI at application startup. - Ensures runtime behavior matches the OpenAPI contract exactly. What this module does NOT do ---------------------------- - It does not generate OpenAPI specs. - It does not generate client code. - It does not introduce a new framework or lifecycle. - It does not alter FastAPI dependency injection semantics. Intended usage -------------- This module is intended for teams that want: - OpenAPI-first API development - Strong contract enforcement - Minimal FastAPI boilerplate - Predictable, CI-friendly failures for spec/implementation drift """ from fastapi import FastAPI from .loader import load_openapi from .binder import bind_routes class OpenAPIFirstApp(FastAPI): """ FastAPI application enforcing OpenAPI-first design. `OpenAPIFirstApp` subclasses FastAPI and replaces manual route registration with OpenAPI-driven binding. All routes are derived from the provided OpenAPI specification, and each operationId is mapped to a Python function in the supplied routes module. Parameters ---------- openapi_path : str Filesystem path to the OpenAPI 3.x specification file. This specification is treated as the authoritative API contract. routes_module : module Python module containing handler functions whose names correspond exactly to OpenAPI operationId values. **fastapi_kwargs Additional keyword arguments passed directly to `fastapi.FastAPI` (e.g., title, version, middleware, lifespan handlers). Raises ------ OpenAPIFirstError If the OpenAPI specification is invalid, or if any declared operationId does not have a corresponding handler function. Behavior guarantees ------------------- - No route can exist without an OpenAPI declaration. - No OpenAPI operation can exist without a handler. - Swagger UI and `/openapi.json` always reflect the provided spec. - Handler functions remain framework-agnostic and testable. Example ------- >>> from openapi_first import OpenAPIFirstApp >>> import app.routes as routes >>> >>> app = OpenAPIFirstApp( ... openapi_path="app/openapi.json", ... routes_module=routes, ... title="Example Service" ... ) """ def __init__( self, *, openapi_path: str, routes_module, **fastapi_kwargs, ): # Initialize FastAPI normally super().__init__(**fastapi_kwargs) # Load and validate OpenAPI specification self._openapi_spec = load_openapi(openapi_path) # Bind routes strictly from OpenAPI spec bind_routes( app=self, spec=self._openapi_spec, routes_module=routes_module, ) # Override FastAPI's OpenAPI generation self.openapi = lambda: self._openapi_spec