How to load a different file than index.html in FastAPI root path?

Viewed 61

Here is a simple static FastAPI app. With this setup even though the root path is expected to return a FileResponse of custom.html, the app still returns index.html. How can I get the root path work and render custom.html?

from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse

app = FastAPI()


app.mount(
    "/",
    StaticFiles(directory="static", html=True),
    name="static",
)

@app.get("/")
async def index() -> FileResponse:
    return FileResponse("custom.html", media_type="html")
1 Answers

As per Starlette documentation:

StaticFiles

Signature: StaticFiles(directory=None, packages=None, check_dir=True)

  • html - Run in HTML mode. Automatically loads index.html for directories if such file exists.

In addtion, as shown from the code snippet you provided, you have mounted StaticFiles to the root directory (i.e., '/'). As per FastAPI documentation:

"Mounting" means adding a complete "independent" application in a specific path, that then takes care of handling all the sub-paths.

Hence, any path that starts with '/' will be handled by that application, and due to specifying html=True, index.html will be automatically loaded; no matter if you have an endpoint pointed to the root path and trying to return something else.

If, for example, you moved app.mount("/",StaticFiles(... line after defining your @app.get("/") endpoint, you would see that order matters and index.html would not be automatically loaded anymore. However, you would get an Internal Server Error, as your @app.get("/") endpoint would be called and attempt to find custom.html, but such a file does not exist. That is because this file exists under 'static' directory (as shown from your code), not under '/', and hence, you would need to return FileResponse("static/custom.html").

Even if you removed html=True, but keep StaticFiles mounted to the root directory (and defined before your '/' endpoint), you would get a {"detail":"Not Found"} error response, when attempting to access http://localhost:8000/. This is because that request is still handled by that application (as mentioned earlier) and you should now need to specify the file that you would like to access, e.g., http://localhost:8000/index.html. Even if you define other endpoints in your code (e.g., /register, /login, /hello) - as long as StaticFiles is mounted to the root directory (i.e., '/') and defined in your code before all other endpoints - all requests to those routes will be handled by StaticFiles application and lead to a {"detail":"Not Found"} error response.

The html=True simply provides an easy way to serve a directory of web content with just one line of code. If you need to serve static files, such as package docs directory, then this is the way to go. If, however, you need to serve different HTML files that will get dynamically updated, as well as you wish to specify various routes/endpoints for each of them, you should have a look at Templates (not FileResponse), as well as mount your StaticFiles to a different directory (e.g., /static), rather than root directory (and without using html=True).

Related