Content Index
FastAPI provides efficient mechanisms to manage client applications (Frontend) built with modern frameworks like Vue, React, or Svelte. This functionality simplifies the deployment of single-page user interfaces (SPAs) alongside the backend, optimizing communication and eliminating the need to configure independent web servers.
1. Using the Native Frontend Method
The most straightforward way to serve a client-side built interface is by using the native method provided by the framework. After compiling the frontend project (generating distribution files in a folder like dist using packaging commands), it is enough to link the output directory directly to the main application:
$ app.frontend("/ui", directory="frontend/dist")This method automatically handles resolving routes, integrating client-side routers (such as Vue Router), and serving the main index.html file without requiring additional routing configurations or manual 404 error management.
2. Project Structure and Hybrid Deployment
In a hybrid architecture combining a FastAPI backend with a modern client interface, the typical project structure separates endpoint logic from compiled static resources:
- Backend Module: Contains Python scripts, database configuration, and API routers integrated via
include_router. - Frontend Directory: Houses the interface source code and generates the distribution folder with files packaged in HTML, CSS, and JavaScript.
Thus, high-performance backend services coexist harmoniously with the user's visual experience in a single integrated application.
3. Advanced Implementation with Custom Classes (StaticFiles)
In scenarios requiring exhaustive control over caching and response handling for SPAs (such as redirecting not-found requests to the index.html file so the client router manages navigation), it is possible to implement a custom class inherited from StaticFiles.
class SpaStaticFiles(StaticFiles):
"""StaticFiles that redirects to index.html on route 404 errors."""
def lookup_path(self, path: str) -> tuple[str, os.stat_result | None]:
self.all_directories = [os.fspath(CARPETA_UI)]
return super().lookup_path(path)
async def get_response(self, path: str, scope: Scope) -> Response:
if not dist_esta_construido():
return HTMLResponse(PAGINA_SIN_BUILD, status_code=status.HTTP_503_SERVICE_UNAVAILABLE)
servido = path
try:
respuesta = await super().get_response(path, scope)
except StarletteHTTPException as exc:
if exc.status_code != 404 or "." in Path(path).name:
raise
respuesta = await super().get_response("index.html", scope)
servido = "index.html"
return self._con_cache_adequate(servido, respuesta)
app.mount(
"/",
SpaStaticFiles(directory=str(CARPETA_UI), html=True, check_dir=False),
name="ui",
)This advanced approach allows managing cache HTTP headers differently, applying immutability policies to hashed assets and ensuring that the main file maintains constant validation.