Files
SlabUploader/backend/app/main.py
T
grokbot_ty e5514fe3bf feat(#27): Gate B [07/10]: FastAPI health endpoint + app factory (H-1)
- App factory pattern (FUND-8): create_app() produces fresh app per test
- Logging config (structured, no secrets)
- Config validation: SLAB_AES_KEY required, WOO_BASE_URL HTTPS-only
- GET /api/health returns 200 {status: ok, version, woo_reachable: false}
- SQLite + alembic skeleton: full DATA-MODEL schema, initial migration
- API contract tests via httpx TestClient: 5 cases all green
  - test_returns_200, test_returns_ok_status, test_woo_reachable_false
  - test_response_shape, test_with_test_client_lifespan (FUND-9/10)
2026-09-07 07:53:36 +00:00

50 lines
1.2 KiB
Python

"""App factory and lifespan."""
import logging
from contextlib import asynccontextmanager
from fastapi import FastAPI
from app.api import health
from app.config import Settings
from app.db.engine import close_db_connection, init_db
from app.logging_config import configure_logging
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application lifespan: startup and shutdown hooks.
Handles database initialization, logging configuration,
and cleanup on shutdown.
"""
configure_logging()
logging.info("SlabUploader starting up")
await init_db()
yield
logging.info("SlabUploader shutting down")
await close_db_connection()
def create_app(settings: Settings | None = None) -> FastAPI:
"""Create a fresh FastAPI app instance.
Each call produces an independent app with its own database connection
and cleared dependency overrides. This is the factory used by tests.
Args:
settings: Application settings. Uses env vars if None.
Returns:
Configured FastAPI application.
"""
if settings is None:
settings = Settings()
settings.validate()
app = FastAPI(title="SlabUploader", version="0.1.0", lifespan=lifespan)
app.include_router(health.router)
return app