todoappapi / main.py
GrowWithTalha's picture
feat: sync backend changes from main repo
dc3879e
"""FastAPI application entry point.
[Task]: T047
[From]: specs/001-user-auth/plan.md
"""
import logging
from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from datetime import datetime
import time
from core.database import init_db, engine
from core.config import get_settings
from api.auth import router as auth_router
from api.tasks import router as tasks_router
from api.chat import router as chat_router
from core.logging import setup_logging, get_logger
settings = get_settings()
# Setup structured logging
setup_logging()
logger = get_logger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application lifespan manager.
Handles startup and shutdown events with graceful connection cleanup.
"""
# Startup
logger.info("Starting up application...")
init_db()
logger.info("Database initialized")
# Track background tasks for graceful shutdown
background_tasks = set()
yield
# Shutdown - Graceful shutdown handler
logger.info("Shutting down application...")
# Close database connections
try:
logger.info("Closing database connections...")
await engine.dispose()
logger.info("Database connections closed")
except Exception as e:
logger.error(f"Error closing database: {e}")
# Wait for background tasks to complete (with timeout)
if background_tasks:
logger.info(f"Waiting for {len(background_tasks)} background tasks to complete...")
try:
# Wait up to 10 seconds for tasks to complete
import asyncio
await asyncio.wait_for(asyncio.gather(*background_tasks, return_exceptions=True), timeout=10.0)
logger.info("All background tasks completed")
except asyncio.TimeoutError:
logger.warning("Background tasks did not complete in time, forcing shutdown...")
logger.info("Application shutdown complete")
# Create FastAPI application
app = FastAPI(
title="Todo List API",
description="REST API for managing tasks with JWT authentication",
version="1.0.0",
lifespan=lifespan,
)
# Add CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=[settings.frontend_url],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Include routers
app.include_router(auth_router) # Authentication endpoints
app.include_router(tasks_router) # Task management endpoints
app.include_router(chat_router) # AI chat endpoints (Phase III)
@app.get("/")
async def root():
"""Root endpoint."""
return {
"message": "Todo List API",
"status": "running",
"version": "2.0.0",
"authentication": "JWT",
"features": {
"task_management": "REST API for CRUD operations",
"ai_chatbot": "Natural language task creation and listing"
}
}
@app.get("/health")
async def health_check():
"""Health check endpoint.
Verifies database connectivity and application status.
Returns 503 if database is unavailable.
[Task]: T048
[From]: specs/001-user-auth/plan.md
"""
from sqlmodel import select
from models.user import User
from sqlmodel import Session
# Try to get database session
try:
# Create a simple query to test database connection
with Session(engine) as session:
# Execute a simple query (doesn't matter if it returns data)
session.exec(select(User).limit(1))
return {"status": "healthy", "database": "connected", "timestamp": datetime.utcnow().isoformat()}
except Exception as e:
logger.error(f"Health check failed: {e}")
raise HTTPException(
status_code=503,
detail="Service unavailable - database connection failed"
)
@app.get("/metrics")
async def metrics():
"""Metrics endpoint for monitoring.
Returns basic application metrics for Kubernetes health probes.
"""
return {
"status": "running",
"timestamp": datetime.utcnow().isoformat(),
"uptime_seconds": time.time(),
"version": "1.0.0",
"database": "connected" # Simplified - in production would check actual DB status
}
# Global exception handler
@app.exception_handler(HTTPException)
async def http_exception_handler(request, exc):
"""Global HTTP exception handler.
Returns consistent error format for all HTTP exceptions.
[Task]: T046
[From]: specs/001-user-auth/research.md
"""
return JSONResponse(
status_code=exc.status_code,
content={
"error": {
"status_code": exc.status_code,
"detail": exc.detail
}
}
)