Files
F-r-ldraledigplannerare/backend/app/main.py
T
2026-06-01 16:48:21 +02:00

88 lines
2.9 KiB
Python

"""FastAPI application entrypoint.
Opens a database connection on startup, runs Alembic migrations, registers
routers, locks CORS to the configured frontend origin(s), and attaches a
rate-limiter to the app (applied per-endpoint via decorators).
"""
from contextlib import asynccontextmanager
from collections.abc import AsyncIterator
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.errors import RateLimitExceeded
from slowapi.util import get_remote_address
from app.config import settings
from app.db.connection import connect, run_migrations
from app.routers import vacation_days
from app.routers.analytics import router as analytics_router
from app.routers.auth import router as auth_router
from app.routers.fetch_data import router as fetch_data_router
from app.routers.fetch_data import scraper_router
from app.routers.planned_days import router as planned_days_router
from app.routers.settings import break_router, child_router, settings_child_router, tips_router
from app.routers.workspace import _inv_router as invitations_router
from app.routers.workspace import router as workspace_router
limiter = Limiter(key_func=get_remote_address)
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncIterator[None]:
# Run pending migrations before accepting requests (dev convenience).
# In production, run `alembic upgrade head` as a separate deploy step.
if settings.database_type == "sqlite":
try:
run_migrations(f"sqlite:///{settings.sqlite_path}")
except Exception:
pass # migrations may fail in test envs without alembic installed
app.state.db_connection = await connect(settings.sqlite_path)
try:
yield
finally:
await app.state.db_connection.close()
def create_app() -> FastAPI:
app = FastAPI(title="Föräldraledigplannerare API", lifespan=lifespan)
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
app.add_middleware(
CORSMiddleware,
allow_origins=list(settings.cors_origins),
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
_register_routers(app)
return app
def _register_routers(app: FastAPI) -> None:
app.include_router(auth_router)
app.include_router(workspace_router)
app.include_router(invitations_router)
app.include_router(fetch_data_router)
app.include_router(scraper_router)
app.include_router(analytics_router)
app.include_router(tips_router)
app.include_router(break_router)
app.include_router(child_router)
app.include_router(settings_child_router)
app.include_router(planned_days_router)
app.include_router(vacation_days.router)
app = create_app()
@app.get("/health", tags=["health"])
async def health() -> dict[str, str]:
return {"status": "ok"}