## Summary
Resolve `{ENV_VAR}` placeholders in the OpenAPI spec before serving it. Replace the monolithic `x-introspect-url` extension with composable `x-server-url` + individual `x-*-path` fields so auth endpoints are configurable per-environment without hardcoding.
## Changes
- **`openapi_first/app.py`** — add `_resolve_spec_env_vars()` that replaces `{ENV_VAR}` patterns (e.g. `{AUTH_SERVER}`) with the corresponding OS environment variable before returning the spec JSON. Called in `__init__` after spec load.
- **`openapi_first/security.py`** — build the introspection URL dynamically from `x-server-url` + `x-introspect-path` extensions on the `bearerAuth` security scheme, instead of reading a single `x-introspect-url`.
## Migration
Existing specs using `x-introspect-url: "https://auth.example.com/introspect"` must switch to the new extension format:
```yaml
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
x-server-url: "{AUTH_SERVER}"
x-login-path: "/login"
x-register-path: "/register"
x-logout-path: "/logout"
x-me-path: "/me"
x-introspect-path: "/introspect"
Reviewed-on: #3
Co-authored-by: Vishesh 'ironeagle' Bangotra <aetoskia@gmail.com>
Co-committed-by: Vishesh 'ironeagle' Bangotra <aetoskia@gmail.com>
117 lines
2.4 KiB
Python
117 lines
2.4 KiB
Python
"""
|
|
# Summary
|
|
|
|
FastAPI OpenAPI First — strict OpenAPI-first application bootstrap for FastAPI.
|
|
|
|
FastAPI OpenAPI First is a **contract-first infrastructure library** that
|
|
enforces OpenAPI as the single source of truth for FastAPI services.
|
|
|
|
The library removes decorator-driven routing and replaces it with
|
|
deterministic, spec-driven application assembly. Every HTTP route,
|
|
method, and operation is defined in OpenAPI first and bound to Python
|
|
handlers explicitly via `operationId`.
|
|
|
|
---
|
|
|
|
# Installation
|
|
|
|
Install using pip:
|
|
|
|
```bash
|
|
pip install openapi-first
|
|
```
|
|
|
|
Or with Poetry:
|
|
|
|
```bash
|
|
poetry add openapi-first
|
|
```
|
|
|
|
---
|
|
|
|
# Quick Start
|
|
|
|
Minimal OpenAPI-first FastAPI application:
|
|
|
|
```python
|
|
from openapi_first import app
|
|
import my_service.routes as routes
|
|
|
|
api = app.OpenAPIFirstApp(
|
|
openapi_path="openapi.yaml",
|
|
routes_module=routes,
|
|
title="My Service",
|
|
version="1.0.0",
|
|
)
|
|
```
|
|
|
|
OperationId-driven HTTP client:
|
|
|
|
```python
|
|
from openapi_first.loader import load_openapi
|
|
from openapi_first.client import OpenAPIClient
|
|
|
|
spec = load_openapi("openapi.yaml")
|
|
client = OpenAPIClient(spec)
|
|
|
|
response = client.get_health()
|
|
```
|
|
|
|
---
|
|
|
|
# Architecture
|
|
|
|
The library is structured around four core responsibilities:
|
|
|
|
- `loader`: Load and validate OpenAPI 3.x specifications (JSON/YAML).
|
|
- `binder`: Bind OpenAPI operations to FastAPI routes via `operationId`.
|
|
- `app`: OpenAPI-first FastAPI application bootstrap.
|
|
- `client`: OpenAPI-first HTTP client driven by the same specification.
|
|
- `errors`: Explicit error hierarchy for contract violations.
|
|
|
|
---
|
|
|
|
# Public API
|
|
|
|
The supported public API consists of the following top-level modules:
|
|
|
|
- `openapi_first.app`
|
|
- `openapi_first.binder`
|
|
- `openapi_first.loader`
|
|
- `openapi_first.client`
|
|
- `openapi_first.errors`
|
|
|
|
---
|
|
|
|
# Design Guarantees
|
|
|
|
- OpenAPI is the single source of truth.
|
|
- No undocumented routes can exist.
|
|
- No OpenAPI operation can exist without a handler or client callable.
|
|
- All contract violations fail at application startup or client creation.
|
|
- No hidden FastAPI magic or implicit behavior.
|
|
- Deterministic, testable application assembly.
|
|
|
|
---
|
|
"""
|
|
|
|
from . import app
|
|
from . import binder
|
|
from . import loader
|
|
from . import client
|
|
from . import errors
|
|
from . import codegen
|
|
from . import codegen_routes
|
|
from . import security
|
|
|
|
__all__ = [
|
|
"app",
|
|
"binder",
|
|
"loader",
|
|
"client",
|
|
"errors",
|
|
"codegen",
|
|
"codegen_routes",
|
|
"security",
|
|
]
|