diff --git a/README.md b/README.md index a37d72f3..f93ed702 100644 --- a/README.md +++ b/README.md @@ -76,13 +76,6 @@ You can run: yarn install --ignore-engines ``` -Next, run the following commands: - -``` -yarn build -mv build/ ../server/curfu/build -``` - Then start the development server: ```commandline diff --git a/server/src/curfu/main.py b/server/src/curfu/main.py index 0f5df845..694cf2d4 100644 --- a/server/src/curfu/main.py +++ b/server/src/curfu/main.py @@ -1,5 +1,6 @@ """Provide FastAPI application and route declarations.""" +import logging from collections.abc import AsyncGenerator from contextlib import asynccontextmanager @@ -25,6 +26,8 @@ validate, ) +_logger = logging.getLogger(__name__) + fastapi_app = FastAPI( title="Fusion Curation API", description="Provide data functions to support [VICC Fusion Curation interface](fusion-builder.cancervariants.org/).", @@ -66,32 +69,46 @@ def serve_react_app(app: FastAPI) -> FastAPI: - """Wrap application initialization in Starlette route param converter. + """Wrap application initialization in Starlette route param converter. This ensures + that the static web client files can be served from the backend. + + Client source must be available at the location specified by `BUILD_DIR` in a + production environment. However, this may not be necessary during local development, + so the `RuntimeError` is simply caught and logged. + + For the live service, `.ebextensions/01_build.config` includes code to build a + production version of the client and move it to the proper location. :param app: FastAPI application instance :return: application with React frontend mounted """ - app.mount( - "/static/", - StaticFiles(directory=BUILD_DIR / "static"), - name="React application static files", - ) - templates = Jinja2Templates(directory=BUILD_DIR.as_posix()) - - @app.get("/{full_path:path}", include_in_schema=False) - async def serve_react_app(request: Request, full_path: str) -> TemplateResponse: # noqa: ARG001 - """Add arbitrary path support to FastAPI service. - - React-router provides something akin to client-side routing based out - of the Javascript embedded in index.html. However, FastAPI will intercede - and handle all client requests, and will 404 on any non-server-defined paths. - This function reroutes those otherwise failed requests against the React-Router - client, allowing it to redirect the client to the appropriate location. - :param request: client request object - :param full_path: request path - :return: Starlette template response object - """ - return templates.TemplateResponse("index.html", {"request": request}) + try: + static_files = StaticFiles(directory=BUILD_DIR / "static") + except RuntimeError: + _logger.error("Unable to access static build files -- does the folder exist?") + else: + app.mount( + "/static/", + static_files, + name="React application static files", + ) + templates = Jinja2Templates(directory=BUILD_DIR.as_posix()) + + @app.get("/{full_path:path}", include_in_schema=False) + async def serve_react_app(request: Request, full_path: str) -> TemplateResponse: # noqa: ARG001 + """Add arbitrary path support to FastAPI service. + + React-router provides something akin to client-side routing based out + of the Javascript embedded in index.html. However, FastAPI will intercede + and handle all client requests, and will 404 on any non-server-defined paths. + This function reroutes those otherwise failed requests against the React-Router + client, allowing it to redirect the client to the appropriate location. + + :param request: client request object + :param full_path: request path + :return: Starlette template response object + """ + return templates.TemplateResponse("index.html", {"request": request}) return app