Files
Vishesh 'ironeagle' Bangotra 2f444a93ad
All checks were successful
continuous-integration/drone/tag Build is passing
doc changes from fastapi openapi first to openapi first. added cli docs
2026-01-10 17:43:52 +05:30

119 lines
3.6 KiB
Python

"""
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