mitlist/be/app/main.py

143 lines
3.9 KiB
Python

import logging
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from starlette.middleware.sessions import SessionMiddleware
import sentry_sdk
from sentry_sdk.integrations.fastapi import FastApiIntegration
import os
import sys
from app.api.api_router import api_router
from app.config import settings
from app.core.api_config import API_METADATA, API_TAGS
from app.auth import fastapi_users, auth_backend
from app.schemas.user import UserPublic, UserCreate, UserUpdate
from app.core.scheduler import init_scheduler, shutdown_scheduler
if settings.SENTRY_DSN:
sentry_sdk.init(
dsn=settings.SENTRY_DSN,
integrations=[
FastApiIntegration(),
],
traces_sample_rate=0.1 if settings.is_production else 1.0,
environment=settings.ENVIRONMENT,
send_default_pii=not settings.is_production
)
logging.basicConfig(
level=getattr(logging, settings.LOG_LEVEL),
format=settings.LOG_FORMAT
)
logger = logging.getLogger(__name__)
api_metadata = {
**API_METADATA,
"docs_url": settings.docs_url,
"redoc_url": settings.redoc_url,
"openapi_url": settings.openapi_url,
}
app = FastAPI(
**api_metadata,
openapi_tags=API_TAGS
)
app.add_middleware(
SessionMiddleware,
secret_key=settings.SESSION_SECRET_KEY
)
app.add_middleware(
CORSMiddleware,
allow_origins=settings.cors_origins_list,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
expose_headers=["*"]
)
app.include_router(
fastapi_users.get_auth_router(auth_backend),
prefix="/auth/jwt",
tags=["auth"],
)
app.include_router(
fastapi_users.get_register_router(UserPublic, UserCreate),
prefix="/auth",
tags=["auth"],
)
app.include_router(
fastapi_users.get_reset_password_router(),
prefix="/auth",
tags=["auth"],
)
app.include_router(
fastapi_users.get_verify_router(UserPublic),
prefix="/auth",
tags=["auth"],
)
app.include_router(
fastapi_users.get_users_router(UserPublic, UserUpdate),
prefix="/users",
tags=["users"],
)
app.include_router(api_router, prefix=settings.API_PREFIX)
@app.get("/health", tags=["Health"])
async def health_check():
"""
Health check endpoint for load balancers and monitoring.
"""
return {
"status": settings.HEALTH_STATUS_OK,
"environment": settings.ENVIRONMENT,
"version": settings.API_VERSION
}
@app.get("/", tags=["Root"])
async def read_root():
"""
Provides a simple welcome message at the root path.
Useful for basic reachability checks.
"""
logger.info("Root endpoint '/' accessed.")
return {
"message": settings.ROOT_MESSAGE,
"environment": settings.ENVIRONMENT,
"version": settings.API_VERSION
}
async def run_migrations():
"""Run database migrations."""
try:
logger.info("Running database migrations...")
base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
alembic_path = os.path.join(base_path, 'alembic')
if alembic_path not in sys.path:
sys.path.insert(0, alembic_path)
from migrations import run_migrations as run_db_migrations
await run_db_migrations()
logger.info("Database migrations completed successfully.")
except Exception as e:
logger.error(f"Error running migrations: {e}")
raise
@app.on_event("startup")
async def startup_event():
"""Initialize services on startup."""
logger.info(f"Application startup in {settings.ENVIRONMENT} environment...")
# await run_migrations()
init_scheduler()
logger.info("Application startup complete.")
@app.on_event("shutdown")
async def shutdown_event():
"""Cleanup services on shutdown."""
logger.info("Application shutdown: Disconnecting from database...")
shutdown_scheduler()
logger.info("Application shutdown complete.")