generated from gilles/template-webapp
130 lines
3.8 KiB
Python
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(),
|
|
)
|