| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- from contextlib import asynccontextmanager
- from pathlib import Path
- from fastapi import FastAPI, Request
- from fastapi.exceptions import RequestValidationError
- from fastapi.middleware.cors import CORSMiddleware
- from fastapi.responses import JSONResponse
- from fastapi.staticfiles import StaticFiles
- from app.api.auth import router as auth_router
- from app.api.admin import router as admin_router
- from app.api.public import router as public_router
- from app.core.config import get_settings
- from app.core.database import SessionLocal, init_db
- from app.core.response import AppHTTPError, error_response, success_response
- from app.services.seed import seed_if_empty
- settings = get_settings()
- @asynccontextmanager
- async def lifespan(app: FastAPI):
- init_db()
- db = SessionLocal()
- try:
- seed_if_empty(db)
- finally:
- db.close()
- yield
- app = FastAPI(title=settings.APP_NAME, lifespan=lifespan)
- _cors_origins = [o.strip() for o in settings.CORS_ORIGINS.split(",") if o.strip()]
- if not _cors_origins:
- _cors_origins = ["*"]
- app.add_middleware(
- CORSMiddleware,
- allow_origins=_cors_origins,
- allow_credentials=_cors_origins != ["*"],
- allow_methods=["*"],
- allow_headers=["*"],
- )
- app.include_router(auth_router, prefix=settings.API_V1_PREFIX)
- app.include_router(public_router, prefix=settings.API_V1_PREFIX)
- app.include_router(admin_router, prefix=settings.API_V1_PREFIX)
- _upload_dir = Path(settings.LOCAL_STORAGE_DIR)
- _upload_dir.mkdir(parents=True, exist_ok=True)
- app.mount("/uploads", StaticFiles(directory=str(_upload_dir)), name="uploads")
- @app.exception_handler(AppHTTPError)
- async def app_http_error_handler(_request: Request, exc: AppHTTPError):
- return JSONResponse(
- status_code=exc.status_code,
- content=error_response(exc.status_code, exc.message, exc.data),
- )
- @app.exception_handler(RequestValidationError)
- async def request_validation_error_handler(
- _request: Request, exc: RequestValidationError
- ):
- # 全局约定:校验失败统一 HTTP 400 + 信封,避免 FastAPI 默认 422/detail
- msg = "请求参数校验失败"
- errors = exc.errors()
- if errors:
- first = errors[0]
- loc = ".".join(str(x) for x in first.get("loc", ()) if x != "body")
- detail = first.get("msg") or msg
- msg = f"{loc}: {detail}" if loc else str(detail)
- return JSONResponse(
- status_code=400,
- content=error_response(400, msg),
- )
- @app.get(f"{settings.API_V1_PREFIX}/health")
- def health_check():
- return success_response({"status": "ok"})
|