I've tried to mount the frontend to /
with app.mount
, but this invalidates all of my /api
routes. I've also tried the following code to mount the folders in /static
to their respective routes and serving the index.html
file on /
:
@app.get("/")
def index():
project_path = Path(__file__).parent.resolve()
frontend_root = project_path / "client/build"
return FileResponse(str(frontend_root) + '/index.html', media_type='text/html')
static_root = project_path / "client/build/static"
app.mount("/static", StaticFiles(directory=static_root), name="static")
This mostly works, but files contained in the client/build
folder aren't mounted and are thus inaccessible. I know that Node.js has a way of serving the front-end page with relative paths with res.sendFile("index.html", { root: </path/to/static/folder });
. Is there an equivalent function for doing this in FastAPI?
clmno's solution is two servers + routing. Jay Jay Cayabyab is looking for an endpoint on the API that serves a webpacked SPA, the kind you get after npm run build
. I was looking for the exact same solution, because that's what I'm doing with Flask and I'm trying to replace Flask with FastAPI.
Following FastAPI's documentation, it is mentioned multiple times that it's based on starlette. Searching for serving a SPA on starlette, I fount this reply to an issue. Of course, this did not work off the shelf for me because I was missing some import, unmentioned in the proposed solution.
Here's my code, and it is working:
from fastapi.staticfiles import StaticFiles
class SPAStaticFiles(StaticFiles):
async def get_response(self, path: str, scope):
response = await super().get_response(path, scope)
if response.status_code == 404:
response = await super().get_response('.', scope)
return response
app.mount('/my-spa/', SPAStaticFiles(directory='folder', html=True), name='whatever')
Note: I changed the names of endpoint (my-spa), directory (folder) and app name(whatever) on purpose to highlight the point that these need not be all the same.
In this case, you put the built SPA in the folder
folder. for this to work, in the SPA project folder, you run npm run build
or yarn run build
, and you get a folder called dist
. Copy all files and folders from dist
into this folder
folder.
Once you did this, run your FastAPI app and then go to http://localhost:5000/my-spa/
. For the sake of absolute clarity, the reason why I'm using this particular URL is that my app has a main like this:
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=5000)
so it starts off port 5000. Your case might differ.
I hate it when imports are missing from these replies, because it sometimes seems like the reply was never even run. Mine is running on the other screen as I type this, so it's not a waste of your time. However, I might be missing some import myself, assuming you're already doing the trivial
from fastapi import FastAPI
and such. If you try this and find anything missing, please let me know here.