Files
home_stock/backend/app/main.py
2026-02-01 01:45:51 +01:00

130 lines
3.8 KiB
Python

"""Point d'entrée de l'application HomeStock.
Application FastAPI pour la gestion d'inventaire domestique.
"""
from contextlib import asynccontextmanager
from typing import Any
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from loguru import logger
from app.core.config import settings
from app.core.database import close_db, init_db
from app.core.logging import setup_logging
# Configuration du logging
setup_logging()
@asynccontextmanager
async def lifespan(app: FastAPI) -> Any:
"""Gère le cycle de vie de l'application.
- Startup : Initialise la base de données
- Shutdown : Ferme les connexions proprement
"""
logger.info("Démarrage de l'application HomeStock")
logger.info(f"Environnement: {settings.ENVIRONMENT}")
logger.info(f"Version: {settings.APP_VERSION}")
# Initialisation de la base de données
# Note: En production, utiliser Alembic pour les migrations
if settings.is_development:
logger.debug("Initialisation de la base de données (mode développement)")
await init_db()
yield
# Nettoyage
logger.info("Arrêt de l'application HomeStock")
await close_db()
# Création de l'application FastAPI
app = FastAPI(
title=settings.APP_NAME,
description="API pour la gestion d'inventaire domestique",
version=settings.APP_VERSION,
docs_url="/api/docs" if settings.is_development else None, # Swagger UI
redoc_url="/api/redoc" if settings.is_development else None, # ReDoc
openapi_url="/api/openapi.json" if settings.is_development else None,
lifespan=lifespan,
)
# === Configuration CORS ===
app.add_middleware(
CORSMiddleware,
allow_origins=settings.cors_origins_list,
allow_credentials=settings.CORS_ALLOW_CREDENTIALS,
allow_methods=["*"], # Autorise toutes les méthodes (GET, POST, PUT, DELETE, etc.)
allow_headers=["*"], # Autorise tous les headers
)
# === Routes de santé ===
@app.get("/", tags=["Health"])
async def root() -> dict[str, str]:
"""Route racine - Vérification de l'état de l'API."""
return {
"app": settings.APP_NAME,
"version": settings.APP_VERSION,
"status": "running",
}
@app.get("/health", tags=["Health"])
async def health() -> dict[str, str]:
"""Endpoint de santé pour monitoring."""
return {
"status": "healthy",
"environment": settings.ENVIRONMENT,
}
# === Gestion globale des erreurs ===
@app.exception_handler(Exception)
async def global_exception_handler(request: Any, exc: Exception) -> JSONResponse:
"""Gestionnaire global des exceptions non capturées.
Log l'erreur et retourne une réponse JSON standardisée.
"""
logger.error(f"Erreur non gérée: {exc}", exc_info=True)
# En production, masquer les détails de l'erreur
detail = str(exc) if settings.is_development else "Erreur interne du serveur"
return JSONResponse(
status_code=500,
content={
"detail": detail,
"type": "internal_server_error",
},
)
# === Enregistrement des routers ===
from app.routers import categories_router, documents_router, import_router, items_router, locations_router, shops_router
app.include_router(categories_router, prefix="/api/v1")
app.include_router(locations_router, prefix="/api/v1")
app.include_router(items_router, prefix="/api/v1")
app.include_router(documents_router, prefix="/api/v1")
app.include_router(shops_router, prefix="/api/v1")
app.include_router(import_router, prefix="/api/v1")
if __name__ == "__main__":
import uvicorn
uvicorn.run(
"app.main:app",
host=settings.BACKEND_HOST,
port=settings.BACKEND_PORT,
reload=settings.BACKEND_RELOAD,
log_level=settings.LOG_LEVEL.lower(),
)