adjust backend to serve static frontend files

This commit is contained in:
maxDorninger
2025-07-17 16:04:57 +02:00
parent 6016e3c155
commit 81c8381a90
3 changed files with 52 additions and 29 deletions

View File

@@ -24,6 +24,6 @@ COPY media_manager ./media_manager
COPY alembic ./alembic
COPY alembic.ini .
HEALTHCHECK CMD curl -f http://localhost:8000${MISC__API_BASE_PATH}/ || exit 1
HEALTHCHECK CMD curl -f http://localhost:8000${MISC__API_BASE_PATH}/health || exit 1
EXPOSE 8000
CMD ["/app/mediamanager-backend-startup.sh"]

View File

@@ -36,7 +36,7 @@ class BasicConfig(BaseSettings):
movie_directory: Path = Path(__file__).parent.parent / "data" / "movies"
torrent_directory: Path = Path(__file__).parent.parent / "data" / "torrents"
frontend_url: AnyHttpUrl = "http://localhost:3000/"
frontend_url: AnyHttpUrl = "http://localhost:3000/web/"
cors_urls: list[str] = []
development: bool = False
api_base_path: str = "/api/v1"

View File

@@ -6,6 +6,7 @@ from pathlib import Path
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
from pythonjsonlogger.json import JsonFormatter
from starlette.responses import FileResponse
import media_manager.database
@@ -90,7 +91,7 @@ from media_manager.exceptions import ( # noqa: E402
import shutil # noqa: E402
from fastapi import FastAPI # noqa: E402
from fastapi import FastAPI, APIRouter # noqa: E402
from fastapi.middleware.cors import CORSMiddleware # noqa: E402
from datetime import datetime # noqa: E402
from contextlib import asynccontextmanager # noqa: E402
@@ -146,9 +147,8 @@ async def lifespan(app: FastAPI):
scheduler.shutdown()
base_path = config.misc.api_base_path
log.info("Base Path for API: %s", base_path)
app = FastAPI(root_path=base_path, lifespan=lifespan)
app = FastAPI(lifespan=lifespan, root_path="")
FRONTEND_FILES_DIR = "/app/web/build"
origins = config.misc.cors_urls
log.info("CORS URLs activated for following origins:")
@@ -163,32 +163,33 @@ app.add_middleware(
allow_headers=["*"],
)
api_app = APIRouter(prefix="/api/v1")
# ----------------------------
# Standard Auth Routers
# ----------------------------
app.include_router(
api_app.include_router(
fastapi_users.get_auth_router(bearer_auth_backend),
prefix="/auth/jwt",
tags=["auth"],
)
app.include_router(
api_app.include_router(
fastapi_users.get_auth_router(cookie_auth_backend),
prefix="/auth/cookie",
tags=["auth"],
)
app.include_router(
api_app.include_router(
fastapi_users.get_register_router(UserRead, UserCreate),
prefix="/auth",
tags=["auth"],
)
app.include_router(
api_app.include_router(
fastapi_users.get_reset_password_router(),
prefix="/auth",
tags=["auth"],
)
app.include_router(
api_app.include_router(
fastapi_users.get_verify_router(UserRead),
prefix="/auth",
tags=["auth"],
@@ -198,8 +199,8 @@ app.include_router(
# User Management Routers
# ----------------------------
app.include_router(custom_users_router, tags=["users"])
app.include_router(
api_app.include_router(custom_users_router, tags=["users"])
api_app.include_router(
fastapi_users.get_users_router(UserRead, UserUpdate),
prefix="/users",
tags=["users"],
@@ -209,10 +210,10 @@ app.include_router(
# OpenID Connect Routers
# ----------------------------
app.include_router(auth_metadata_router, tags=["openid"])
api_app.include_router(auth_metadata_router, tags=["openid"])
if openid_client is not None:
app.include_router(
api_app.include_router(
get_oauth_router(
oauth_client=openid_client,
backend=openid_cookie_auth_backend,
@@ -225,11 +226,13 @@ if openid_client is not None:
tags=["openid"],
)
app.include_router(tv_router.router, prefix="/tv", tags=["tv"])
app.include_router(torrent_router.router, prefix="/torrent", tags=["torrent"])
app.include_router(movies_router.router, prefix="/movies", tags=["movie"])
app.include_router(notification_router, prefix="/notification", tags=["notification"])
app.mount(
api_app.include_router(tv_router.router, prefix="/tv", tags=["tv"])
api_app.include_router(torrent_router.router, prefix="/torrent", tags=["torrent"])
api_app.include_router(movies_router.router, prefix="/movies", tags=["movie"])
api_app.include_router(
notification_router, prefix="/notification", tags=["notification"]
)
api_app.mount(
"/static/image",
StaticFiles(directory=config.misc.image_directory),
name="static-images",
@@ -242,8 +245,36 @@ app.mount(
app.add_exception_handler(NotFoundError, not_found_error_exception_handler)
app.add_exception_handler(MediaAlreadyExists, media_already_exists_exception_handler)
app.add_exception_handler(InvalidConfigError, invalid_config_error_exception_handler)
@app.exception_handler(404)
async def not_found_handler(request, exc):
return FileResponse(f"{FRONTEND_FILES_DIR}/404.html")
# ----------------------------
# Hello World
# ----------------------------
@api_app.get("/health")
async def hello_world() -> dict:
"""
A simple endpoint to check if the API is running.
"""
return {"message": "Hello World!", "version": os.getenv("PUBLIC_VERSION")}
log.info("Hello World!")
# ----------------------------
# Include Api Router
# ----------------------------
app.include_router(api_app)
# ----------------------------
# Frontend Static Files
# ----------------------------
app.mount("/web", StaticFiles(directory=FRONTEND_FILES_DIR, html=True), name="frontend")
# ----------------------------
# Startup filesystem checks
# ----------------------------
@@ -294,14 +325,6 @@ except Exception as e:
log.error(f"Error creating test directory: {e}")
raise
@app.get("/")
async def hello_world() -> dict:
"""
A simple endpoint to check if the API is running.
"""
return {"message": "Hello World!", "version": os.getenv("PUBLIC_VERSION")}
if __name__ == "__main__":
# TODO: add feature to run app with different root_path
uvicorn.run(app, host="127.0.0.1", port=5049, log_config=LOGGING_CONFIG)