""" OpenAPI-driven route binding for FastAPI. --- ## Summary This module is responsible for translating an OpenAPI 3.x specification into concrete FastAPI routes. It enforces a strict one-to-one mapping between OpenAPI operations and Python handler functions using operationId. Notes: **Core Responsibility:** - Read path + method definitions from an OpenAPI specification - Resolve each operationId to a Python callable - Register routes with FastAPI using APIRoute - Fail fast when contract violations are detected **Design Constraints:** - All routes MUST be declared in the OpenAPI specification - All OpenAPI operations MUST define an operationId - Every operationId MUST resolve to a handler function - Handlers are plain Python callables (no decorators required) - No implicit route creation or inference is allowed **Constraints:** - This module intentionally does NOT: Perform request or response validation, generate Pydantic models, modify FastAPI dependency injection, or interpret OpenAPI semantics beyond routing metadata. """ from fastapi.routing import APIRoute from .errors import MissingOperationHandler def bind_routes(app, spec: dict, routes_module) -> None: """ Bind OpenAPI operations to FastAPI routes. Args: app (fastapi.FastAPI): The FastAPI application instance to which routes will be added. spec (dict): Parsed OpenAPI 3.x specification dictionary. routes_module (module): Python module containing handler functions. Each handler's name MUST exactly match an OpenAPI operationId. Raises: MissingOperationHandler: If an operationId is missing from the spec or if no corresponding handler function exists in the routes module. Notes: **Responsibilities:** - Iterates through the OpenAPI specification paths and methods - Resolves each operationId to a handler function, and registers a corresponding APIRoute on the FastAPI application **Guarantees:** - Route registration is deterministic and spec-driven. No route decorators are required or supported. Handler resolution errors surface at application startup. """ paths = spec.get("paths", {}) for path, methods in paths.items(): for http_method, operation in methods.items(): operation_id = operation.get("operationId") if not operation_id: raise MissingOperationHandler( path=path, method=http_method, ) try: endpoint = getattr(routes_module, operation_id) except AttributeError: raise MissingOperationHandler( path=path, method=http_method, operation_id=operation_id, ) route = APIRoute( path=path, endpoint=endpoint, methods=[http_method.upper()], name=operation_id, ) app.router.routes.append(route)