已發布·持續改進
FastAPI 指南 · 2/6
本章目前僅提供英文版。
FastAPI does not impose a folder layout. A single file is a fine place to start, but as endpoints pile up you will want to split them by feature. Based on the "Bigger Applications" example from the official docs, this chapter covers a common layout, routers, configuration files and conventions.
hello-fastapi/
├── app/
│ ├── __init__.py
│ ├── main.py # creates FastAPI(), registers routers
│ ├── dependencies.py # shared dependencies
│ ├── config.py # settings (pydantic-settings)
│ ├── models.py # Pydantic and SQLModel models
│ └── routers/
│ ├── __init__.py
│ ├── items.py
│ └── users.py
├── tests/
│ └── test_items.py
├── .env # local environment variables (not committed)
├── pyproject.toml # or requirements.txt
└── DockerfileThe app folder is a Python package. Every folder gets an __init__.py so imports like from app.routers import items work. Run the dev server with fastapi dev app/main.py; the fastapi command works out the package structure from the file path and finds the app object for you.
An APIRouter behaves like a small FastAPI app. Create one per feature and give it a shared path prefix and documentation tags in one place.
# app/routers/items.py
from fastapi import APIRouter, HTTPException
router = APIRouter(prefix="/items", tags=["items"])
fake_items = {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}}
@router.get("/")
def list_items():
return fake_items
@router.get("/{item_id}")
def read_item(item_id: str):
if item_id not in fake_items:
raise HTTPException(status_code=404, detail="Item not found")
return fake_items[item_id]main.py then only creates the app and registers routers. The entry point stays short, and each feature's code lives in its own file.
# app/main.py
from fastapi import FastAPI
from app.routers import items, users
app = FastAPI(title="Hello FastAPI", version="0.1.0")
app.include_router(items.router)
app.include_router(users.router)
@app.get("/health")
def health():
return {"status": "ok"}include_router also accepts prefix, tags and dependencies, so you can mount the same router under /api/v1, or require authentication for an entire admin router.
Dependencies shared by several routers belong in dependencies.py. Here is a simple check of a token in a request header:
# app/dependencies.py
from typing import Annotated
from fastapi import Header, HTTPException
async def verify_token(x_token: Annotated[str, Header()]):
if x_token != "secret-token":
raise HTTPException(status_code=400, detail="X-Token header invalid")Pass it when creating a router, as in APIRouter(dependencies=[Depends(verify_token)]), and it applies to every route on that router. The parameter name x_token is automatically mapped to the x-token header.
Project dependencies usually go in pyproject.toml, which tools such as uv, Poetry and Hatch read to manage the virtual environment. If you only use pip, a requirements.txt is enough.
[project]
name = "hello-fastapi"
version = "0.1.0"
requires-python = ">=3.10"
dependencies = [
"fastapi[standard]",
"sqlmodel",
"pydantic-settings",
]
[dependency-groups]
dev = ["pytest", "ruff"]Keep values such as database URLs and secret keys out of the code and pass them in through environment variables or a .env file. Add .env to .gitignore and commit a .env.example listing just the variable names. Chapter 4 shows how to read these settings.
Resources that should be prepared once when the app starts and cleaned up when it stops, such as a connection pool or a machine learning model, are handled with lifespan:
from contextlib import asynccontextmanager
from fastapi import FastAPI
@asynccontextmanager
async def lifespan(app: FastAPI):
print("starting up") # open connections, load models
yield
print("shutting down") # release resources
app = FastAPI(lifespan=lifespan)Code before yield runs before the first request is served; code after it runs when the server stops.
| Topic | Convention |
|---|---|
| Entry point | the app variable in app/main.py |
| Routers | one file per feature, router = APIRouter(prefix=..., tags=[...]) |
| Models | separate input and output models (ItemCreate, ItemPublic) |
| Tests | tests/test_*.py, run with pytest |
| Secrets | environment variables or .env, never committed |
main.py, then move to an app package with a routers folder as it grows.APIRouter and register them with app.include_router.dependencies.py and configuration in environment variables or .env.lifespan.
0 則留言
登入 · 登入後即可留言。
來留下第一則留言吧。