I'm trying to serve React SPA and a few API endpoints from FastAPI. React has its own routing, so in order to split responsibilities I use 2 FastAPI apps - one comes with all authorization bells and whistles and is mounted to the API route, and the second has one job - all requests that don't begin with /api
should return the SPA's index.html
. Sounds simple, right? Well, I either miss something really basic, or it's not that simple after all.
So this is the API app mounting (no questions here, works fine):
api_app = secure_authenticated_app() # returns a tweaked FastAPI app
# main app
app = FastAPI()
app.mount("/api", api_app, name="api")
But then, the party starts.
client_folder_path = pathlib.Path(__file__).parent.absolute().joinpath("build")
app.mount("", StaticFiles(directory=client_folder_path, html=True), name="client")
@app.get("/{full_path:path}")
async def serve_client():
with open(client_folder_path.joinpath("index.html")) as fh:
data = fh.read()
return Response(content=data, media_type="text/html")
My logic here following is: mount the client build folder to the root path so it could easily find all its assets, serve the index.html
when getting to the root path, and if you encounter some route that you don't know - no worries, just serve index.html
.
In reality it serves the html from the root path, other frontend assets are served too, but the /{full_path:path}
, which I keep seeing as a starlette solution for 'wildcard route', doesn't get hit - routes like /whtever
return 404.
I tried moving them around - with no luck, each time one of the features (either serving html from root, serving it from any other path or both) won't work. For the one coming from Node, this behavior is really surprising; is there a simple beautiful solution without writing full-blown helper classes?