from __future__ import annotations from fastapi import FastAPI, HTTPException, Request from fastapi.exceptions import RequestValidationError from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse from starlette.exceptions import HTTPException as StarletteHTTPException from core.config.settings import config from core.http.models import HealthResponse from core.http.response import build_problem_details from core.logging import configure_logging, get_logger from v1.router import router as mobile_router configure_logging(config) app = FastAPI() app.add_middleware( CORSMiddleware, allow_origins=config.cors.allow_origins, allow_credentials=config.cors.allow_credentials, allow_methods=config.cors.allow_methods, allow_headers=config.cors.allow_headers, ) app.include_router(mobile_router) logger = get_logger("api.app") @app.get("/health", response_model=HealthResponse) async def health() -> HealthResponse: return HealthResponse(status="ok") def _build_http_error_response( request: Request, exc: Exception, status_code: int, detail: object, ) -> JSONResponse: instance = request.url.path detail_text = detail if isinstance(detail, str) else "Request failed" logger.warning( "HTTP error", status_code=status_code, detail=detail_text, detail_extra=detail, path=request.url.path, method=request.method, ) problem = build_problem_details( status_code=status_code, detail=detail_text, instance=instance, ) return JSONResponse( status_code=status_code, content=problem.model_dump(), media_type="application/problem+json", ) @app.exception_handler(HTTPException) async def http_exception_handler( request: Request, exc: HTTPException, ) -> JSONResponse: return _build_http_error_response( request=request, exc=exc, status_code=exc.status_code, detail=exc.detail, ) @app.exception_handler(StarletteHTTPException) async def starlette_http_exception_handler( request: Request, exc: StarletteHTTPException, ) -> JSONResponse: return _build_http_error_response( request=request, exc=exc, status_code=exc.status_code, detail=exc.detail, ) @app.exception_handler(RequestValidationError) async def validation_exception_handler( request: Request, exc: RequestValidationError, ) -> JSONResponse: instance = request.url.path logger.warning( "Request validation error", path=request.url.path, method=request.method, errors=exc.errors(), ) problem = build_problem_details( status_code=422, detail="Invalid request", instance=instance, ) return JSONResponse( status_code=422, content=problem.model_dump(), media_type="application/problem+json", ) @app.exception_handler(Exception) async def unhandled_exception_handler( request: Request, exc: Exception, ) -> JSONResponse: instance = request.url.path logger.exception( "Unhandled error", path=request.url.path, method=request.method, ) problem = build_problem_details( status_code=500, detail="Internal Server Error", instance=instance, ) return JSONResponse( status_code=500, content=problem.model_dump(), media_type="application/problem+json", )