npx skills add https://github.com/fastapi/fastapi --skill fastapi官方 FastAPI 技能,用于编写遵循最佳实践的代码,保持与新版本和功能的同步。
fastapi CLI在 localhost 上运行带热重载的开发服务器:
fastapi dev
运行生产服务器:
fastapi run
pyproject.toml 中添加入口点FastAPI CLI 会读取 pyproject.toml 中的入口点,以了解 FastAPI 应用在何处声明。
[tool.fastapi]
entrypoint = "my_app.main:app"
fastapi当无法将入口点添加到 pyproject.toml,或者用户明确要求不添加,或者正在运行一个独立的小型应用时,你可以将应用文件路径传递给 命令:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
fastapifastapi dev my_app/main.py
尽可能在 pyproject.toml 中设置入口点。
Annotated在参数和依赖声明中,始终优先使用 Annotated 风格。
它能使函数签名在其他上下文中正常工作,尊重类型,并允许重用。
对参数声明使用 Annotated,包括 Path、Query、Header 等:
from typing import Annotated
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(
item_id: Annotated[int, Path(ge=1, description="The item ID")],
q: Annotated[str | None, Query(max_length=50)] = None,
):
return {"message": "Hello World"}
而不是:
# 不要这样做
@app.get("/items/{item_id}")
async def read_item(
item_id: int = Path(ge=1, description="The item ID"),
q: str | None = Query(default=None, max_length=50),
):
return {"message": "Hello World"}
对带有 Depends() 的依赖项使用 Annotated。
除非被要求不这样做,否则为依赖项创建一个新的类型别名以允许重用。
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
def get_current_user():
return {"username": "johndoe"}
CurrentUserDep = Annotated[dict, Depends(get_current_user)]
@app.get("/items/")
async def read_item(current_user: CurrentUserDep):
return {"message": "Hello World"}
而不是:
# 不要这样做
@app.get("/items/")
async def read_item(current_user: dict = Depends(get_current_user)):
return {"message": "Hello World"}
不要使用 ... 作为必需参数的默认值,这既不需要也不推荐。
这样做,不使用省略号 (...):
from typing import Annotated
from fastapi import FastAPI, Query
from pydantic import BaseModel, Field
class Item(BaseModel):
name: str
description: str | None = None
price: float = Field(gt=0)
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item, project_id: Annotated[int, Query()]): ...
而不是这样:
# 不要这样做
class Item(BaseModel):
name: str = ...
description: str | None = None
price: float = Field(..., gt=0)
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item, project_id: Annotated[int, Query(...)]): ...
尽可能包含返回类型。它将用于验证、过滤、文档化和序列化响应。
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
@app.get("/items/me")
async def get_item() -> Item:
return Item(name="Plumbus", description="All-purpose home device")
重要:返回类型或响应模型是过滤数据、确保不暴露敏感信息的关键。它们用于通过 Pydantic(在 Rust 中)序列化数据,这是提高响应性能的主要思路。
返回类型不一定是 Pydantic 模型,它可以是其他类型,如整数列表、字典等。
response_model 替代如果返回类型与你想要用于验证、过滤或序列化的类型不同,请改用装饰器上的 response_model 参数。
from typing import Any
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
@app.get("/items/me", response_model=Item)
async def get_item() -> Any:
return {"name": "Foo", "description": "A very nice Item"}
这在过滤数据以仅暴露公共字段并避免暴露敏感信息时特别有用。
from typing import Any
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class InternalItem(BaseModel):
name: str
description: str | None = None
secret_key: str
class Item(BaseModel):
name: str
description: str | None = None
@app.get("/items/me", response_model=Item)
async def get_item() -> Any:
item = InternalItem(
name="Foo", description="A very nice Item", secret_key="supersecret"
)
return item
不要使用 ORJSONResponse 或 UJSONResponse,它们已弃用。
相反,声明一个返回类型或响应模型。Pydantic 将在 Rust 端处理数据序列化。
在声明路由器时,优先将路由器级别的参数(如前缀、标签等)添加到路由器本身,而不是在 include_router() 中添加。
这样做:
from fastapi import APIRouter, FastAPI
app = FastAPI()
router = APIRouter(prefix="/items", tags=["items"])
@router.get("/")
async def list_items():
return []
# 在 main.py 中
app.include_router(router)
而不是这样:
# 不要这样做
from fastapi import APIRouter, FastAPI
app = FastAPI()
router = APIRouter()
@router.get("/")
async def list_items():
return []
# 在 main.py 中
app.include_router(router, prefix="/items", tags=["items"])
可能存在例外情况,但请尽量遵循此约定。
通过 dependencies=[Depends(...)] 在路由器级别应用共享依赖项。
有关详细模式(包括带 scope 的 yield 和类依赖项),请参阅依赖注入参考。
当逻辑无法在 Pydantic 验证中声明、依赖于外部资源、需要清理(使用 yield)或在多个端点之间共享时,请使用依赖项。
通过 dependencies=[Depends(...)] 在路由器级别应用共享依赖项。
仅当完全确定内部调用的逻辑与 async 和 await 兼容(使用 await 调用)或不阻塞时,才使用 async 路径操作。
from fastapi import FastAPI
app = FastAPI()
# 调用异步代码时使用 async def
@app.get("/async-items/")
async def read_async_items():
data = await some_async_library.fetch_items()
return data
# 调用阻塞/同步代码或有疑问时使用普通 def
@app.get("/items/")
def read_items():
data = some_blocking_library.fetch_items()
return data
如有疑问或默认情况下,请使用常规的 def 函数,这些函数将在线程池中运行,因此不会阻塞事件循环。
同样的规则适用于依赖项。
确保阻塞代码不在 async 函数内部运行。逻辑会正常工作,但会严重损害性能。
当需要混合阻塞和异步代码时,请参阅其他工具参考中的 Asyncer。
有关 JSON 行、服务器发送事件(EventSourceResponse、ServerSentEvent)和字节流(StreamingResponse)模式,请参阅流式传输参考。
有关 uv、Ruff、ty 用于包管理、代码检查、类型检查、格式化等的详细信息,请参阅其他工具参考。
有关其他库的详细信息,请参阅其他工具参考:
不要使用 Pydantic RootModel,而是使用带有 Annotated 和 Pydantic 验证实用程序的常规类型注解。
例如,对于带验证的列表,你可以这样做:
from typing import Annotated
from fastapi import Body, FastAPI
from pydantic import Field
app = FastAPI()
@app.post("/items/")
async def create_items(items: Annotated[list[int], Field(min_length=1), Body()]):
return items
而不是:
# 不要这样做
from typing import Annotated
from fastapi import FastAPI
from pydantic import Field, RootModel
app = FastAPI()
class ItemList(RootModel[Annotated[list[int], Field(min_length=1)]]):
pass
@app.post("/items/")
async def create_items(items: ItemList):
return items
FastAPI 支持这些类型注解,并将为它们创建一个 Pydantic TypeAdapter,因此类型可以正常工作,并且不需要 RootModels 中的自定义逻辑和类型。
不要在一个函数中混合 HTTP 操作,每个 HTTP 操作对应一个函数有助于分离关注点和组织代码。
这样做:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
@app.get("/items/")
async def list_items():
return []
@app.post("/items/")
async def create_item(item: Item):
return item
而不是这样:
# 不要这样做
from fastapi import FastAPI, Request
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
@app.api_route("/items/", methods=["GET", "POST"])
async def handle_items(request: Request):
if request.method == "GET":
return []
每周安装量
755
仓库
GitHub 星标数
96.6K
首次出现
2026年2月25日
安全审计
安装于
codex713
opencode704
cursor703
github-copilot701
gemini-cli701
kimi-cli700
Official FastAPI skill to write code with best practices, keeping up to date with new versions and features.
fastapi CLIRun the development server on localhost with reload:
fastapi dev
Run the production server:
fastapi run
pyproject.tomlFastAPI CLI will read the entrypoint in pyproject.toml to know where the FastAPI app is declared.
[tool.fastapi]
entrypoint = "my_app.main:app"
fastapi with a pathWhen adding the entrypoint to pyproject.toml is not possible, or the user explicitly asks not to, or it's running an independent small app, you can pass the app file path to the fastapi command:
fastapi dev my_app/main.py
Prefer to set the entrypoint in pyproject.toml when possible.
AnnotatedAlways prefer the Annotated style for parameter and dependency declarations.
It keeps the function signatures working in other contexts, respects the types, allows reusability.
Use Annotated for parameter declarations, including Path, Query, Header, etc.:
from typing import Annotated
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(
item_id: Annotated[int, Path(ge=1, description="The item ID")],
q: Annotated[str | None, Query(max_length=50)] = None,
):
return {"message": "Hello World"}
instead of:
# DO NOT DO THIS
@app.get("/items/{item_id}")
async def read_item(
item_id: int = Path(ge=1, description="The item ID"),
q: str | None = Query(default=None, max_length=50),
):
return {"message": "Hello World"}
Use Annotated for dependencies with Depends().
Unless asked not to, create a new type alias for the dependency to allow re-using it.
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
def get_current_user():
return {"username": "johndoe"}
CurrentUserDep = Annotated[dict, Depends(get_current_user)]
@app.get("/items/")
async def read_item(current_user: CurrentUserDep):
return {"message": "Hello World"}
instead of:
# DO NOT DO THIS
@app.get("/items/")
async def read_item(current_user: dict = Depends(get_current_user)):
return {"message": "Hello World"}
Do not use ... as a default value for required parameters, it's not needed and not recommended.
Do this, without Ellipsis (...):
from typing import Annotated
from fastapi import FastAPI, Query
from pydantic import BaseModel, Field
class Item(BaseModel):
name: str
description: str | None = None
price: float = Field(gt=0)
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item, project_id: Annotated[int, Query()]): ...
instead of this:
# DO NOT DO THIS
class Item(BaseModel):
name: str = ...
description: str | None = None
price: float = Field(..., gt=0)
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item, project_id: Annotated[int, Query(...)]): ...
When possible, include a return type. It will be used to validate, filter, document, and serialize the response.
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
@app.get("/items/me")
async def get_item() -> Item:
return Item(name="Plumbus", description="All-purpose home device")
Important : Return types or response models are what filter data ensuring no sensitive information is exposed. And they are used to serialize data with Pydantic (in Rust), this is the main idea that can increase response performance.
The return type doesn't have to be a Pydantic model, it could be a different type, like a list of integers, or a dict, etc.
response_model insteadIf the return type is not the same as the type that you want to use to validate, filter, or serialize, use the response_model parameter on the decorator instead.
from typing import Any
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
@app.get("/items/me", response_model=Item)
async def get_item() -> Any:
return {"name": "Foo", "description": "A very nice Item"}
This can be particularly useful when filtering data to expose only the public fields and avoid exposing sensitive information.
from typing import Any
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class InternalItem(BaseModel):
name: str
description: str | None = None
secret_key: str
class Item(BaseModel):
name: str
description: str | None = None
@app.get("/items/me", response_model=Item)
async def get_item() -> Any:
item = InternalItem(
name="Foo", description="A very nice Item", secret_key="supersecret"
)
return item
Do not use ORJSONResponse or UJSONResponse, they are deprecated.
Instead, declare a return type or response model. Pydantic will handle the data serialization on the Rust side.
When declaring routers, prefer to add router level parameters like prefix, tags, etc. to the router itself, instead of in include_router().
Do this:
from fastapi import APIRouter, FastAPI
app = FastAPI()
router = APIRouter(prefix="/items", tags=["items"])
@router.get("/")
async def list_items():
return []
# In main.py
app.include_router(router)
instead of this:
# DO NOT DO THIS
from fastapi import APIRouter, FastAPI
app = FastAPI()
router = APIRouter()
@router.get("/")
async def list_items():
return []
# In main.py
app.include_router(router, prefix="/items", tags=["items"])
There could be exceptions, but try to follow this convention.
Apply shared dependencies at the router level via dependencies=[Depends(...)].
See the dependency injection reference for detailed patterns including yield with scope, and class dependencies.
Use dependencies when the logic can't be declared in Pydantic validation, depends on external resources, needs cleanup (with yield), or is shared across endpoints.
Apply shared dependencies at the router level via dependencies=[Depends(...)].
Use async path operations only when fully certain that the logic called inside is compatible with async and await (it's called with await) or that doesn't block.
from fastapi import FastAPI
app = FastAPI()
# Use async def when calling async code
@app.get("/async-items/")
async def read_async_items():
data = await some_async_library.fetch_items()
return data
# Use plain def when calling blocking/sync code or when in doubt
@app.get("/items/")
def read_items():
data = some_blocking_library.fetch_items()
return data
In case of doubt, or by default, use regular def functions, those will be run in a threadpool so they don't block the event loop.
The same rules apply to dependencies.
Make sure blocking code is not run inside of async functions. The logic will work, but will damage the performance heavily.
When needing to mix blocking and async code, see Asyncer in the other tools reference.
See the streaming reference for JSON Lines, Server-Sent Events (EventSourceResponse, ServerSentEvent), and byte streaming (StreamingResponse) patterns.
See the other tools reference for details on uv, Ruff, ty for package management, linting, type checking, formatting, etc.
See the other tools reference for details on other libraries:
Do not use Pydantic RootModel, instead use regular type annotations with Annotated and Pydantic validation utilities.
For example, for a list with validations you could do:
from typing import Annotated
from fastapi import Body, FastAPI
from pydantic import Field
app = FastAPI()
@app.post("/items/")
async def create_items(items: Annotated[list[int], Field(min_length=1), Body()]):
return items
instead of:
# DO NOT DO THIS
from typing import Annotated
from fastapi import FastAPI
from pydantic import Field, RootModel
app = FastAPI()
class ItemList(RootModel[Annotated[list[int], Field(min_length=1)]]):
pass
@app.post("/items/")
async def create_items(items: ItemList):
return items
FastAPI supports these type annotations and will create a Pydantic TypeAdapter for them, so that types can work as normally and there's no need for the custom logic and types in RootModels.
Don't mix HTTP operations in a single function, having one function per HTTP operation helps separate concerns and organize the code.
Do this:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
@app.get("/items/")
async def list_items():
return []
@app.post("/items/")
async def create_item(item: Item):
return item
instead of this:
# DO NOT DO THIS
from fastapi import FastAPI, Request
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
@app.api_route("/items/", methods=["GET", "POST"])
async def handle_items(request: Request):
if request.method == "GET":
return []
Weekly Installs
755
Repository
GitHub Stars
96.6K
First Seen
Feb 25, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex713
opencode704
cursor703
github-copilot701
gemini-cli701
kimi-cli700
agent-browser 浏览器自动化工具 - Vercel Labs 命令行网页操作与测试
136,300 周安装