Fix: move SPA catch-all route to end so API routes match first
The catch-all @app.get('/{full_path:path}') was defined before API routes,
causing GET requests for /api/* endpoints to be intercepted and served
the admin SPA index.html instead of the actual API response. Moving
the catch-all to after all API routes ensures proper route resolution.
This commit is contained in:
+15
-16
@@ -23,7 +23,7 @@ from typing import Optional
|
|||||||
|
|
||||||
from fastapi import FastAPI, HTTPException, Query, Request, UploadFile, File
|
from fastapi import FastAPI, HTTPException, Query, Request, UploadFile, File
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from fastapi.responses import JSONResponse, StreamingResponse
|
from fastapi.responses import FileResponse, JSONResponse, StreamingResponse
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
@@ -355,21 +355,6 @@ app.add_middleware(
|
|||||||
# Mount Cantaloupe sync routes
|
# Mount Cantaloupe sync routes
|
||||||
app.include_router(cantaloupe_router)
|
app.include_router(cantaloupe_router)
|
||||||
|
|
||||||
# Serve admin frontend SPA (single index.html, no external assets needed)
|
|
||||||
from fastapi.responses import FileResponse
|
|
||||||
|
|
||||||
FRONTEND_INDEX = Path(__file__).parent / "static" / "index.html"
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
|
||||||
@app.get("/{full_path:path}")
|
|
||||||
async def serve_frontend(full_path: str = ""):
|
|
||||||
"""Serve the admin SPA — all routes return index.html."""
|
|
||||||
if FRONTEND_INDEX.is_file():
|
|
||||||
return FileResponse(str(FRONTEND_INDEX))
|
|
||||||
return JSONResponse({"detail": "Frontend not found"}, status_code=404)
|
|
||||||
|
|
||||||
|
|
||||||
# ─── Auth Middleware ────────────────────────────────────────────────────────
|
# ─── Auth Middleware ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
@@ -1621,3 +1606,17 @@ def reset_database(request: Request):
|
|||||||
raise HTTPException(status_code=500, detail=f"Reset failed: {str(e)}")
|
raise HTTPException(status_code=500, detail=f"Reset failed: {str(e)}")
|
||||||
conn.close()
|
conn.close()
|
||||||
return {"detail": "Database reset complete — all tables recreated with seed data."}
|
return {"detail": "Database reset complete — all tables recreated with seed data."}
|
||||||
|
|
||||||
|
|
||||||
|
# ─── SPA Frontend (catch-all — MUST be last route) ────────────────────────
|
||||||
|
|
||||||
|
FRONTEND_INDEX = Path(__file__).parent / "static" / "index.html"
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
@app.get("/{full_path:path}")
|
||||||
|
async def serve_frontend(full_path: str = ""):
|
||||||
|
"""Serve the admin SPA — all routes return index.html."""
|
||||||
|
if FRONTEND_INDEX.is_file():
|
||||||
|
return FileResponse(str(FRONTEND_INDEX))
|
||||||
|
return JSONResponse({"detail": "Frontend not found"}, status_code=404)
|
||||||
|
|||||||
Reference in New Issue
Block a user