mirror of
https://github.com/fastapi/fastapi.git
synced 2026-06-25 15:52:19 -04:00
Compare commits
11 Commits
dependabot
...
0.138.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b90c49aefa | ||
|
|
1f2f3df485 | ||
|
|
0af003a85d | ||
|
|
d5494c1f01 | ||
|
|
82c527e714 | ||
|
|
3f28dbe6d8 | ||
|
|
f6ea6b1f12 | ||
|
|
219ac634ab | ||
|
|
fcc8e1f994 | ||
|
|
457f4c705c | ||
|
|
29fc8f6166 |
4
.github/workflows/build-docs.yml
vendored
4
.github/workflows/build-docs.yml
vendored
@@ -4,10 +4,6 @@ on:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
|
||||
25
.github/workflows/issue-manager.yml
vendored
25
.github/workflows/issue-manager.yml
vendored
@@ -29,29 +29,6 @@ jobs:
|
||||
env:
|
||||
GITHUB_CONTEXT: ${{ toJson(github) }}
|
||||
run: echo "$GITHUB_CONTEXT"
|
||||
- uses: tiangolo/issue-manager@2fb3484ec9279485df8659e8ec73de262431737d # 0.6.0
|
||||
- uses: tiangolo/issue-manager@75d60679db1ea348f6f6ea1d0e20de80a7c04645 # 0.7.1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
config: >
|
||||
{
|
||||
"answered": {
|
||||
"delay": 864000,
|
||||
"message": "Assuming the original need was handled, this will be automatically closed now. But feel free to add more comments or create new issues or PRs."
|
||||
},
|
||||
"waiting": {
|
||||
"delay": 2628000,
|
||||
"message": "As this PR has been waiting for the original user for a while but seems to be inactive, it's now going to be closed. But if there's anyone interested, feel free to create a new PR.",
|
||||
"reminder": {
|
||||
"before": "P3D",
|
||||
"message": "Heads-up: this will be closed in 3 days unless there's new activity."
|
||||
}
|
||||
},
|
||||
"invalid": {
|
||||
"delay": 0,
|
||||
"message": "This was marked as invalid and will be closed now. If this is an error, please provide additional details."
|
||||
},
|
||||
"maybe-ai": {
|
||||
"delay": 0,
|
||||
"message": "This was marked as potentially AI generated and will be closed now. If this is an error, please provide additional details, make sure to read the docs about contributing and AI."
|
||||
}
|
||||
}
|
||||
|
||||
4
.github/workflows/pre-commit.yml
vendored
4
.github/workflows/pre-commit.yml
vendored
@@ -2,10 +2,6 @@ name: pre-commit
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
|
||||
4
.github/workflows/test-redistribute.yml
vendored
4
.github/workflows/test-redistribute.yml
vendored
@@ -5,10 +5,6 @@ on:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
|
||||
5
.github/workflows/test.yml
vendored
5
.github/workflows/test.yml
vendored
@@ -5,9 +5,6 @@ on:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
schedule:
|
||||
# cron every week on monday
|
||||
- cron: "0 0 * * 1"
|
||||
@@ -194,7 +191,7 @@ jobs:
|
||||
- name: Install Dependencies
|
||||
run: uv sync --no-dev --group tests --extra all
|
||||
- name: CodSpeed benchmarks
|
||||
uses: CodSpeedHQ/action@c145068895e045cc725ee76fcd2307624b65c3af # v4.17.5
|
||||
uses: CodSpeedHQ/action@9d332c4d90b43981c3e55ae8e38e68709996240f # v4.17.0
|
||||
with:
|
||||
mode: simulation
|
||||
run: uv run --no-sync pytest tests/benchmarks --codspeed
|
||||
|
||||
@@ -53,3 +53,6 @@ bronze:
|
||||
# - url: https://testdriven.io/courses/tdd-fastapi/
|
||||
# title: Learn to build high-quality web apps with best practices
|
||||
# img: /img/sponsors/testdriven.svg
|
||||
- url: https://www.testmu.ai/?utm_source=fastapi&utm_medium=partner&utm_campaign=sponsor&utm_term=opensource&utm_content=webpage
|
||||
title: TestMu AI. The Native AI-Agentic Cloud Platform to Supercharge Quality Engineering.
|
||||
img: /img/sponsors/testmu.png
|
||||
|
||||
@@ -249,6 +249,16 @@ They are supporting my work with **FastAPI** (and others), mainly through [GitHu
|
||||
<a href="{{ sponsor.url }}" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if sponsors.bronze %}
|
||||
|
||||
### Bronze Sponsors
|
||||
|
||||
{% for sponsor in sponsors.bronze -%}
|
||||
<a href="{{ sponsor.url }}" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
### Individual Sponsors
|
||||
|
||||
@@ -7,8 +7,18 @@ hide:
|
||||
|
||||
## Latest Changes
|
||||
|
||||
## 0.138.1 (2026-06-25)
|
||||
|
||||
### Refactors
|
||||
|
||||
* ♻️ Refactor Library Skills, make info easier to find for agents. PR [#15841](https://github.com/fastapi/fastapi/pull/15841) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Internal
|
||||
|
||||
* 👷 Simplify pull request workflow triggers. PR [#15836](https://github.com/fastapi/fastapi/pull/15836) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👷 Update issue-manager to 0.7.1. PR [#15833](https://github.com/fastapi/fastapi/pull/15833) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ⬆️ Update issue-manager to 0.7.0. PR [#15831](https://github.com/fastapi/fastapi/pull/15831) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update sponsors: Add TestMu again. PR [#15830](https://github.com/fastapi/fastapi/pull/15830) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔒️ Update zizmor workflow security checks. PR [#15820](https://github.com/fastapi/fastapi/pull/15820) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ⬆ Bump pydantic-settings from 2.14.1 to 2.14.2. PR [#15799](https://github.com/fastapi/fastapi/pull/15799) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
---
|
||||
name: fastapi
|
||||
description: FastAPI best practices and conventions. Use when working with FastAPI APIs and Pydantic models for them. Keeps FastAPI code clean and up to date with the latest features and patterns, updated with new versions. Write new code or refactor and update old code.
|
||||
description: FastAPI best practices and conventions. Use when working with FastAPI APIs, Pydantic models, dependencies, streaming responses including Server-Sent Events (SSE), and serving frontend apps. Keeps FastAPI code clean and up to date with the latest features and patterns.
|
||||
---
|
||||
|
||||
# FastAPI
|
||||
|
||||
Official FastAPI skill to write code with best practices, keeping up to date with new versions and features.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
* Serve frontend apps: use `app.frontend()` or `router.frontend()` for built frontend assets; see [Serve Frontend Apps](#serve-frontend-apps).
|
||||
* Server-Sent Events (SSE): use `response_class=EventSourceResponse` and `yield`; see [Streaming](#streaming-json-lines-sse-bytes) and [the streaming reference](references/streaming.md).
|
||||
* JSON Lines and byte streaming: see [the streaming reference](references/streaming.md).
|
||||
* Dependencies: use `Annotated[..., Depends(...)]`; see [Dependency Injection](#dependency-injection) and [the dependency injection reference](references/dependencies.md) for `yield`, scopes, and class dependencies.
|
||||
* Response models: prefer return types; use `response_model` when the public response schema differs from the internal return value; see [the response reference](references/responses.md).
|
||||
* Pydantic models: do not use ellipsis or `RootModel`; see [the Pydantic reference](references/pydantic.md).
|
||||
* Routing: declare router-level prefix, tags, and shared dependencies on the `APIRouter`; see [the path operation reference](references/path-operations.md).
|
||||
* Tooling and related libraries: use uv, Ruff, ty, Asyncer, SQLModel, and HTTPX when applicable; see [the other tools reference](references/other-tools.md).
|
||||
|
||||
## Use the `fastapi` CLI
|
||||
|
||||
Run the development server on localhost with reload:
|
||||
@@ -15,39 +26,28 @@ Run the development server on localhost with reload:
|
||||
fastapi dev
|
||||
```
|
||||
|
||||
|
||||
Run the production server:
|
||||
|
||||
```bash
|
||||
fastapi run
|
||||
```
|
||||
|
||||
### Add an entrypoint in `pyproject.toml`
|
||||
|
||||
FastAPI CLI will read the entrypoint in `pyproject.toml` to know where the FastAPI app is declared.
|
||||
Prefer declaring the entrypoint in `pyproject.toml`:
|
||||
|
||||
```toml
|
||||
[tool.fastapi]
|
||||
entrypoint = "my_app.main:app"
|
||||
```
|
||||
|
||||
### Use `fastapi` with a path
|
||||
|
||||
When 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:
|
||||
When adding the entrypoint is not possible, or the user explicitly asks not to, pass the app file path:
|
||||
|
||||
```bash
|
||||
fastapi dev my_app/main.py
|
||||
```
|
||||
|
||||
Prefer to set the entrypoint in `pyproject.toml` when possible.
|
||||
|
||||
## Use `Annotated`
|
||||
|
||||
Always prefer the `Annotated` style for parameter and dependency declarations.
|
||||
|
||||
It keeps the function signatures working in other contexts, respects the types, allows reusability.
|
||||
|
||||
### In Parameter Declarations
|
||||
Always prefer the `Annotated` style for parameter and dependency declarations. It keeps function signatures working in other contexts, respects the types, and allows reusability.
|
||||
|
||||
Use `Annotated` for parameter declarations, including `Path`, `Query`, `Header`, etc.:
|
||||
|
||||
@@ -67,23 +67,7 @@ async def read_item(
|
||||
return {"message": "Hello World"}
|
||||
```
|
||||
|
||||
instead of:
|
||||
|
||||
```python
|
||||
# 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"}
|
||||
```
|
||||
|
||||
### For Dependencies
|
||||
|
||||
Use `Annotated` for dependencies with `Depends()`.
|
||||
|
||||
Unless asked not to, create a new type alias for the dependency to allow re-using it.
|
||||
Use `Annotated` for dependencies with `Depends()`. Unless asked not to, create a new type alias for the dependency to allow reusing it:
|
||||
|
||||
```python
|
||||
from typing import Annotated
|
||||
@@ -105,20 +89,9 @@ async def read_item(current_user: CurrentUserDep):
|
||||
return {"message": "Hello World"}
|
||||
```
|
||||
|
||||
instead of:
|
||||
|
||||
```python
|
||||
# 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 Ellipsis for *path operations* or Pydantic models
|
||||
|
||||
Do not use `...` as a default value for required parameters, it's not needed and not recommended.
|
||||
|
||||
Do this, without Ellipsis (`...`):
|
||||
Do not use `...` as a default value for required parameters or model fields. It's not needed and not recommended.
|
||||
|
||||
```python
|
||||
from typing import Annotated
|
||||
@@ -126,6 +99,8 @@ from typing import Annotated
|
||||
from fastapi import FastAPI, Query
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
@@ -133,29 +108,12 @@ class Item(BaseModel):
|
||||
price: float = Field(gt=0)
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.post("/items/")
|
||||
async def create_item(item: Item, project_id: Annotated[int, Query()]): ...
|
||||
async def create_item(item: Item, project_id: Annotated[int, Query()]):
|
||||
return item
|
||||
```
|
||||
|
||||
instead of this:
|
||||
|
||||
```python
|
||||
# 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(...)]): ...
|
||||
```
|
||||
See [the Pydantic reference](references/pydantic.md) for more details.
|
||||
|
||||
## Return Type or Response Model
|
||||
|
||||
@@ -178,62 +136,9 @@ 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.
|
||||
Return types or response models filter data to avoid exposing sensitive information, and they let Pydantic serialize the data on the Rust side for 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.
|
||||
|
||||
### When to use `response_model` instead
|
||||
|
||||
If 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.
|
||||
|
||||
```python
|
||||
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.
|
||||
|
||||
```python
|
||||
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
|
||||
```
|
||||
Use `response_model` when the type you return is not the same as the public schema you want to validate, filter, document, and serialize. See [the response reference](references/responses.md).
|
||||
|
||||
## Performance
|
||||
|
||||
@@ -243,16 +148,23 @@ Instead, declare a return type or response model. Pydantic will handle the data
|
||||
|
||||
## Including Routers
|
||||
|
||||
When declaring routers, prefer to add router level parameters like prefix, tags, etc. to the router itself, instead of in `include_router()`.
|
||||
|
||||
Do this:
|
||||
When declaring routers, prefer to add router-level parameters like prefix, tags, and shared dependencies to the router itself instead of in `include_router()`.
|
||||
|
||||
```python
|
||||
from fastapi import APIRouter, FastAPI
|
||||
from fastapi import APIRouter, Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
router = APIRouter(prefix="/items", tags=["items"])
|
||||
|
||||
def get_current_user():
|
||||
return {"username": "johndoe"}
|
||||
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/items",
|
||||
tags=["items"],
|
||||
dependencies=[Depends(get_current_user)],
|
||||
)
|
||||
|
||||
|
||||
@router.get("/")
|
||||
@@ -260,33 +172,10 @@ async def list_items():
|
||||
return []
|
||||
|
||||
|
||||
# In main.py
|
||||
app.include_router(router)
|
||||
```
|
||||
|
||||
instead of this:
|
||||
|
||||
```python
|
||||
# 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 path operation reference](references/path-operations.md) for more routing patterns.
|
||||
|
||||
## Serve Frontend Apps
|
||||
|
||||
@@ -316,15 +205,15 @@ app.include_router(router)
|
||||
|
||||
## Dependency Injection
|
||||
|
||||
See [the dependency injection reference](references/dependencies.md) 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.
|
||||
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(...)]`.
|
||||
|
||||
See [the dependency injection reference](references/dependencies.md) for detailed patterns including `yield` with `scope`, and class dependencies.
|
||||
|
||||
## Async vs Sync *path operations*
|
||||
|
||||
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 it doesn't block.
|
||||
Use `async` *path operations* only when fully certain that the logic called inside is compatible with async and await, and that it doesn't block.
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
@@ -332,30 +221,44 @@ 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.
|
||||
In case of doubt, or by default, use regular `def` functions. They will be run in a threadpool so they don't block the event loop. The same rules apply to dependencies.
|
||||
|
||||
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.
|
||||
Make sure blocking code is not run inside of `async` functions. The logic will work, but will damage performance heavily.
|
||||
|
||||
When needing to mix blocking and async code, see Asyncer in [the other tools reference](references/other-tools.md).
|
||||
|
||||
## Streaming (JSON Lines, SSE, bytes)
|
||||
|
||||
To stream Server-Sent Events, use `response_class=EventSourceResponse` and `yield` items from the endpoint.
|
||||
|
||||
```python
|
||||
from collections.abc import AsyncIterable
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.sse import EventSourceResponse, ServerSentEvent
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/events", response_class=EventSourceResponse)
|
||||
async def stream_events() -> AsyncIterable[ServerSentEvent]:
|
||||
yield ServerSentEvent(data={"status": "started"}, event="status", id="1")
|
||||
```
|
||||
|
||||
Plain objects are automatically JSON-serialized as `data:` fields. Use `ServerSentEvent` for full control over SSE fields (`event`, `id`, `retry`, `comment`) and `raw_data` for pre-formatted strings.
|
||||
|
||||
See [the streaming reference](references/streaming.md) for JSON Lines, Server-Sent Events (`EventSourceResponse`, `ServerSentEvent`), and byte streaming (`StreamingResponse`) patterns.
|
||||
|
||||
## Tooling
|
||||
@@ -372,9 +275,7 @@ See [the other tools reference](references/other-tools.md) for details on other
|
||||
|
||||
## Do not use Pydantic RootModels
|
||||
|
||||
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:
|
||||
Do not use Pydantic `RootModel`; instead use regular type annotations with `Annotated` and Pydantic validation utilities.
|
||||
|
||||
```python
|
||||
from typing import Annotated
|
||||
@@ -390,35 +291,11 @@ async def create_items(items: Annotated[list[int], Field(min_length=1), Body()])
|
||||
return items
|
||||
```
|
||||
|
||||
instead of:
|
||||
|
||||
```python
|
||||
# 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.
|
||||
FastAPI supports these type annotations and will create a Pydantic `TypeAdapter` for them, so types work normally without custom wrapper models. See [the Pydantic reference](references/pydantic.md).
|
||||
|
||||
## Use one HTTP operation per function
|
||||
|
||||
Don't mix HTTP operations in a single function, having one function per HTTP operation helps separate concerns and organize the code.
|
||||
|
||||
Do this:
|
||||
Don't mix HTTP operations in a single function. Having one function per HTTP operation helps separate concerns and organize the code.
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
@@ -441,22 +318,4 @@ async def create_item(item: Item):
|
||||
return item
|
||||
```
|
||||
|
||||
instead of this:
|
||||
|
||||
```python
|
||||
# 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 []
|
||||
```
|
||||
See [the path operation reference](references/path-operations.md) for more examples.
|
||||
|
||||
93
fastapi/.agents/skills/fastapi/references/path-operations.md
Normal file
93
fastapi/.agents/skills/fastapi/references/path-operations.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# Path Operations and Routing
|
||||
|
||||
## Including Routers
|
||||
|
||||
When declaring routers, prefer to add router-level parameters like prefix, tags, and shared dependencies to the router itself instead of in `include_router()`.
|
||||
|
||||
Do this:
|
||||
|
||||
```python
|
||||
from fastapi import APIRouter, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
router = APIRouter(prefix="/items", tags=["items"])
|
||||
|
||||
|
||||
@router.get("/")
|
||||
async def list_items():
|
||||
return []
|
||||
|
||||
|
||||
app.include_router(router)
|
||||
```
|
||||
|
||||
Instead of:
|
||||
|
||||
```python
|
||||
# DO NOT DO THIS
|
||||
from fastapi import APIRouter, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/")
|
||||
async def list_items():
|
||||
return []
|
||||
|
||||
|
||||
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(...)]`.
|
||||
|
||||
## Use one HTTP operation per function
|
||||
|
||||
Don't mix HTTP operations in a single function. Having one function per HTTP operation helps separate concerns and organize the code.
|
||||
|
||||
Do this:
|
||||
|
||||
```python
|
||||
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:
|
||||
|
||||
```python
|
||||
# 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 []
|
||||
```
|
||||
93
fastapi/.agents/skills/fastapi/references/pydantic.md
Normal file
93
fastapi/.agents/skills/fastapi/references/pydantic.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# Pydantic
|
||||
|
||||
## Do not use Ellipsis
|
||||
|
||||
Do not use `...` as a default value for required parameters or model fields. It's not needed and not recommended.
|
||||
|
||||
Do this, without Ellipsis (`...`):
|
||||
|
||||
```python
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import FastAPI, Query
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str | None = None
|
||||
price: float = Field(gt=0)
|
||||
|
||||
|
||||
@app.post("/items/")
|
||||
async def create_item(item: Item, project_id: Annotated[int, Query()]):
|
||||
return item
|
||||
```
|
||||
|
||||
Instead of:
|
||||
|
||||
```python
|
||||
# DO NOT DO THIS
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import FastAPI, Query
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str = ...
|
||||
description: str | None = None
|
||||
price: float = Field(..., gt=0)
|
||||
|
||||
|
||||
@app.post("/items/")
|
||||
async def create_item(item: Item, project_id: Annotated[int, Query(...)]):
|
||||
return item
|
||||
```
|
||||
|
||||
## Do not use Pydantic RootModels
|
||||
|
||||
Do not use Pydantic `RootModel`; instead use regular type annotations with `Annotated` and Pydantic validation utilities.
|
||||
|
||||
For example, for a list with validations:
|
||||
|
||||
```python
|
||||
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:
|
||||
|
||||
```python
|
||||
# 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 types work normally without custom wrapper models.
|
||||
79
fastapi/.agents/skills/fastapi/references/responses.md
Normal file
79
fastapi/.agents/skills/fastapi/references/responses.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# Responses
|
||||
|
||||
## Return Type or Response Model
|
||||
|
||||
When possible, include a return type. It will be used to validate, filter, document, and serialize the response.
|
||||
|
||||
```python
|
||||
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")
|
||||
```
|
||||
|
||||
Return types or response models filter data to avoid exposing sensitive information. They also let Pydantic serialize data on the Rust side for performance.
|
||||
|
||||
The return type doesn't have to be a Pydantic model. It can be a different type, like a list of integers, a dict, etc.
|
||||
|
||||
## When to use `response_model`
|
||||
|
||||
If 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.
|
||||
|
||||
```python
|
||||
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 is particularly useful when filtering data to expose only the public fields and avoid exposing sensitive information.
|
||||
|
||||
```python
|
||||
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
|
||||
```
|
||||
@@ -1,6 +1,6 @@
|
||||
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
|
||||
|
||||
__version__ = "0.138.0"
|
||||
__version__ = "0.138.1"
|
||||
|
||||
from starlette import status as status
|
||||
|
||||
|
||||
Reference in New Issue
Block a user