Coverage for apps/kwai-api/src/kwai_api/frontend/app.py: 21%

47 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2024-01-01 00:00 +0000

1"""Module that defines a sub application for handling the frontend.""" 

2 

3import uuid 

4 

5from pathlib import Path 

6from typing import Annotated 

7 

8from fastapi import Depends, FastAPI, Request, status 

9from fastapi.responses import FileResponse, JSONResponse, RedirectResponse 

10from kwai_core.settings import Settings, get_settings 

11from loguru import logger 

12 

13from kwai_api.frontend.apps import application_routers 

14 

15 

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.") 

22 

23 

24def create_frontend(): 

25 """Create the frontend.""" 

26 frontend_app = FastAPI() 

27 

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") 

34 

35 try: 

36 response = await call_next(request) 

37 except Exception as ex: 

38 logger.error(f"{request.url} - Request failed: {ex}") 

39 logger.exception(ex) 

40 response = JSONResponse( 

41 content={ 

42 "detail": str(ex), 

43 }, 

44 status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, 

45 ) 

46 finally: 

47 response.headers["X-Request-ID"] = request_id 

48 logger.info( 

49 f"{request.url} - {request.method} - Request ended: " 

50 f"{response.status_code}" 

51 ) 

52 

53 return response 

54 

55 for router in application_routers: 

56 frontend_app.include_router(router, prefix="/apps") 

57 

58 @frontend_app.get("/favicon.ico", include_in_schema=False) 

59 def favicon() -> FileResponse: 

60 """Return the favicon.""" 

61 favicon_path = Path(__file__).parent.parent / "static" / "favicon.ico" 

62 if favicon_path.is_file(): 

63 return FileResponse(favicon_path) 

64 raise status.HTTP_404_NOT_FOUND 

65 

66 @frontend_app.get("/news/{path:path}", name="frontend.news") 

67 def news(path: Path, default_app: Annotated[str, Depends(get_default_app)]): 

68 """Redirect the news path to the portal application. 

69 

70 When FastAPI serves the frontend, the root path can't be used for the portal. 

71 So redirect this url to the root application. 

72 """ 

73 return RedirectResponse(f"/apps/{default_app}/news/{path}") 

74 

75 @frontend_app.get("/pages/{path:path}", name="frontend.pages") 

76 def pages(path: Path, default_app: Annotated[str, Depends(get_default_app)]): 

77 """Redirect the pages path to the portal application. 

78 

79 When FastAPI serves the frontend, the root path can't be used for the portal. 

80 So redirect this url to the root application. 

81 """ 

82 return RedirectResponse(f"/apps/{default_app}/pages/{path}") 

83 

84 @frontend_app.get("/", name="frontend.home") 

85 def root(default_app: Annotated[str, Depends(get_default_app)]): 

86 """Redirect index to the portal application.""" 

87 return RedirectResponse(f"/apps/{default_app}") 

88 

89 return frontend_app