diff --git a/fastapi-vue/README.md b/fastapi-vue/README.md index 3013b1e..7c3eb70 100644 --- a/fastapi-vue/README.md +++ b/fastapi-vue/README.md @@ -1,13 +1,13 @@ -# fastapi-vue +# FastAPI-Vue Runtime -Runtime helpers for FastAPI + Vite/Vue projects. +Runtime utilities for making FastAPI apps standalone, with their own CLI entry point and facilities that make the FastAPI + Vue stack pleasant to use. -## Overview +ℹ️ Use [fastapi-vue-setup](https://pypi.org/project/fastapi-vue-setup/) to set up your project. Everything below is configured automatically by it. -This package provides: +## Main Components -- `fastapi_vue.Frontend`: serves built SPA assets (with SPA support, caching, and optional zstd) -- `fastapi_vue.server.run`: a small Uvicorn runner with convenient `listen` endpoint parsing +- **Frontend**: Serves static files with proper caching, compression and SPA support +- **Server**: Runs the FastAPI app from your own CLI entry point with uvicorn facilities vastly augmented ## Quickstart @@ -21,13 +21,11 @@ from fastapi_vue import Frontend frontend = Frontend(Path(__file__).with_name("frontend-build"), spa=True) - @asynccontextmanager async def lifespan(app: FastAPI): await frontend.load() yield - app = FastAPI(lifespan=lifespan) # Add API routes here... @@ -36,16 +34,16 @@ app = FastAPI(lifespan=lifespan) frontend.route(app, "/") ``` -## Frontend +If SPA mode is disabled, we only route the paths that actually exist, leaving anything else to your own handlers that come after and may themselves wish to catch all that remains. -`Frontend` serves a directory with: +## Frontend (fastapi_vue.Frontend) -- RAM caching, with zstd compression when smaller than original -- Browser caching: ETag + Last-Modified, Immutable assets -- Favicon mapping (serve PNG or other images there instead) -- SPA routing (serve browsers index.html at all paths not otherwise handled) +- Designed to serve at `/`, living together with your other routes +- SPA routing: serves `index.html` for paths not otherwise handled +- RAM caching with zstd compression +- Browser caching with ETag, Last-Modified and immutable assets -Dev-mode behavior with `FastAPI(debug=True)`: requests error HTTP 409 with a message telling you to use the Vite dev server instead. Avoids accidentally using outdated `frontend-build` during development. +With `FastAPI(debug=True)`, frontend requests return HTTP 409 with a message directing you to the Vite dev server. This prevents accidentally serving an outdated frontend build during development. - `directory`: Path on local filesystem - `index`: Index file name (default: `index.html`) @@ -55,11 +53,13 @@ Dev-mode behavior with `FastAPI(debug=True)`: requests error HTTP 409 with a mes - `favicon`: Optional path or glob (e.g. `/assets/logo*.png`) - `zstdlevel`: Compression level (default: 18) -ℹ️ Even when your page has a meta tag giving favicon location, browsers still try loading `/favicon.ico` whenever looking at something else. We find it more convenient to simply serve the image where the browser expects it, with correct MIME type. This also allows having a default favicon for your application that can be easily overriden at the reverse proxy (Caddy, Nginx) to serve the company branding if needed in deployment. +ℹ️ Browsers commonly request `/favicon.ico` even when another icon is specified in HTML. The favicon option lets you serve an SVG or PNG there instead. This also provides a convenient application default that a deployment reverse proxy such as Caddy or Nginx can override with company branding. -## Server runner +## Server runner (fastapi_vue.server) -When you need more flexibility than `fastapi` CLI can provide (e.g. CLI arguments to your own program), you may use this convenience to run FastAPI app with Uvicorn startup on given `listen` endpoints. Runs in the same process if possible but delegates to uvicorn supervisors for auto-reloads and multiple workers. `localhost` binds both 127.0.0.1 and ::1, so the server stays reachable regardless of how the name resolves. This would typically be called from your CLI main, which can set its own env variables to pass information to the FastAPI instances that run (Python imports only work in same-process mode). +When you need more flexibility than the `fastapi` CLI provides—for example, to support arguments in your own CLI—you can use the bundled server runner. + +It starts the FastAPI app, running directly in the current process when possible and delegating to Uvicorn supervisors for reloads and multiple workers. The `server.run` is modeled after `uvicorn.run` that you would otherwise have to use to run FastAPI. ```python from fastapi_vue import server @@ -67,14 +67,33 @@ from fastapi_vue import server server.run("my_app.app:app", listen=["localhost:8000"]) ``` -- As a deployment option, environment `FORWARDED_ALLOW_IPS` controls `X-Forwarded` trusted IPs (default: `127.0.0.1,::1`). +Endpoints are plain strings: `host:port`, a bare port (localhost only), `:port` (all interfaces), or a unix socket path. Multiple endpoints can be served simultaneously. This also avoids Uvicorn's localhost limitation, where localhost may bind only to either 127.0.0.1 or ::1. -## Environment variables +A single `reload` argument replaces Uvicorn's separate reload arguments and may directly specify paths to watch. -The generated project entry point sets `FASTAPI_VUE` to the project's environment prefix (e.g. `MY_APP`), and settings are passed as `_*` variables. `fastapi_vue.env` resolves them, lazily on each access: +A startup box with the app name, version and connect URL is printed before serving. Pass a `startup_box` template (`{name}`, `{version}`, `{listen}`, `{url}`, ...) to customize it, None to disable, or use `server.print_startup_box` on its own. + +Printed by `server.run("my_app.app:app", listen=["localhost:3100"])`: + +``` +╭──────────────────────────────────────────╮ +│ My App 0.1.0 @ 127.0.0.1:3100 [::1]:3100 │ +│ http://localhost:3100 │ +╰──────────────────────────────────────────╯ +``` + +Logging is integrated as well: removes noisy uvicorn logging, replacing it with prettified log formatting, a colored access log and tracebacks rendered by [tracerite](https://pypi.org/project/tracerite/). Note that HTTP responses also include tracerite formatting when `FastAPI(debug=True)` is used. + +Other arguments are generally passed to `uvicorn.run`, although some like `log_config` receive our modifications. + +> As a deployment option, environment `FORWARDED_ALLOW_IPS` controls `X-Forwarded` trusted IPs (default: `127.0.0.1,::1` works for typical setups). + +### Environment (fastapi_vue.env) + +We use environment variables to pass values between program components, from devserver script setting dev mode and telling backend and frontend URLs, to your CLI, which in turn runs the FastAPI app that may also need access to this information. The variables are prefixed by the current application name to avoid conflicts. The CLI entry point should set one like `os.environ["FASTAPI_VUE"] = "MY_APP"`, before using `server.run` + +The following properties read the environment and return `None` when variables haven't been set: -- `fastapi_vue.env.dev` — running under the devserver (`_DEV=1`) -- `fastapi_vue.env.vite_url`, `fastapi_vue.env.backend_url` — URLs set by the devserver - `fastapi_vue.env.prefix` — the prefix itself - -Value accessors return `None` when `FASTAPI_VUE` or the variable is not set. +- `fastapi_vue.env.dev` — running in development mode, from e.g. `MY_APP_DEV=1` +- `fastapi_vue.env.vite_url`, `fastapi_vue.env.backend_url` — URLs set by the devserver diff --git a/fastapi-vue/fastapi_vue/server.py b/fastapi-vue/fastapi_vue/server.py index ebe0baf..51b04b6 100644 --- a/fastapi-vue/fastapi_vue/server.py +++ b/fastapi-vue/fastapi_vue/server.py @@ -118,7 +118,7 @@ def run( # noqa: PLR0913 reload: bool | Path = False, workers: int | None = None, access_log: bool = True, - startup_box: str | None = "{Name} {version}\n{url}", + startup_box: str | None = "{Name} {version} @ {listen}\n{url}", log_config: Any = uvicorn.config.LOGGING_CONFIG, # noqa: ANN401 **uvicorn_config: Any, # noqa: ANN401 ) -> None: