Coverage for src/kwai/frontend/app.py: 0%
48 statements
« prev ^ index » next coverage.py v7.6.10, created at 2024-01-01 00:00 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2024-01-01 00:00 +0000
1"""Module that defines a sub application for handling the frontend."""
3import uuid
5from pathlib import Path
6from typing import Annotated
8from fastapi import Depends, FastAPI, Request, status
9from fastapi.responses import FileResponse, JSONResponse, RedirectResponse
10from loguru import logger
12from kwai.core.settings import Settings, get_settings
13from kwai.frontend.apps import application_routers
16def get_default_app(settings: Annotated[Settings, Depends(get_settings)]) -> str:
17 """Search for the default application in the settings."""
18 for app in settings.frontend.apps:
19 if app.default:
20 return app.name
21 raise ValueError("No default app defined in settings.")
24def create_frontend():
25 """Create the frontend."""
26 frontend_app = FastAPI()
28 @frontend_app.middleware("http")
29 async def log(request: Request, call_next):
30 """Middleware for logging the requests."""
31 request_id = str(uuid.uuid4())
32 with logger.contextualize(request_id=request_id):
33 logger.info(f"{request.url} - {request.method} - Request started")
35 response = None # Make pylint happy...
36 try:
37 response = await call_next(request)
38 except Exception as ex:
39 logger.error(f"{request.url} - Request failed: {ex}")
40 logger.exception(ex)
41 response = JSONResponse(
42 content={
43 "detail": str(ex),
44 },
45 status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
46 )
47 finally:
48 response.headers["X-Request-ID"] = request_id
49 logger.info(
50 f"{request.url} - {request.method} - Request ended: "
51 f"{response.status_code}"
52 )
54 return response
56 for router in application_routers:
57 frontend_app.include_router(router, prefix="/apps")
59 @frontend_app.get("/favicon.ico", include_in_schema=False)
60 def favicon() -> FileResponse:
61 """Return the favicon."""
62 favicon_path = Path(__file__).parent.parent / "static" / "favicon.ico"
63 if favicon_path.is_file():
64 return FileResponse(favicon_path)
65 raise status.HTTP_404_NOT_FOUND
67 @frontend_app.get("/news/{path:path}", name="frontend.news")
68 def news(path: Path, default_app: Annotated[str, Depends(get_default_app)]):
69 """Redirect the news path to the portal application.
71 When FastAPI serves the frontend, the root path can't be used for the portal.
72 So redirect this url to the root application.
73 """
74 return RedirectResponse(f"/apps/{default_app}/news/{path}")
76 @frontend_app.get("/pages/{path:path}", name="frontend.pages")
77 def pages(path: Path, default_app: Annotated[str, Depends(get_default_app)]):
78 """Redirect the pages path to the portal application.
80 When FastAPI serves the frontend, the root path can't be used for the portal.
81 So redirect this url to the root application.
82 """
83 return RedirectResponse(f"/apps/{default_app}/pages/{path}")
85 @frontend_app.get("/", name="frontend.home")
86 def root(default_app: Annotated[str, Depends(get_default_app)]):
87 """Redirect index to the portal application."""
88 return RedirectResponse(f"/apps/{default_app}")
90 return frontend_app