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:
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 runnpm run build
oryarn run build
, and you get a folder calleddist
. Copy all files and folders fromdist
into thisfolder
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: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
and such. If you try this and find anything missing, please let me know here.