refactor: align backend layout and supabase infra
Consolidate backend modules/tests under the backend package while syncing Supabase compose/env config and related plans.
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
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",
|
||||
)
|
||||
Reference in New Issue
Block a user