3 changed files with 128 additions and 0 deletions
@ -0,0 +1,119 @@ |
|||
# Frontend { #frontend } |
|||
|
|||
You can serve static frontend apps with `app.frontend()` (or `router.frontend()`). |
|||
|
|||
This is useful for frontend tools that generate static files, like React with Vite, TanStack Router, Astro, Vue, Svelte, Angular, Solid, and others. |
|||
|
|||
With these tools, you normally have a step that builds the frontend, with a command like: |
|||
|
|||
```bash |
|||
npm run build |
|||
``` |
|||
|
|||
That would generate a directory like `./dist/` with your frontend files. |
|||
|
|||
You can use `app.frontend()` to serve that directory following the conventions needed by these frontend frameworks. |
|||
|
|||
**FastAPI** checks *path operations* first. The frontend files are checked only if no normal route matched, so your API won't be affected. |
|||
|
|||
## Serve a Frontend { #serve-a-frontend } |
|||
|
|||
After building your frontend, for example with `npm run build`, put the generated files in a directory, for example, `dist`. |
|||
|
|||
Your project structure could look like this: |
|||
|
|||
```text |
|||
. |
|||
├── pyproject.toml |
|||
├── app |
|||
│ ├── __init__.py |
|||
│ └── main.py |
|||
└── dist |
|||
├── index.html |
|||
└── assets |
|||
└── app.js |
|||
``` |
|||
|
|||
Then serve it with `app.frontend()`: |
|||
|
|||
{* ../../docs_src/frontend/tutorial001_py310.py hl[5] *} |
|||
|
|||
With this, a request for `/assets/app.js` can serve `dist/assets/app.js`. |
|||
|
|||
If you also have a **FastAPI** *path operation*, the *path operation* wins. |
|||
|
|||
## Client-Side Routing { #client-side-routing } |
|||
|
|||
Many frontend apps, including **single-page apps** (SPAs), use client-side routing. A path like `/dashboard/settings` might not be a real file but the framework would take care of handling it. |
|||
|
|||
So, if accessing that URL directly (instead of navigating through the app), the backend should serve the frontend app from `index.html`, so that the frontend framework can then handle the client-side routing. |
|||
|
|||
For that, use `fallback="index.html"`: |
|||
|
|||
{* ../../docs_src/frontend/tutorial002_py310.py hl[5] *} |
|||
|
|||
**FastAPI** uses this fallback only for requests that look like browser navigation. Missing files like JavaScript, CSS, and images still return `404`. |
|||
|
|||
/// tip |
|||
|
|||
By default, `fallback` has a value of `fallback="auto"`. In most cases you won't need to specify `fallback`. Read below for details. |
|||
|
|||
/// |
|||
|
|||
This is what you would want with many frontend apps that use client-side routing, for example, React with TanStack Router, Vue, Angular, SvelteKit, or Solid. |
|||
|
|||
## Custom 404 Page { #custom-404-page } |
|||
|
|||
You can also serve a static `404.html` page for missing frontend paths: |
|||
|
|||
{* ../../docs_src/frontend/tutorial003_py310.py hl[5] *} |
|||
|
|||
That response keeps a status code of `404`. |
|||
|
|||
In this case, **FastAPI** won't serve `index.html` for missing frontend paths. It will return the `404.html` file instead. |
|||
|
|||
/// tip |
|||
|
|||
By default, `fallback` has a value of `fallback="auto"`. With this, if a `404.html` file is found, it will be used as the fallback automatically. |
|||
|
|||
So, you can normally omit the `fallback` argument. |
|||
|
|||
/// |
|||
|
|||
This is useful with frontend tools that generate static HTML files for each page, like Astro. |
|||
|
|||
## Fallback Auto { #fallback-auto } |
|||
|
|||
By default, `app.frontend()` uses `fallback="auto"`. |
|||
|
|||
If there is a `404.html` file in the frontend directory, missing frontend paths serve that file with status code `404`. |
|||
|
|||
Otherwise, if there is an `index.html` file, missing browser navigation paths serve `index.html`, which is what many frontend apps with client-side routing expect. |
|||
|
|||
So, in most cases you can use `app.frontend("/", directory="dist")` without specifying the `fallback` argument. |
|||
|
|||
{* ../../docs_src/frontend/tutorial001_py310.py hl[5] *} |
|||
|
|||
## Disable Fallback { #disable-fallback } |
|||
|
|||
If you don't want to serve a fallback file for missing frontend paths, use `fallback=None`: |
|||
|
|||
{* ../../docs_src/frontend/tutorial005_py310.py hl[5] *} |
|||
|
|||
Then missing frontend paths return the normal `404`. |
|||
|
|||
## Use it with `APIRouter` { #use-it-with-apirouter } |
|||
|
|||
You can also add frontend files to an `APIRouter` and include it with a prefix: |
|||
|
|||
{* ../../docs_src/frontend/tutorial004_py310.py hl[6,7] *} |
|||
|
|||
In this example, frontend paths are served under `/app`. |
|||
|
|||
Any regular *path operations* in the app will still take precedence, including in other routers. |
|||
|
|||
## Static Build Output Only { #static-build-output-only } |
|||
|
|||
`app.frontend()` serves files already generated by your frontend build. |
|||
|
|||
It does not run server-side rendering. It is for frontend frameworks that generate static files, not for frameworks that need dynamic rendering on the server for each request. |
|||
Loading…
Reference in new issue