mirror of
https://github.com/fastapi/fastapi.git
synced 2026-02-06 12:21:13 -05:00
Compare commits
4 Commits
update-out
...
additional
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
841c5c3189 | ||
|
|
fa7a5d38a7 | ||
|
|
cf7d4fe7b7 | ||
|
|
02d8c6e258 |
32
.github/workflows/test.yml
vendored
32
.github/workflows/test.yml
vendored
@@ -16,35 +16,7 @@ env:
|
||||
UV_NO_SYNC: true
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-latest
|
||||
# Required permissions
|
||||
permissions:
|
||||
pull-requests: read
|
||||
# Set job outputs to values from filter step
|
||||
outputs:
|
||||
src: ${{ steps.filter.outputs.src }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
# For pull requests it's not necessary to checkout the code but for the main branch it is
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
src:
|
||||
- .github/workflows/test.yml
|
||||
- docs_src/**
|
||||
- fastapi/**
|
||||
- scripts/**
|
||||
- tests/**
|
||||
- .python-version
|
||||
- pyproject.toml
|
||||
- uv.lock
|
||||
|
||||
test:
|
||||
needs:
|
||||
- changes
|
||||
if: needs.changes.outputs.src == 'true'
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ windows-latest, macos-latest ]
|
||||
@@ -119,8 +91,7 @@ jobs:
|
||||
include-hidden-files: true
|
||||
|
||||
coverage-combine:
|
||||
needs:
|
||||
- test
|
||||
needs: [test]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Dump GitHub context
|
||||
@@ -172,4 +143,3 @@ jobs:
|
||||
uses: re-actors/alls-green@release/v1
|
||||
with:
|
||||
jobs: ${{ toJSON(needs) }}
|
||||
allowed-skips: coverage-combine,test
|
||||
|
||||
@@ -30,13 +30,6 @@ repos:
|
||||
language: unsupported
|
||||
types: [python]
|
||||
|
||||
- id: local-mypy
|
||||
name: mypy check
|
||||
entry: uv run mypy fastapi
|
||||
require_serial: true
|
||||
language: unsupported
|
||||
pass_filenames: false
|
||||
|
||||
- id: add-permalinks-pages
|
||||
language: unsupported
|
||||
name: add-permalinks-pages
|
||||
|
||||
18
README.md
18
README.md
@@ -164,6 +164,8 @@ $ pip install "fastapi[standard]"
|
||||
Create a file `main.py` with:
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -175,7 +177,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -184,7 +186,9 @@ def read_item(item_id: int, q: str | None = None):
|
||||
|
||||
If your code uses `async` / `await`, use `async def`:
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -196,7 +200,7 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: str | None = None):
|
||||
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -287,7 +291,9 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
|
||||
|
||||
Declare the body using standard Python types, thanks to Pydantic.
|
||||
|
||||
```Python hl_lines="2 7-10 23-25"
|
||||
```Python hl_lines="4 9-12 25-27"
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -297,7 +303,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: bool | None = None
|
||||
is_offer: Union[bool, None] = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -306,7 +312,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
|
||||
@@ -6,29 +6,13 @@ Dazu können Sie die `WSGIMiddleware` verwenden und damit Ihre WSGI-Anwendung wr
|
||||
|
||||
## `WSGIMiddleware` verwenden { #using-wsgimiddleware }
|
||||
|
||||
/// info | Info
|
||||
|
||||
Dafür muss `a2wsgi` installiert sein, z. B. mit `pip install a2wsgi`.
|
||||
|
||||
///
|
||||
|
||||
Sie müssen `WSGIMiddleware` aus `a2wsgi` importieren.
|
||||
Sie müssen `WSGIMiddleware` importieren.
|
||||
|
||||
Wrappen Sie dann die WSGI-Anwendung (z. B. Flask) mit der Middleware.
|
||||
|
||||
Und dann mounten Sie das auf einem Pfad.
|
||||
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[1,3,23] *}
|
||||
|
||||
/// note | Hinweis
|
||||
|
||||
Früher wurde empfohlen, `WSGIMiddleware` aus `fastapi.middleware.wsgi` zu verwenden, dies ist jetzt deprecatet.
|
||||
|
||||
Stattdessen wird empfohlen, das Paket `a2wsgi` zu verwenden. Die Nutzung bleibt gleich.
|
||||
|
||||
Stellen Sie lediglich sicher, dass das Paket `a2wsgi` installiert ist und importieren Sie `WSGIMiddleware` korrekt aus `a2wsgi`.
|
||||
|
||||
///
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[2:3,3] *}
|
||||
|
||||
## Es testen { #check-it }
|
||||
|
||||
|
||||
@@ -145,6 +145,8 @@ Es gibt andere Formate und Tools zum Definieren und Installieren von Paketabhän
|
||||
* Erstellen Sie eine `main.py`-Datei mit:
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -156,7 +158,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
|
||||
@@ -161,6 +161,8 @@ $ pip install "fastapi[standard]"
|
||||
Erstellen Sie eine Datei `main.py` mit:
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -172,7 +174,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -181,7 +183,9 @@ def read_item(item_id: int, q: str | None = None):
|
||||
|
||||
Wenn Ihr Code `async` / `await` verwendet, benutzen Sie `async def`:
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -193,7 +197,7 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: str | None = None):
|
||||
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -284,7 +288,9 @@ Sie sehen die alternative automatische Dokumentation (bereitgestellt von <a href
|
||||
|
||||
Deklarieren Sie den Body mit Standard-Python-Typen, dank Pydantic.
|
||||
|
||||
```Python hl_lines="2 7-10 23-25"
|
||||
```Python hl_lines="4 9-12 25-27"
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -294,7 +300,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: bool | None = None
|
||||
is_offer: Union[bool, None] = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -303,7 +309,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Body – Mehrere Parameter { #body-multiple-parameters }
|
||||
|
||||
Nun, da wir gesehen haben, wie `Path` und `Query` verwendet werden, schauen wir uns fortgeschrittenere Verwendungsmöglichkeiten von <abbr title="Requestbody">Requestbody</abbr>-Deklarationen an.
|
||||
Nun, da wir gesehen haben, wie `Path` und `Query` verwendet werden, schauen wir uns fortgeschrittenere Verwendungsmöglichkeiten von <abbr title="Anfragekörper">Requestbody</abbr>-Deklarationen an.
|
||||
|
||||
## `Path`-, `Query`- und Body-Parameter vermischen { #mix-path-query-and-body-parameters }
|
||||
|
||||
@@ -101,13 +101,13 @@ Natürlich können Sie auch, wann immer Sie das brauchen, weitere Query-Paramete
|
||||
Da einfache Werte standardmäßig als Query-Parameter interpretiert werden, müssen Sie `Query` nicht explizit hinzufügen, Sie können einfach schreiben:
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
Oder in Python 3.9:
|
||||
Oder in Python 3.10 und darüber:
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
Zum Beispiel:
|
||||
|
||||
@@ -52,7 +52,7 @@ In diesem Fall macht es Sinn, die Tags in einem `Enum` zu speichern.
|
||||
|
||||
Sie können eine <abbr title="Zusammenfassung">`summary`</abbr> und eine <abbr title="Beschreibung">`description`</abbr> hinzufügen:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[18:19] *}
|
||||
|
||||
## Beschreibung mittels Docstring { #description-from-docstring }
|
||||
|
||||
@@ -70,7 +70,7 @@ Es wird in der interaktiven Dokumentation verwendet:
|
||||
|
||||
Sie können die Response mit dem Parameter `response_description` beschreiben:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[19] *}
|
||||
|
||||
/// info | Info
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
tiangolo:
|
||||
login: tiangolo
|
||||
count: 871
|
||||
count: 857
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4
|
||||
url: https://github.com/tiangolo
|
||||
dependabot:
|
||||
login: dependabot
|
||||
count: 133
|
||||
count: 130
|
||||
avatarUrl: https://avatars.githubusercontent.com/in/29110?v=4
|
||||
url: https://github.com/apps/dependabot
|
||||
alejsdev:
|
||||
login: alejsdev
|
||||
count: 53
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/90076947?u=0facffe3abf87f57a1f05fa773d1119cc5c2f6a5&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/90076947?u=85ceac49fb87138aebe8d663912e359447329090&v=4
|
||||
url: https://github.com/alejsdev
|
||||
pre-commit-ci:
|
||||
login: pre-commit-ci
|
||||
@@ -20,8 +20,8 @@ pre-commit-ci:
|
||||
url: https://github.com/apps/pre-commit-ci
|
||||
YuriiMotov:
|
||||
login: YuriiMotov
|
||||
count: 38
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=bc48be95c429989224786106b027f3c5e40cc354&v=4
|
||||
count: 36
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=b9b13d598dddfab529a52d264df80a900bfe7060&v=4
|
||||
url: https://github.com/YuriiMotov
|
||||
github-actions:
|
||||
login: github-actions
|
||||
@@ -40,7 +40,7 @@ dmontagu:
|
||||
url: https://github.com/dmontagu
|
||||
svlandeg:
|
||||
login: svlandeg
|
||||
count: 17
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8796347?u=556c97650c27021911b0b9447ec55e75987b0e8a&v=4
|
||||
url: https://github.com/svlandeg
|
||||
nilslindemann:
|
||||
@@ -126,7 +126,7 @@ hitrust:
|
||||
ShahriyarR:
|
||||
login: ShahriyarR
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3852029?u=2dc6402d9053ee53f7afc407089cbab21c68f21d&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3852029?u=631b2ae59360ab380c524b32bc3d245aff1165af&v=4
|
||||
url: https://github.com/ShahriyarR
|
||||
adriangb:
|
||||
login: adriangb
|
||||
@@ -266,7 +266,7 @@ Nimitha-jagadeesha:
|
||||
lucaromagnoli:
|
||||
login: lucaromagnoli
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/38782977?u=a09a2e916625fa035f9dfa25ebc58e07aac8ec36&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/38782977?u=15df02e806a2293af40ac619fba11dbe3c0c4fd4&v=4
|
||||
url: https://github.com/lucaromagnoli
|
||||
salmantec:
|
||||
login: salmantec
|
||||
@@ -521,7 +521,7 @@ s111d:
|
||||
estebanx64:
|
||||
login: estebanx64
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10840422?u=812422ae5d6a4bc5ff331c901fc54f9ab3cecf5c&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10840422?u=1900887aeed268699e5ea6f3fb7db614f7b77cd3&v=4
|
||||
url: https://github.com/estebanx64
|
||||
ndimares:
|
||||
login: ndimares
|
||||
|
||||
@@ -1,181 +1,176 @@
|
||||
- name: full-stack-fastapi-template
|
||||
html_url: https://github.com/fastapi/full-stack-fastapi-template
|
||||
stars: 41312
|
||||
stars: 40334
|
||||
owner_login: fastapi
|
||||
owner_html_url: https://github.com/fastapi
|
||||
- name: Hello-Python
|
||||
html_url: https://github.com/mouredev/Hello-Python
|
||||
stars: 34206
|
||||
stars: 33628
|
||||
owner_login: mouredev
|
||||
owner_html_url: https://github.com/mouredev
|
||||
- name: serve
|
||||
html_url: https://github.com/jina-ai/serve
|
||||
stars: 21832
|
||||
stars: 21817
|
||||
owner_login: jina-ai
|
||||
owner_html_url: https://github.com/jina-ai
|
||||
- name: HivisionIDPhotos
|
||||
html_url: https://github.com/Zeyi-Lin/HivisionIDPhotos
|
||||
stars: 20661
|
||||
stars: 20409
|
||||
owner_login: Zeyi-Lin
|
||||
owner_html_url: https://github.com/Zeyi-Lin
|
||||
- name: sqlmodel
|
||||
html_url: https://github.com/fastapi/sqlmodel
|
||||
stars: 17567
|
||||
stars: 17415
|
||||
owner_login: fastapi
|
||||
owner_html_url: https://github.com/fastapi
|
||||
- name: fastapi-best-practices
|
||||
html_url: https://github.com/zhanymkanov/fastapi-best-practices
|
||||
stars: 16291
|
||||
stars: 15776
|
||||
owner_login: zhanymkanov
|
||||
owner_html_url: https://github.com/zhanymkanov
|
||||
- name: Douyin_TikTok_Download_API
|
||||
html_url: https://github.com/Evil0ctal/Douyin_TikTok_Download_API
|
||||
stars: 16132
|
||||
stars: 15588
|
||||
owner_login: Evil0ctal
|
||||
owner_html_url: https://github.com/Evil0ctal
|
||||
- name: SurfSense
|
||||
html_url: https://github.com/MODSetter/SurfSense
|
||||
stars: 12723
|
||||
owner_login: MODSetter
|
||||
owner_html_url: https://github.com/MODSetter
|
||||
- name: machine-learning-zoomcamp
|
||||
html_url: https://github.com/DataTalksClub/machine-learning-zoomcamp
|
||||
stars: 12575
|
||||
stars: 12447
|
||||
owner_login: DataTalksClub
|
||||
owner_html_url: https://github.com/DataTalksClub
|
||||
- name: SurfSense
|
||||
html_url: https://github.com/MODSetter/SurfSense
|
||||
stars: 12128
|
||||
owner_login: MODSetter
|
||||
owner_html_url: https://github.com/MODSetter
|
||||
- name: fastapi_mcp
|
||||
html_url: https://github.com/tadata-org/fastapi_mcp
|
||||
stars: 11478
|
||||
stars: 11326
|
||||
owner_login: tadata-org
|
||||
owner_html_url: https://github.com/tadata-org
|
||||
- name: awesome-fastapi
|
||||
html_url: https://github.com/mjhea0/awesome-fastapi
|
||||
stars: 11018
|
||||
stars: 10901
|
||||
owner_login: mjhea0
|
||||
owner_html_url: https://github.com/mjhea0
|
||||
- name: XHS-Downloader
|
||||
html_url: https://github.com/JoeanAmier/XHS-Downloader
|
||||
stars: 9938
|
||||
stars: 9584
|
||||
owner_login: JoeanAmier
|
||||
owner_html_url: https://github.com/JoeanAmier
|
||||
- name: polar
|
||||
html_url: https://github.com/polarsource/polar
|
||||
stars: 9348
|
||||
stars: 8951
|
||||
owner_login: polarsource
|
||||
owner_html_url: https://github.com/polarsource
|
||||
- name: FastUI
|
||||
html_url: https://github.com/pydantic/FastUI
|
||||
stars: 8949
|
||||
stars: 8934
|
||||
owner_login: pydantic
|
||||
owner_html_url: https://github.com/pydantic
|
||||
- name: FileCodeBox
|
||||
html_url: https://github.com/vastsa/FileCodeBox
|
||||
stars: 8060
|
||||
stars: 7934
|
||||
owner_login: vastsa
|
||||
owner_html_url: https://github.com/vastsa
|
||||
- name: nonebot2
|
||||
html_url: https://github.com/nonebot/nonebot2
|
||||
stars: 7311
|
||||
stars: 7248
|
||||
owner_login: nonebot
|
||||
owner_html_url: https://github.com/nonebot
|
||||
- name: hatchet
|
||||
html_url: https://github.com/hatchet-dev/hatchet
|
||||
stars: 6479
|
||||
stars: 6392
|
||||
owner_login: hatchet-dev
|
||||
owner_html_url: https://github.com/hatchet-dev
|
||||
- name: fastapi-users
|
||||
html_url: https://github.com/fastapi-users/fastapi-users
|
||||
stars: 5970
|
||||
stars: 5899
|
||||
owner_login: fastapi-users
|
||||
owner_html_url: https://github.com/fastapi-users
|
||||
- name: serge
|
||||
html_url: https://github.com/serge-chat/serge
|
||||
stars: 5751
|
||||
stars: 5754
|
||||
owner_login: serge-chat
|
||||
owner_html_url: https://github.com/serge-chat
|
||||
- name: strawberry
|
||||
html_url: https://github.com/strawberry-graphql/strawberry
|
||||
stars: 4598
|
||||
stars: 4577
|
||||
owner_login: strawberry-graphql
|
||||
owner_html_url: https://github.com/strawberry-graphql
|
||||
- name: devpush
|
||||
html_url: https://github.com/hunvreus/devpush
|
||||
stars: 4407
|
||||
owner_login: hunvreus
|
||||
owner_html_url: https://github.com/hunvreus
|
||||
- name: Kokoro-FastAPI
|
||||
html_url: https://github.com/remsky/Kokoro-FastAPI
|
||||
stars: 4359
|
||||
owner_login: remsky
|
||||
owner_html_url: https://github.com/remsky
|
||||
- name: poem
|
||||
html_url: https://github.com/poem-web/poem
|
||||
stars: 4337
|
||||
stars: 4303
|
||||
owner_login: poem-web
|
||||
owner_html_url: https://github.com/poem-web
|
||||
- name: chatgpt-web-share
|
||||
html_url: https://github.com/chatpire/chatgpt-web-share
|
||||
stars: 4279
|
||||
stars: 4287
|
||||
owner_login: chatpire
|
||||
owner_html_url: https://github.com/chatpire
|
||||
- name: dynaconf
|
||||
html_url: https://github.com/dynaconf/dynaconf
|
||||
stars: 4244
|
||||
stars: 4221
|
||||
owner_login: dynaconf
|
||||
owner_html_url: https://github.com/dynaconf
|
||||
- name: Yuxi-Know
|
||||
html_url: https://github.com/xerrors/Yuxi-Know
|
||||
stars: 4154
|
||||
owner_login: xerrors
|
||||
owner_html_url: https://github.com/xerrors
|
||||
- name: Kokoro-FastAPI
|
||||
html_url: https://github.com/remsky/Kokoro-FastAPI
|
||||
stars: 4181
|
||||
owner_login: remsky
|
||||
owner_html_url: https://github.com/remsky
|
||||
- name: atrilabs-engine
|
||||
html_url: https://github.com/Atri-Labs/atrilabs-engine
|
||||
stars: 4086
|
||||
stars: 4090
|
||||
owner_login: Atri-Labs
|
||||
owner_html_url: https://github.com/Atri-Labs
|
||||
- name: devpush
|
||||
html_url: https://github.com/hunvreus/devpush
|
||||
stars: 4037
|
||||
owner_login: hunvreus
|
||||
owner_html_url: https://github.com/hunvreus
|
||||
- name: logfire
|
||||
html_url: https://github.com/pydantic/logfire
|
||||
stars: 3975
|
||||
stars: 3896
|
||||
owner_login: pydantic
|
||||
owner_html_url: https://github.com/pydantic
|
||||
- name: LitServe
|
||||
html_url: https://github.com/Lightning-AI/LitServe
|
||||
stars: 3797
|
||||
stars: 3756
|
||||
owner_login: Lightning-AI
|
||||
owner_html_url: https://github.com/Lightning-AI
|
||||
- name: huma
|
||||
html_url: https://github.com/danielgtaylor/huma
|
||||
stars: 3785
|
||||
stars: 3702
|
||||
owner_login: danielgtaylor
|
||||
owner_html_url: https://github.com/danielgtaylor
|
||||
- name: Yuxi-Know
|
||||
html_url: https://github.com/xerrors/Yuxi-Know
|
||||
stars: 3680
|
||||
owner_login: xerrors
|
||||
owner_html_url: https://github.com/xerrors
|
||||
- name: datamodel-code-generator
|
||||
html_url: https://github.com/koxudaxi/datamodel-code-generator
|
||||
stars: 3731
|
||||
stars: 3675
|
||||
owner_login: koxudaxi
|
||||
owner_html_url: https://github.com/koxudaxi
|
||||
- name: fastapi-admin
|
||||
html_url: https://github.com/fastapi-admin/fastapi-admin
|
||||
stars: 3697
|
||||
stars: 3659
|
||||
owner_login: fastapi-admin
|
||||
owner_html_url: https://github.com/fastapi-admin
|
||||
- name: farfalle
|
||||
html_url: https://github.com/rashadphz/farfalle
|
||||
stars: 3506
|
||||
stars: 3497
|
||||
owner_login: rashadphz
|
||||
owner_html_url: https://github.com/rashadphz
|
||||
- name: tracecat
|
||||
html_url: https://github.com/TracecatHQ/tracecat
|
||||
stars: 3458
|
||||
stars: 3421
|
||||
owner_login: TracecatHQ
|
||||
owner_html_url: https://github.com/TracecatHQ
|
||||
- name: mcp-context-forge
|
||||
html_url: https://github.com/IBM/mcp-context-forge
|
||||
stars: 3216
|
||||
owner_login: IBM
|
||||
owner_html_url: https://github.com/IBM
|
||||
- name: opyrator
|
||||
html_url: https://github.com/ml-tooling/opyrator
|
||||
stars: 3134
|
||||
stars: 3136
|
||||
owner_login: ml-tooling
|
||||
owner_html_url: https://github.com/ml-tooling
|
||||
- name: docarray
|
||||
@@ -185,311 +180,316 @@
|
||||
owner_html_url: https://github.com/docarray
|
||||
- name: fastapi-realworld-example-app
|
||||
html_url: https://github.com/nsidnev/fastapi-realworld-example-app
|
||||
stars: 3072
|
||||
stars: 3051
|
||||
owner_login: nsidnev
|
||||
owner_html_url: https://github.com/nsidnev
|
||||
- name: mcp-context-forge
|
||||
html_url: https://github.com/IBM/mcp-context-forge
|
||||
stars: 3034
|
||||
owner_login: IBM
|
||||
owner_html_url: https://github.com/IBM
|
||||
- name: uvicorn-gunicorn-fastapi-docker
|
||||
html_url: https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker
|
||||
stars: 2908
|
||||
stars: 2904
|
||||
owner_login: tiangolo
|
||||
owner_html_url: https://github.com/tiangolo
|
||||
- name: FastAPI-template
|
||||
html_url: https://github.com/s3rius/FastAPI-template
|
||||
stars: 2728
|
||||
stars: 2680
|
||||
owner_login: s3rius
|
||||
owner_html_url: https://github.com/s3rius
|
||||
- name: best-of-web-python
|
||||
html_url: https://github.com/ml-tooling/best-of-web-python
|
||||
stars: 2686
|
||||
stars: 2662
|
||||
owner_login: ml-tooling
|
||||
owner_html_url: https://github.com/ml-tooling
|
||||
- name: YC-Killer
|
||||
html_url: https://github.com/sahibzada-allahyar/YC-Killer
|
||||
stars: 2648
|
||||
stars: 2614
|
||||
owner_login: sahibzada-allahyar
|
||||
owner_html_url: https://github.com/sahibzada-allahyar
|
||||
- name: sqladmin
|
||||
html_url: https://github.com/aminalaee/sqladmin
|
||||
stars: 2637
|
||||
stars: 2587
|
||||
owner_login: aminalaee
|
||||
owner_html_url: https://github.com/aminalaee
|
||||
- name: fastapi-react
|
||||
html_url: https://github.com/Buuntu/fastapi-react
|
||||
stars: 2573
|
||||
stars: 2566
|
||||
owner_login: Buuntu
|
||||
owner_html_url: https://github.com/Buuntu
|
||||
- name: RasaGPT
|
||||
html_url: https://github.com/paulpierre/RasaGPT
|
||||
stars: 2460
|
||||
stars: 2456
|
||||
owner_login: paulpierre
|
||||
owner_html_url: https://github.com/paulpierre
|
||||
- name: supabase-py
|
||||
html_url: https://github.com/supabase/supabase-py
|
||||
stars: 2428
|
||||
stars: 2394
|
||||
owner_login: supabase
|
||||
owner_html_url: https://github.com/supabase
|
||||
- name: 30-Days-of-Python
|
||||
html_url: https://github.com/codingforentrepreneurs/30-Days-of-Python
|
||||
stars: 2347
|
||||
owner_login: codingforentrepreneurs
|
||||
owner_html_url: https://github.com/codingforentrepreneurs
|
||||
- name: nextpy
|
||||
html_url: https://github.com/dot-agent/nextpy
|
||||
stars: 2337
|
||||
stars: 2338
|
||||
owner_login: dot-agent
|
||||
owner_html_url: https://github.com/dot-agent
|
||||
- name: fastapi-utils
|
||||
html_url: https://github.com/fastapiutils/fastapi-utils
|
||||
stars: 2299
|
||||
stars: 2289
|
||||
owner_login: fastapiutils
|
||||
owner_html_url: https://github.com/fastapiutils
|
||||
- name: langserve
|
||||
html_url: https://github.com/langchain-ai/langserve
|
||||
stars: 2255
|
||||
stars: 2234
|
||||
owner_login: langchain-ai
|
||||
owner_html_url: https://github.com/langchain-ai
|
||||
- name: NoteDiscovery
|
||||
html_url: https://github.com/gamosoft/NoteDiscovery
|
||||
stars: 2182
|
||||
owner_login: gamosoft
|
||||
owner_html_url: https://github.com/gamosoft
|
||||
- name: 30-Days-of-Python
|
||||
html_url: https://github.com/codingforentrepreneurs/30-Days-of-Python
|
||||
stars: 2232
|
||||
owner_login: codingforentrepreneurs
|
||||
owner_html_url: https://github.com/codingforentrepreneurs
|
||||
- name: solara
|
||||
html_url: https://github.com/widgetti/solara
|
||||
stars: 2154
|
||||
stars: 2141
|
||||
owner_login: widgetti
|
||||
owner_html_url: https://github.com/widgetti
|
||||
- name: mangum
|
||||
html_url: https://github.com/Kludex/mangum
|
||||
stars: 2071
|
||||
stars: 2046
|
||||
owner_login: Kludex
|
||||
owner_html_url: https://github.com/Kludex
|
||||
- name: fastapi_best_architecture
|
||||
html_url: https://github.com/fastapi-practices/fastapi_best_architecture
|
||||
stars: 2036
|
||||
stars: 1963
|
||||
owner_login: fastapi-practices
|
||||
owner_html_url: https://github.com/fastapi-practices
|
||||
- name: vue-fastapi-admin
|
||||
html_url: https://github.com/mizhexiaoxiao/vue-fastapi-admin
|
||||
stars: 1983
|
||||
owner_login: mizhexiaoxiao
|
||||
owner_html_url: https://github.com/mizhexiaoxiao
|
||||
- name: NoteDiscovery
|
||||
html_url: https://github.com/gamosoft/NoteDiscovery
|
||||
stars: 1943
|
||||
owner_login: gamosoft
|
||||
owner_html_url: https://github.com/gamosoft
|
||||
- name: agentkit
|
||||
html_url: https://github.com/BCG-X-Official/agentkit
|
||||
stars: 1941
|
||||
stars: 1936
|
||||
owner_login: BCG-X-Official
|
||||
owner_html_url: https://github.com/BCG-X-Official
|
||||
- name: fastapi-langgraph-agent-production-ready-template
|
||||
html_url: https://github.com/wassim249/fastapi-langgraph-agent-production-ready-template
|
||||
stars: 1920
|
||||
owner_login: wassim249
|
||||
owner_html_url: https://github.com/wassim249
|
||||
- name: openapi-python-client
|
||||
html_url: https://github.com/openapi-generators/openapi-python-client
|
||||
stars: 1900
|
||||
owner_login: openapi-generators
|
||||
owner_html_url: https://github.com/openapi-generators
|
||||
- name: vue-fastapi-admin
|
||||
html_url: https://github.com/mizhexiaoxiao/vue-fastapi-admin
|
||||
stars: 1909
|
||||
owner_login: mizhexiaoxiao
|
||||
owner_html_url: https://github.com/mizhexiaoxiao
|
||||
- name: manage-fastapi
|
||||
html_url: https://github.com/ycd/manage-fastapi
|
||||
stars: 1894
|
||||
stars: 1887
|
||||
owner_login: ycd
|
||||
owner_html_url: https://github.com/ycd
|
||||
- name: openapi-python-client
|
||||
html_url: https://github.com/openapi-generators/openapi-python-client
|
||||
stars: 1879
|
||||
owner_login: openapi-generators
|
||||
owner_html_url: https://github.com/openapi-generators
|
||||
- name: slowapi
|
||||
html_url: https://github.com/laurentS/slowapi
|
||||
stars: 1891
|
||||
stars: 1845
|
||||
owner_login: laurentS
|
||||
owner_html_url: https://github.com/laurentS
|
||||
- name: piccolo
|
||||
html_url: https://github.com/piccolo-orm/piccolo
|
||||
stars: 1854
|
||||
stars: 1843
|
||||
owner_login: piccolo-orm
|
||||
owner_html_url: https://github.com/piccolo-orm
|
||||
- name: fastapi-cache
|
||||
html_url: https://github.com/long2ice/fastapi-cache
|
||||
stars: 1816
|
||||
owner_login: long2ice
|
||||
owner_html_url: https://github.com/long2ice
|
||||
- name: python-week-2022
|
||||
html_url: https://github.com/rochacbruno/python-week-2022
|
||||
stars: 1813
|
||||
owner_login: rochacbruno
|
||||
owner_html_url: https://github.com/rochacbruno
|
||||
- name: fastapi-cache
|
||||
html_url: https://github.com/long2ice/fastapi-cache
|
||||
stars: 1805
|
||||
owner_login: long2ice
|
||||
owner_html_url: https://github.com/long2ice
|
||||
- name: ormar
|
||||
html_url: https://github.com/collerek/ormar
|
||||
stars: 1797
|
||||
stars: 1785
|
||||
owner_login: collerek
|
||||
owner_html_url: https://github.com/collerek
|
||||
- name: fastapi-langgraph-agent-production-ready-template
|
||||
html_url: https://github.com/wassim249/fastapi-langgraph-agent-production-ready-template
|
||||
stars: 1780
|
||||
owner_login: wassim249
|
||||
owner_html_url: https://github.com/wassim249
|
||||
- name: FastAPI-boilerplate
|
||||
html_url: https://github.com/benavlabs/FastAPI-boilerplate
|
||||
stars: 1792
|
||||
stars: 1734
|
||||
owner_login: benavlabs
|
||||
owner_html_url: https://github.com/benavlabs
|
||||
- name: termpair
|
||||
html_url: https://github.com/cs01/termpair
|
||||
stars: 1727
|
||||
stars: 1724
|
||||
owner_login: cs01
|
||||
owner_html_url: https://github.com/cs01
|
||||
- name: fastapi-crudrouter
|
||||
html_url: https://github.com/awtkns/fastapi-crudrouter
|
||||
stars: 1677
|
||||
stars: 1671
|
||||
owner_login: awtkns
|
||||
owner_html_url: https://github.com/awtkns
|
||||
- name: langchain-serve
|
||||
html_url: https://github.com/jina-ai/langchain-serve
|
||||
stars: 1634
|
||||
stars: 1633
|
||||
owner_login: jina-ai
|
||||
owner_html_url: https://github.com/jina-ai
|
||||
- name: fastapi-pagination
|
||||
html_url: https://github.com/uriyyo/fastapi-pagination
|
||||
stars: 1607
|
||||
stars: 1588
|
||||
owner_login: uriyyo
|
||||
owner_html_url: https://github.com/uriyyo
|
||||
- name: awesome-fastapi-projects
|
||||
html_url: https://github.com/Kludex/awesome-fastapi-projects
|
||||
stars: 1592
|
||||
stars: 1583
|
||||
owner_login: Kludex
|
||||
owner_html_url: https://github.com/Kludex
|
||||
- name: bracket
|
||||
html_url: https://github.com/evroon/bracket
|
||||
stars: 1580
|
||||
owner_login: evroon
|
||||
owner_html_url: https://github.com/evroon
|
||||
- name: coronavirus-tracker-api
|
||||
html_url: https://github.com/ExpDev07/coronavirus-tracker-api
|
||||
stars: 1570
|
||||
stars: 1571
|
||||
owner_login: ExpDev07
|
||||
owner_html_url: https://github.com/ExpDev07
|
||||
- name: bracket
|
||||
html_url: https://github.com/evroon/bracket
|
||||
stars: 1549
|
||||
owner_login: evroon
|
||||
owner_html_url: https://github.com/evroon
|
||||
- name: fastapi-amis-admin
|
||||
html_url: https://github.com/amisadmin/fastapi-amis-admin
|
||||
stars: 1512
|
||||
stars: 1491
|
||||
owner_login: amisadmin
|
||||
owner_html_url: https://github.com/amisadmin
|
||||
- name: fastcrud
|
||||
html_url: https://github.com/benavlabs/fastcrud
|
||||
stars: 1471
|
||||
owner_login: benavlabs
|
||||
owner_html_url: https://github.com/benavlabs
|
||||
- name: fastapi-boilerplate
|
||||
html_url: https://github.com/teamhide/fastapi-boilerplate
|
||||
stars: 1461
|
||||
stars: 1452
|
||||
owner_login: teamhide
|
||||
owner_html_url: https://github.com/teamhide
|
||||
- name: fastcrud
|
||||
html_url: https://github.com/benavlabs/fastcrud
|
||||
stars: 1452
|
||||
owner_login: benavlabs
|
||||
owner_html_url: https://github.com/benavlabs
|
||||
- name: awesome-python-resources
|
||||
html_url: https://github.com/DjangoEx/awesome-python-resources
|
||||
stars: 1435
|
||||
stars: 1430
|
||||
owner_login: DjangoEx
|
||||
owner_html_url: https://github.com/DjangoEx
|
||||
- name: prometheus-fastapi-instrumentator
|
||||
html_url: https://github.com/trallnag/prometheus-fastapi-instrumentator
|
||||
stars: 1417
|
||||
stars: 1399
|
||||
owner_login: trallnag
|
||||
owner_html_url: https://github.com/trallnag
|
||||
- name: fastapi-code-generator
|
||||
html_url: https://github.com/koxudaxi/fastapi-code-generator
|
||||
stars: 1382
|
||||
stars: 1371
|
||||
owner_login: koxudaxi
|
||||
owner_html_url: https://github.com/koxudaxi
|
||||
- name: fastapi-scaff
|
||||
html_url: https://github.com/atpuxiner/fastapi-scaff
|
||||
stars: 1367
|
||||
owner_login: atpuxiner
|
||||
owner_html_url: https://github.com/atpuxiner
|
||||
- name: fastapi-tutorial
|
||||
html_url: https://github.com/liaogx/fastapi-tutorial
|
||||
stars: 1360
|
||||
stars: 1346
|
||||
owner_login: liaogx
|
||||
owner_html_url: https://github.com/liaogx
|
||||
- name: budgetml
|
||||
html_url: https://github.com/ebhy/budgetml
|
||||
stars: 1343
|
||||
stars: 1345
|
||||
owner_login: ebhy
|
||||
owner_html_url: https://github.com/ebhy
|
||||
- name: fastapi-scaff
|
||||
html_url: https://github.com/atpuxiner/fastapi-scaff
|
||||
stars: 1331
|
||||
owner_login: atpuxiner
|
||||
owner_html_url: https://github.com/atpuxiner
|
||||
- name: bolt-python
|
||||
html_url: https://github.com/slackapi/bolt-python
|
||||
stars: 1276
|
||||
stars: 1266
|
||||
owner_login: slackapi
|
||||
owner_html_url: https://github.com/slackapi
|
||||
- name: bedrock-chat
|
||||
html_url: https://github.com/aws-samples/bedrock-chat
|
||||
stars: 1268
|
||||
stars: 1266
|
||||
owner_login: aws-samples
|
||||
owner_html_url: https://github.com/aws-samples
|
||||
- name: fastapi-alembic-sqlmodel-async
|
||||
html_url: https://github.com/vargasjona/fastapi-alembic-sqlmodel-async
|
||||
stars: 1265
|
||||
owner_login: vargasjona
|
||||
owner_html_url: https://github.com/vargasjona
|
||||
html_url: https://github.com/jonra1993/fastapi-alembic-sqlmodel-async
|
||||
stars: 1260
|
||||
owner_login: jonra1993
|
||||
owner_html_url: https://github.com/jonra1993
|
||||
- name: fastapi_production_template
|
||||
html_url: https://github.com/zhanymkanov/fastapi_production_template
|
||||
stars: 1227
|
||||
stars: 1222
|
||||
owner_login: zhanymkanov
|
||||
owner_html_url: https://github.com/zhanymkanov
|
||||
- name: restish
|
||||
html_url: https://github.com/rest-sh/restish
|
||||
stars: 1200
|
||||
owner_login: rest-sh
|
||||
owner_html_url: https://github.com/rest-sh
|
||||
- name: langchain-extract
|
||||
html_url: https://github.com/langchain-ai/langchain-extract
|
||||
stars: 1183
|
||||
stars: 1179
|
||||
owner_login: langchain-ai
|
||||
owner_html_url: https://github.com/langchain-ai
|
||||
- name: restish
|
||||
html_url: https://github.com/rest-sh/restish
|
||||
stars: 1152
|
||||
owner_login: rest-sh
|
||||
owner_html_url: https://github.com/rest-sh
|
||||
- name: odmantic
|
||||
html_url: https://github.com/art049/odmantic
|
||||
stars: 1162
|
||||
stars: 1143
|
||||
owner_login: art049
|
||||
owner_html_url: https://github.com/art049
|
||||
- name: aktools
|
||||
html_url: https://github.com/akfamily/aktools
|
||||
stars: 1155
|
||||
owner_login: akfamily
|
||||
owner_html_url: https://github.com/akfamily
|
||||
- name: RuoYi-Vue3-FastAPI
|
||||
html_url: https://github.com/insistence/RuoYi-Vue3-FastAPI
|
||||
stars: 1155
|
||||
owner_login: insistence
|
||||
owner_html_url: https://github.com/insistence
|
||||
- name: authx
|
||||
html_url: https://github.com/yezz123/authx
|
||||
stars: 1142
|
||||
stars: 1128
|
||||
owner_login: yezz123
|
||||
owner_html_url: https://github.com/yezz123
|
||||
- name: SAG
|
||||
html_url: https://github.com/Zleap-AI/SAG
|
||||
stars: 1110
|
||||
stars: 1104
|
||||
owner_login: Zleap-AI
|
||||
owner_html_url: https://github.com/Zleap-AI
|
||||
- name: aktools
|
||||
html_url: https://github.com/akfamily/aktools
|
||||
stars: 1072
|
||||
owner_login: akfamily
|
||||
owner_html_url: https://github.com/akfamily
|
||||
- name: RuoYi-Vue3-FastAPI
|
||||
html_url: https://github.com/insistence/RuoYi-Vue3-FastAPI
|
||||
stars: 1063
|
||||
owner_login: insistence
|
||||
owner_html_url: https://github.com/insistence
|
||||
- name: flock
|
||||
html_url: https://github.com/Onelevenvy/flock
|
||||
stars: 1069
|
||||
stars: 1059
|
||||
owner_login: Onelevenvy
|
||||
owner_html_url: https://github.com/Onelevenvy
|
||||
- name: fastapi-observability
|
||||
html_url: https://github.com/blueswen/fastapi-observability
|
||||
stars: 1063
|
||||
stars: 1046
|
||||
owner_login: blueswen
|
||||
owner_html_url: https://github.com/blueswen
|
||||
- name: enterprise-deep-research
|
||||
html_url: https://github.com/SalesforceAIResearch/enterprise-deep-research
|
||||
stars: 1061
|
||||
stars: 1019
|
||||
owner_login: SalesforceAIResearch
|
||||
owner_html_url: https://github.com/SalesforceAIResearch
|
||||
- name: titiler
|
||||
html_url: https://github.com/developmentseed/titiler
|
||||
stars: 1039
|
||||
stars: 1016
|
||||
owner_login: developmentseed
|
||||
owner_html_url: https://github.com/developmentseed
|
||||
- name: every-pdf
|
||||
html_url: https://github.com/DDULDDUCK/every-pdf
|
||||
stars: 1017
|
||||
stars: 1004
|
||||
owner_login: DDULDDUCK
|
||||
owner_html_url: https://github.com/DDULDDUCK
|
||||
- name: autollm
|
||||
html_url: https://github.com/viddexa/autollm
|
||||
stars: 1005
|
||||
stars: 1003
|
||||
owner_login: viddexa
|
||||
owner_html_url: https://github.com/viddexa
|
||||
- name: lanarky
|
||||
html_url: https://github.com/ajndkr/lanarky
|
||||
stars: 995
|
||||
stars: 996
|
||||
owner_login: ajndkr
|
||||
owner_html_url: https://github.com/ajndkr
|
||||
|
||||
@@ -10,12 +10,12 @@ Xewus:
|
||||
url: https://github.com/Xewus
|
||||
sodaMelon:
|
||||
login: sodaMelon
|
||||
count: 128
|
||||
count: 127
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/66295123?u=be939db90f1119efee9e6110cc05066ff1f40f00&v=4
|
||||
url: https://github.com/sodaMelon
|
||||
ceb10n:
|
||||
login: ceb10n
|
||||
count: 119
|
||||
count: 117
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4
|
||||
url: https://github.com/ceb10n
|
||||
tokusumi:
|
||||
@@ -25,7 +25,7 @@ tokusumi:
|
||||
url: https://github.com/tokusumi
|
||||
hard-coders:
|
||||
login: hard-coders
|
||||
count: 102
|
||||
count: 96
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=78d12d1acdf853c817700145e73de7fd9e5d068b&v=4
|
||||
url: https://github.com/hard-coders
|
||||
hasansezertasan:
|
||||
@@ -50,7 +50,7 @@ AlertRED:
|
||||
url: https://github.com/AlertRED
|
||||
tiangolo:
|
||||
login: tiangolo
|
||||
count: 78
|
||||
count: 73
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4
|
||||
url: https://github.com/tiangolo
|
||||
Alexandrhub:
|
||||
@@ -58,31 +58,26 @@ Alexandrhub:
|
||||
count: 68
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/119126536?u=9fc0d48f3307817bafecc5861eb2168401a6cb04&v=4
|
||||
url: https://github.com/Alexandrhub
|
||||
cassiobotaro:
|
||||
login: cassiobotaro
|
||||
count: 64
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=a08022b191ddbd0a6159b2981d9d878b6d5bb71f&v=4
|
||||
url: https://github.com/cassiobotaro
|
||||
waynerv:
|
||||
login: waynerv
|
||||
count: 63
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4
|
||||
url: https://github.com/waynerv
|
||||
nilslindemann:
|
||||
login: nilslindemann
|
||||
count: 61
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4
|
||||
url: https://github.com/nilslindemann
|
||||
cassiobotaro:
|
||||
login: cassiobotaro
|
||||
count: 62
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=a08022b191ddbd0a6159b2981d9d878b6d5bb71f&v=4
|
||||
url: https://github.com/cassiobotaro
|
||||
mattwang44:
|
||||
login: mattwang44
|
||||
count: 61
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/24987826?u=58e37fb3927b9124b458945ac4c97aa0f1062d85&v=4
|
||||
url: https://github.com/mattwang44
|
||||
YuriiMotov:
|
||||
login: YuriiMotov
|
||||
count: 56
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=bc48be95c429989224786106b027f3c5e40cc354&v=4
|
||||
url: https://github.com/YuriiMotov
|
||||
nilslindemann:
|
||||
login: nilslindemann
|
||||
count: 59
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4
|
||||
url: https://github.com/nilslindemann
|
||||
Laineyzhang55:
|
||||
login: Laineyzhang55
|
||||
count: 48
|
||||
@@ -93,21 +88,26 @@ Kludex:
|
||||
count: 47
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4
|
||||
url: https://github.com/Kludex
|
||||
YuriiMotov:
|
||||
login: YuriiMotov
|
||||
count: 46
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=b9b13d598dddfab529a52d264df80a900bfe7060&v=4
|
||||
url: https://github.com/YuriiMotov
|
||||
komtaki:
|
||||
login: komtaki
|
||||
count: 45
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4
|
||||
url: https://github.com/komtaki
|
||||
svlandeg:
|
||||
login: svlandeg
|
||||
count: 43
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8796347?u=556c97650c27021911b0b9447ec55e75987b0e8a&v=4
|
||||
url: https://github.com/svlandeg
|
||||
rostik1410:
|
||||
login: rostik1410
|
||||
count: 42
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11443899?u=e26a635c2ba220467b308a326a579b8ccf4a8701&v=4
|
||||
url: https://github.com/rostik1410
|
||||
svlandeg:
|
||||
login: svlandeg
|
||||
count: 42
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8796347?u=556c97650c27021911b0b9447ec55e75987b0e8a&v=4
|
||||
url: https://github.com/svlandeg
|
||||
alperiox:
|
||||
login: alperiox
|
||||
count: 42
|
||||
@@ -136,7 +136,7 @@ JavierSanchezCastro:
|
||||
alejsdev:
|
||||
login: alejsdev
|
||||
count: 37
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/90076947?u=0facffe3abf87f57a1f05fa773d1119cc5c2f6a5&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/90076947?u=85ceac49fb87138aebe8d663912e359447329090&v=4
|
||||
url: https://github.com/alejsdev
|
||||
mezgoodle:
|
||||
login: mezgoodle
|
||||
@@ -383,11 +383,6 @@ Joao-Pedro-P-Holanda:
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/110267046?u=331bd016326dac4cf3df4848f6db2dbbf8b5f978&v=4
|
||||
url: https://github.com/Joao-Pedro-P-Holanda
|
||||
maru0123-2004:
|
||||
login: maru0123-2004
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/43961566?u=16ed8603a4d6a4665cb6c53a7aece6f31379b769&v=4
|
||||
url: https://github.com/maru0123-2004
|
||||
JaeHyuckSa:
|
||||
login: JaeHyuckSa
|
||||
count: 16
|
||||
@@ -423,6 +418,11 @@ mattkoehne:
|
||||
count: 14
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/80362153?v=4
|
||||
url: https://github.com/mattkoehne
|
||||
maru0123-2004:
|
||||
login: maru0123-2004
|
||||
count: 14
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/43961566?u=16ed8603a4d6a4665cb6c53a7aece6f31379b769&v=4
|
||||
url: https://github.com/maru0123-2004
|
||||
jovicon:
|
||||
login: jovicon
|
||||
count: 13
|
||||
@@ -458,11 +458,6 @@ wesinalves:
|
||||
count: 13
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/13563128?u=9eb17ed50645dd684bfec47e75dba4e9772ec9c1&v=4
|
||||
url: https://github.com/wesinalves
|
||||
andersonrocha0:
|
||||
login: andersonrocha0
|
||||
count: 13
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/22346169?u=93a1359c8c5461d894802c0cc65bcd09217e7a02&v=4
|
||||
url: https://github.com/andersonrocha0
|
||||
NastasiaSaby:
|
||||
login: NastasiaSaby
|
||||
count: 12
|
||||
@@ -476,7 +471,7 @@ oandersonmagalhaes:
|
||||
mkdir700:
|
||||
login: mkdir700
|
||||
count: 12
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/56359329?u=818e5f4b4dcc1a6ffb3e5aaa08fd827e5a726dfd&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/56359329?u=3d6ea8714f5000829b60dcf7b13a75b1e73aaf47&v=4
|
||||
url: https://github.com/mkdir700
|
||||
batlopes:
|
||||
login: batlopes
|
||||
@@ -498,6 +493,11 @@ KaniKim:
|
||||
count: 12
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/19832624?u=296dbdd490e0eb96e3d45a2608c065603b17dc31&v=4
|
||||
url: https://github.com/KaniKim
|
||||
andersonrocha0:
|
||||
login: andersonrocha0
|
||||
count: 12
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/22346169?u=93a1359c8c5461d894802c0cc65bcd09217e7a02&v=4
|
||||
url: https://github.com/andersonrocha0
|
||||
gitgernit:
|
||||
login: gitgernit
|
||||
count: 12
|
||||
@@ -558,11 +558,6 @@ Zhongheng-Cheng:
|
||||
count: 11
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/95612344?u=a0f7730a3cc7486827965e01a119ad610bda4b0a&v=4
|
||||
url: https://github.com/Zhongheng-Cheng
|
||||
Pyth3rEx:
|
||||
login: Pyth3rEx
|
||||
count: 11
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/26427764?u=087724f74d813c95925d51e354554bd4b6d6bb60&v=4
|
||||
url: https://github.com/Pyth3rEx
|
||||
mariacamilagl:
|
||||
login: mariacamilagl
|
||||
count: 10
|
||||
@@ -616,7 +611,7 @@ socket-socket:
|
||||
nick-cjyx9:
|
||||
login: nick-cjyx9
|
||||
count: 10
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/119087246?u=3d51dcbd79222ecb6538642f31dc7c8bb708d191&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/119087246?u=7227a2de948c68fb8396d5beff1ee5b0e057c42e&v=4
|
||||
url: https://github.com/nick-cjyx9
|
||||
marcelomarkus:
|
||||
login: marcelomarkus
|
||||
@@ -688,6 +683,11 @@ Yarous:
|
||||
count: 9
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/61277193?u=5b462347458a373b2d599c6f416d2b75eddbffad&v=4
|
||||
url: https://github.com/Yarous
|
||||
Pyth3rEx:
|
||||
login: Pyth3rEx
|
||||
count: 9
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/26427764?u=087724f74d813c95925d51e354554bd4b6d6bb60&v=4
|
||||
url: https://github.com/Pyth3rEx
|
||||
dimaqq:
|
||||
login: dimaqq
|
||||
count: 8
|
||||
@@ -736,7 +736,7 @@ minaton-ru:
|
||||
sungchan1:
|
||||
login: sungchan1
|
||||
count: 8
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/28076127?u=fadbf24840186aca639d344bb3e0ecf7ff3441cf&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/28076127?u=a816d86ef3e60450a7225f128caf9a394c9320f9&v=4
|
||||
url: https://github.com/sungchan1
|
||||
Serrones:
|
||||
login: Serrones
|
||||
@@ -761,7 +761,7 @@ anthonycepeda:
|
||||
fabioueno:
|
||||
login: fabioueno
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/14273852?u=a3d546449cdc96621c32bcc26cf74be6e4390209&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/14273852?u=edd700982b16317ac6ebfd24c47bc0029b21d360&v=4
|
||||
url: https://github.com/fabioueno
|
||||
cfraboulet:
|
||||
login: cfraboulet
|
||||
@@ -793,11 +793,6 @@ Zerohertz:
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/42334717?u=5ebf4d33e73b1ad373154f6cdee44f7cab4d05ba&v=4
|
||||
url: https://github.com/Zerohertz
|
||||
EdmilsonRodrigues:
|
||||
login: EdmilsonRodrigues
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62777025?u=217d6f3cd6cc750bb8818a3af7726c8d74eb7c2d&v=4
|
||||
url: https://github.com/EdmilsonRodrigues
|
||||
deniscapeto:
|
||||
login: deniscapeto
|
||||
count: 6
|
||||
@@ -1033,6 +1028,11 @@ devluisrodrigues:
|
||||
count: 5
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/21125286?v=4
|
||||
url: https://github.com/11kkw
|
||||
EdmilsonRodrigues:
|
||||
login: EdmilsonRodrigues
|
||||
count: 5
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62777025?u=217d6f3cd6cc750bb8818a3af7726c8d74eb7c2d&v=4
|
||||
url: https://github.com/EdmilsonRodrigues
|
||||
lpdswing:
|
||||
login: lpdswing
|
||||
count: 4
|
||||
@@ -1178,11 +1178,6 @@ SBillion:
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1070649?u=3ab493dfc88b39da0eb1600e3b8e7df1c90a5dee&v=4
|
||||
url: https://github.com/SBillion
|
||||
seuthootDev:
|
||||
login: seuthootDev
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/175179350?u=7c2cbc48ab43b52e0c86592111d92e013d72ea4d&v=4
|
||||
url: https://github.com/seuthootDev
|
||||
tyronedamasceno:
|
||||
login: tyronedamasceno
|
||||
count: 3
|
||||
@@ -1271,7 +1266,7 @@ rafsaf:
|
||||
frnsimoes:
|
||||
login: frnsimoes
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/66239468?u=cba345870d8d6b25dd6d56ee18f7120581e3c573&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/66239468?u=fd8d408946633acc4bea057c207e6c0833871527&v=4
|
||||
url: https://github.com/frnsimoes
|
||||
lieryan:
|
||||
login: lieryan
|
||||
@@ -1598,11 +1593,6 @@ ayr-ton:
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1090517?u=5cf70a0e0f0dbf084e074e494aa94d7c91a46ba6&v=4
|
||||
url: https://github.com/ayr-ton
|
||||
Kadermiyanyedi:
|
||||
login: Kadermiyanyedi
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/48386782?u=e34f31bf50a8ed8d37fbfa4f301b0c190b1b4b86&v=4
|
||||
url: https://github.com/Kadermiyanyedi
|
||||
raphaelauv:
|
||||
login: raphaelauv
|
||||
count: 2
|
||||
@@ -1841,7 +1831,7 @@ EgorOnishchuk:
|
||||
iamantonreznik:
|
||||
login: iamantonreznik
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/112612414?u=b9ba8d9b4d3940198bc3a4353dfce70c044a39b1&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/112612414?u=bf6de9a1ab17326fe14de0709719fff3826526d0&v=4
|
||||
url: https://github.com/iamantonreznik
|
||||
Azazul123:
|
||||
login: Azazul123
|
||||
@@ -1861,7 +1851,7 @@ NavesSapnis:
|
||||
isgin01:
|
||||
login: isgin01
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/157279130?u=16d6466476cf7dbc55a4cd575b6ea920ebdd81e1&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/157279130?u=ddffde10876b50f35dc90d1337f507a630530a6a&v=4
|
||||
url: https://github.com/isgin01
|
||||
syedasamina56:
|
||||
login: syedasamina56
|
||||
|
||||
@@ -8,14 +8,9 @@ jaystone776:
|
||||
count: 46
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4
|
||||
url: https://github.com/jaystone776
|
||||
tiangolo:
|
||||
login: tiangolo
|
||||
count: 31
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4
|
||||
url: https://github.com/tiangolo
|
||||
ceb10n:
|
||||
login: ceb10n
|
||||
count: 30
|
||||
count: 29
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4
|
||||
url: https://github.com/ceb10n
|
||||
valentinDruzhinin:
|
||||
@@ -33,6 +28,11 @@ SwftAlpc:
|
||||
count: 23
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4
|
||||
url: https://github.com/SwftAlpc
|
||||
tiangolo:
|
||||
login: tiangolo
|
||||
count: 22
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4
|
||||
url: https://github.com/tiangolo
|
||||
hasansezertasan:
|
||||
login: hasansezertasan
|
||||
count: 22
|
||||
@@ -43,16 +43,16 @@ waynerv:
|
||||
count: 20
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4
|
||||
url: https://github.com/waynerv
|
||||
hard-coders:
|
||||
login: hard-coders
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=78d12d1acdf853c817700145e73de7fd9e5d068b&v=4
|
||||
url: https://github.com/hard-coders
|
||||
AlertRED:
|
||||
login: AlertRED
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/15695000?u=f5a4944c6df443030409c88da7d7fa0b7ead985c&v=4
|
||||
url: https://github.com/AlertRED
|
||||
hard-coders:
|
||||
login: hard-coders
|
||||
count: 15
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=78d12d1acdf853c817700145e73de7fd9e5d068b&v=4
|
||||
url: https://github.com/hard-coders
|
||||
Joao-Pedro-P-Holanda:
|
||||
login: Joao-Pedro-P-Holanda
|
||||
count: 14
|
||||
@@ -108,11 +108,6 @@ pablocm83:
|
||||
count: 8
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/28315068?u=3310fbb05bb8bfc50d2c48b6cb64ac9ee4a14549&v=4
|
||||
url: https://github.com/pablocm83
|
||||
YuriiMotov:
|
||||
login: YuriiMotov
|
||||
count: 8
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=bc48be95c429989224786106b027f3c5e40cc354&v=4
|
||||
url: https://github.com/YuriiMotov
|
||||
ptt3199:
|
||||
login: ptt3199
|
||||
count: 7
|
||||
@@ -138,6 +133,11 @@ Alexandrhub:
|
||||
count: 6
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/119126536?u=9fc0d48f3307817bafecc5861eb2168401a6cb04&v=4
|
||||
url: https://github.com/Alexandrhub
|
||||
YuriiMotov:
|
||||
login: YuriiMotov
|
||||
count: 6
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=b9b13d598dddfab529a52d264df80a900bfe7060&v=4
|
||||
url: https://github.com/YuriiMotov
|
||||
Serrones:
|
||||
login: Serrones
|
||||
count: 5
|
||||
@@ -291,7 +291,7 @@ hsuanchi:
|
||||
alejsdev:
|
||||
login: alejsdev
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/90076947?u=0facffe3abf87f57a1f05fa773d1119cc5c2f6a5&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/90076947?u=85ceac49fb87138aebe8d663912e359447329090&v=4
|
||||
url: https://github.com/alejsdev
|
||||
riroan:
|
||||
login: riroan
|
||||
@@ -361,7 +361,7 @@ Rishat-F:
|
||||
ruzia:
|
||||
login: ruzia
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/24503?u=abce66d26c9611818720f11e6ae6773a6e0928f8&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/24503?v=4
|
||||
url: https://github.com/ruzia
|
||||
izaguerreiro:
|
||||
login: izaguerreiro
|
||||
@@ -413,11 +413,6 @@ ayr-ton:
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1090517?u=5cf70a0e0f0dbf084e074e494aa94d7c91a46ba6&v=4
|
||||
url: https://github.com/ayr-ton
|
||||
Kadermiyanyedi:
|
||||
login: Kadermiyanyedi
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/48386782?u=e34f31bf50a8ed8d37fbfa4f301b0c190b1b4b86&v=4
|
||||
url: https://github.com/Kadermiyanyedi
|
||||
KdHyeon0661:
|
||||
login: KdHyeon0661
|
||||
count: 2
|
||||
@@ -466,7 +461,7 @@ ArtemKhymenko:
|
||||
hasnatsajid:
|
||||
login: hasnatsajid
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/86589885?v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/86589885?u=6668823c3b029bfecf10a8918ed3af1aafb8b15e&v=4
|
||||
url: https://github.com/hasnatsajid
|
||||
alperiox:
|
||||
login: alperiox
|
||||
|
||||
@@ -120,7 +120,7 @@ The exit code, the automatic closing of the `Session` in:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}
|
||||
|
||||
...would be run after the response finishes sending the slow data:
|
||||
...would be run after the the response finishes sending the slow data:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}
|
||||
|
||||
|
||||
@@ -6,29 +6,13 @@ For that, you can use the `WSGIMiddleware` and use it to wrap your WSGI applicat
|
||||
|
||||
## Using `WSGIMiddleware` { #using-wsgimiddleware }
|
||||
|
||||
/// info
|
||||
|
||||
This requires installing `a2wsgi` for example with `pip install a2wsgi`.
|
||||
|
||||
///
|
||||
|
||||
You need to import `WSGIMiddleware` from `a2wsgi`.
|
||||
You need to import `WSGIMiddleware`.
|
||||
|
||||
Then wrap the WSGI (e.g. Flask) app with the middleware.
|
||||
|
||||
And then mount that under a path.
|
||||
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[1,3,23] *}
|
||||
|
||||
/// note
|
||||
|
||||
Previously, it was recommended to use `WSGIMiddleware` from `fastapi.middleware.wsgi`, but it is now deprecated.
|
||||
|
||||
It’s advised to use the `a2wsgi` package instead. The usage remains the same.
|
||||
|
||||
Just ensure that you have the `a2wsgi` package installed and import `WSGIMiddleware` correctly from `a2wsgi`.
|
||||
|
||||
///
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[2:3,3] *}
|
||||
|
||||
## Check it { #check-it }
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ Create a virtual environment and install the required packages with <a href="htt
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uv sync --extra all
|
||||
$ uv sync
|
||||
|
||||
---> 100%
|
||||
```
|
||||
@@ -32,9 +32,9 @@ That way, you don't have to "install" your local version to be able to test ever
|
||||
|
||||
/// note | Technical Details
|
||||
|
||||
This only happens when you install using `uv sync --extra all` instead of running `pip install fastapi` directly.
|
||||
This only happens when you install using `uv sync` instead of running `pip install fastapi` directly.
|
||||
|
||||
That is because `uv sync --extra all` will install the local version of FastAPI in "editable" mode by default.
|
||||
That is because `uv sync` will install the local version of FastAPI in "editable" mode by default.
|
||||
|
||||
///
|
||||
|
||||
@@ -179,23 +179,19 @@ as Uvicorn by default will use the port `8000`, the documentation on port `8008`
|
||||
|
||||
Help with translations is VERY MUCH appreciated! And it can't be done without the help from the community. 🌎 🚀
|
||||
|
||||
Here are the steps to help with translations.
|
||||
|
||||
#### Review Translation PRs
|
||||
|
||||
Translation pull requests are made by LLMs guided with prompts designed by the FastAPI team together with the community of native speakers for each supported language.
|
||||
|
||||
#### LLM Prompt per Language
|
||||
These translations are normally still reviewed by native speakers, and here's where you can help!
|
||||
|
||||
Each language has a directory: <a href="https://github.com/fastapi/fastapi/tree/master/docs" class="external-link" target="_blank">https://github.com/fastapi/fastapi/tree/master/docs</a>, in it you can see a file `llm-prompt.md` with the prompt specific for that language.
|
||||
* Check the currently <a href="https://github.com/fastapi/fastapi/pulls" class="external-link" target="_blank">existing pull requests</a> for your language. You can filter the pull requests by the ones with the label for your language. For example, for Spanish, the label is <a href="https://github.com/fastapi/fastapi/pulls?q=is%3Aopen+sort%3Aupdated-desc+label%3Alang-es+label%3Aawaiting-review" class="external-link" target="_blank">`lang-es`</a>.
|
||||
|
||||
For example, for Spanish, the prompt is at: <a href="https://github.com/fastapi/fastapi/blob/master/docs/es/llm-prompt.md" class="external-link" target="_blank">`docs/es/llm-prompt.md`</a>.
|
||||
* When reviewing a pull request, it's better not to suggest changes in the same pull request, because it is LLM generated, and it won't be possible to make sure that small individual changes are replicated in other similar sections, or that they are preserved when translating the same content again.
|
||||
|
||||
If you see mistakes in your language, you can make suggestions to the prompt in that file for your language, and request the specific pages you would like to re-generate after the changes.
|
||||
|
||||
#### Reviewing Translation PRs
|
||||
|
||||
You can also check the currently <a href="https://github.com/fastapi/fastapi/pulls" class="external-link" target="_blank">existing pull requests</a> for your language. You can filter the pull requests by the ones with the label for your language. For example, for Spanish, the label is <a href="https://github.com/fastapi/fastapi/pulls?q=is%3Aopen+sort%3Aupdated-desc+label%3Alang-es+label%3Aawaiting-review" class="external-link" target="_blank">`lang-es`</a>.
|
||||
|
||||
When reviewing a pull request, it's better not to suggest changes in the same pull request, because it is LLM generated, and it won't be possible to make sure that small individual changes are replicated in other similar sections, or that they are preserved when translating the same content again.
|
||||
|
||||
Instead of adding suggestions to the translation PR, make the suggestions to the LLM prompt file for that language, in a new PR. For example, for Spanish, the LLM prompt file is at: <a href="https://github.com/fastapi/fastapi/blob/master/docs/es/llm-prompt.md" class="external-link" target="_blank">`docs/es/llm-prompt.md`</a>.
|
||||
* Instead of adding suggestions to the translation PR, make the suggestions to the LLM prompt file for that language, in a new PR. For example, for Spanish, the LLM prompt file is at: <a href="https://github.com/fastapi/fastapi/blob/master/docs/es/llm-prompt.md" class="external-link" target="_blank">`docs/es/llm-prompt.md`</a>.
|
||||
|
||||
/// tip
|
||||
|
||||
@@ -205,9 +201,9 @@ Check the docs about <a href="https://help.github.com/en/github/collaborating-wi
|
||||
|
||||
#### Subscribe to Notifications for Your Language
|
||||
|
||||
Check if there's a <a href="https://github.com/fastapi/fastapi/discussions/categories/translations" class="external-link" target="_blank">GitHub Discussion</a> to coordinate translations for your language. You can subscribe to it, and when there's a new pull request to review, an automatic comment will be added to the discussion.
|
||||
* Check if there's a <a href="https://github.com/fastapi/fastapi/discussions/categories/translations" class="external-link" target="_blank">GitHub Discussion</a> to coordinate translations for your language. You can subscribe to it, and when there's a new pull request to review, an automatic comment will be added to the discussion.
|
||||
|
||||
To check the 2-letter code for the language you want to translate, you can use the table <a href="https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes" class="external-link" target="_blank">List of ISO 639-1 codes</a>.
|
||||
* To check the 2-letter code for the language you want to translate, you can use the table <a href="https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes" class="external-link" target="_blank">List of ISO 639-1 codes</a>.
|
||||
|
||||
#### Request a New Language
|
||||
|
||||
|
||||
@@ -145,6 +145,8 @@ There are other formats and tools to define and install package dependencies.
|
||||
* Create a `main.py` file with:
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -156,7 +158,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
|
||||
@@ -60,8 +60,7 @@ FastAPI also includes these JavaScript-only `presets` settings:
|
||||
|
||||
```JavaScript
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIBundle.SwaggerUIStandalonePreset
|
||||
SwaggerUIBundle.presets.apis
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
@@ -161,6 +161,8 @@ $ pip install "fastapi[standard]"
|
||||
Create a file `main.py` with:
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -172,7 +174,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -181,7 +183,9 @@ def read_item(item_id: int, q: str | None = None):
|
||||
|
||||
If your code uses `async` / `await`, use `async def`:
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -193,7 +197,7 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: str | None = None):
|
||||
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -284,7 +288,9 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
|
||||
|
||||
Declare the body using standard Python types, thanks to Pydantic.
|
||||
|
||||
```Python hl_lines="2 7-10 23-25"
|
||||
```Python hl_lines="4 9-12 25-27"
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -294,7 +300,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: bool | None = None
|
||||
is_offer: Union[bool, None] = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -303,7 +309,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
|
||||
@@ -35,3 +35,11 @@ It can be imported from `fastapi`:
|
||||
```python
|
||||
from fastapi.middleware.trustedhost import TrustedHostMiddleware
|
||||
```
|
||||
|
||||
::: fastapi.middleware.wsgi.WSGIMiddleware
|
||||
|
||||
It can be imported from `fastapi`:
|
||||
|
||||
```python
|
||||
from fastapi.middleware.wsgi import WSGIMiddleware
|
||||
```
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
You can declare a parameter in a *path operation function* or dependency to be of type `Request` and then you can access the raw request object directly, without any validation, etc.
|
||||
|
||||
Read more about it in the [FastAPI docs about using Request directly](https://fastapi.tiangolo.com/advanced/using-request-directly/)
|
||||
|
||||
You can import it directly from `fastapi`:
|
||||
|
||||
```python
|
||||
|
||||
@@ -4,8 +4,6 @@ You can declare a parameter in a *path operation function* or dependency to be o
|
||||
|
||||
You can also use it directly to create an instance of it and return it from your *path operations*.
|
||||
|
||||
Read more about it in the [FastAPI docs about returning a custom Response](https://fastapi.tiangolo.com/advanced/response-directly/#returning-a-custom-response)
|
||||
|
||||
You can import it directly from `fastapi`:
|
||||
|
||||
```python
|
||||
|
||||
@@ -56,8 +56,6 @@ There are a couple of custom FastAPI response classes, you can use them to optim
|
||||
|
||||
## Starlette Responses
|
||||
|
||||
You can read more about all of them in the [FastAPI docs for Custom Response](https://fastapi.tiangolo.com/advanced/custom-response/) and in the [Starlette docs about Responses](https://starlette.dev/responses/).
|
||||
|
||||
::: fastapi.responses.FileResponse
|
||||
options:
|
||||
members:
|
||||
|
||||
@@ -28,8 +28,6 @@ from fastapi.security import (
|
||||
)
|
||||
```
|
||||
|
||||
Read more about them in the [FastAPI docs about Security](https://fastapi.tiangolo.com/tutorial/security/).
|
||||
|
||||
## API Key Security Schemes
|
||||
|
||||
::: fastapi.security.APIKeyCookie
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
When defining WebSockets, you normally declare a parameter of type `WebSocket` and with it you can read data from the client and send data to it.
|
||||
|
||||
Read more about it in the [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/)
|
||||
|
||||
It is provided directly by Starlette, but you can import it from `fastapi`:
|
||||
|
||||
```python
|
||||
@@ -46,6 +44,16 @@ When you want to define dependencies that should be compatible with both HTTP an
|
||||
- send_json
|
||||
- close
|
||||
|
||||
When a client disconnects, a `WebSocketDisconnect` exception is raised, you can catch it.
|
||||
|
||||
You can import it directly form `fastapi`:
|
||||
|
||||
```python
|
||||
from fastapi import WebSocketDisconnect
|
||||
```
|
||||
|
||||
::: fastapi.WebSocketDisconnect
|
||||
|
||||
## WebSockets - additional classes
|
||||
|
||||
Additional classes for handling WebSockets.
|
||||
@@ -58,16 +66,4 @@ from fastapi.websockets import WebSocketDisconnect, WebSocketState
|
||||
|
||||
::: fastapi.websockets.WebSocketDisconnect
|
||||
|
||||
When a client disconnects, a `WebSocketDisconnect` exception is raised, you can catch it.
|
||||
|
||||
You can import it directly form `fastapi`:
|
||||
|
||||
```python
|
||||
from fastapi import WebSocketDisconnect
|
||||
```
|
||||
|
||||
Read more about it in the [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/#handling-disconnections-and-multiple-clients)
|
||||
|
||||
::: fastapi.websockets.WebSocketState
|
||||
|
||||
`WebSocketState` is an enumeration of the possible states of a WebSocket connection.
|
||||
|
||||
@@ -9,55 +9,6 @@ hide:
|
||||
|
||||
### Docs
|
||||
|
||||
* 📝 Update docs for translations. PR [#14830](https://github.com/fastapi/fastapi/pull/14830) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 📝 Fix duplicate word in `advanced-dependencies.md`. PR [#14815](https://github.com/fastapi/fastapi/pull/14815) by [@Rayyan-Oumlil](https://github.com/Rayyan-Oumlil).
|
||||
|
||||
### Translations
|
||||
|
||||
* 🌐 Update translations for fr (translate-page). PR [#14837](https://github.com/fastapi/fastapi/pull/14837) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for de (update-outdated). PR [#14836](https://github.com/fastapi/fastapi/pull/14836) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for pt (update-outdated). PR [#14833](https://github.com/fastapi/fastapi/pull/14833) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for ko (update-outdated). PR [#14835](https://github.com/fastapi/fastapi/pull/14835) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for es (update-outdated). PR [#14832](https://github.com/fastapi/fastapi/pull/14832) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for tr (update-outdated). PR [#14831](https://github.com/fastapi/fastapi/pull/14831) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for tr (add-missing). PR [#14790](https://github.com/fastapi/fastapi/pull/14790) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for fr (update-outdated). PR [#14826](https://github.com/fastapi/fastapi/pull/14826) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for zh-hant (update-outdated). PR [#14825](https://github.com/fastapi/fastapi/pull/14825) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for uk (update-outdated). PR [#14822](https://github.com/fastapi/fastapi/pull/14822) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔨 Update docs and translations scripts, enable Turkish. PR [#14824](https://github.com/fastapi/fastapi/pull/14824) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
## 0.128.1
|
||||
|
||||
### Features
|
||||
|
||||
* ✨ Add `viewport` meta tag to improve Swagger UI on mobile devices. PR [#14777](https://github.com/fastapi/fastapi/pull/14777) by [@Joab0](https://github.com/Joab0).
|
||||
* 🚸 Improve error message for invalid query parameter type annotations. PR [#14479](https://github.com/fastapi/fastapi/pull/14479) by [@retwish](https://github.com/retwish).
|
||||
|
||||
### Fixes
|
||||
|
||||
* 🐛 Update `ValidationError` schema to include `input` and `ctx`. PR [#14791](https://github.com/fastapi/fastapi/pull/14791) by [@jonathan-fulton](https://github.com/jonathan-fulton).
|
||||
* 🐛 Fix TYPE_CHECKING annotations for Python 3.14 (PEP 649). PR [#14789](https://github.com/fastapi/fastapi/pull/14789) by [@mgu](https://github.com/mgu).
|
||||
* 🐛 Strip whitespaces from `Authorization` header credentials. PR [#14786](https://github.com/fastapi/fastapi/pull/14786) by [@WaveTheory1](https://github.com/WaveTheory1).
|
||||
* 🐛 Fix OpenAPI duplication of `anyOf` refs for app-level responses with specified `content` and `model` as `Union`. PR [#14463](https://github.com/fastapi/fastapi/pull/14463) by [@DJMcoder](https://github.com/DJMcoder).
|
||||
|
||||
### Refactors
|
||||
|
||||
* 🎨 Tweak types for mypy. PR [#14816](https://github.com/fastapi/fastapi/pull/14816) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🏷️ Re-export `IncEx` type from Pydantic instead of duplicating it. PR [#14641](https://github.com/fastapi/fastapi/pull/14641) by [@mvanderlee](https://github.com/mvanderlee).
|
||||
* 💡 Update comment for Pydantic internals. PR [#14814](https://github.com/fastapi/fastapi/pull/14814) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Docs
|
||||
|
||||
* 📝 Update docs for contributing translations, simplify title. PR [#14817](https://github.com/fastapi/fastapi/pull/14817) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 📝 Fix typing issue in `docs_src/app_testing/app_b` code example. PR [#14573](https://github.com/fastapi/fastapi/pull/14573) by [@timakaa](https://github.com/timakaa).
|
||||
* 📝 Fix example of license identifier in documentation. PR [#14492](https://github.com/fastapi/fastapi/pull/14492) by [@johnson-earls](https://github.com/johnson-earls).
|
||||
* 📝 Add banner to translated pages. PR [#14809](https://github.com/fastapi/fastapi/pull/14809) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 📝 Add links to related sections of docs to docstrings. PR [#14776](https://github.com/fastapi/fastapi/pull/14776) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 📝 Update embedded code examples to Python 3.10 syntax. PR [#14758](https://github.com/fastapi/fastapi/pull/14758) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 📝 Fix dependency installation command in `docs/en/docs/contributing.md`. PR [#14757](https://github.com/fastapi/fastapi/pull/14757) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 📝 Use return type annotation instead of `response_model` when possible. PR [#14753](https://github.com/fastapi/fastapi/pull/14753) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 📝 Use `WSGIMiddleware` from `a2wsgi` instead of deprecated `fastapi.middleware.wsgi.WSGIMiddleware`. PR [#14756](https://github.com/fastapi/fastapi/pull/14756) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 📝 Fix minor typos in release notes. PR [#14780](https://github.com/fastapi/fastapi/pull/14780) by [@whyvineet](https://github.com/whyvineet).
|
||||
* 🐛 Fix copy button in custom.js. PR [#14722](https://github.com/fastapi/fastapi/pull/14722) by [@fcharrier](https://github.com/fcharrier).
|
||||
* 📝 Add contribution instructions about LLM generated code and comments and automated tools for PRs. PR [#14706](https://github.com/fastapi/fastapi/pull/14706) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 📝 Update docs for management tasks. PR [#14705](https://github.com/fastapi/fastapi/pull/14705) by [@tiangolo](https://github.com/tiangolo).
|
||||
@@ -67,12 +18,6 @@ hide:
|
||||
|
||||
### Translations
|
||||
|
||||
* 🌐 Improve LLM prompt of `uk` documentation. PR [#14795](https://github.com/fastapi/fastapi/pull/14795) by [@roli2py](https://github.com/roli2py).
|
||||
* 🌐 Update translations for ja (update-outdated). PR [#14588](https://github.com/fastapi/fastapi/pull/14588) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for uk (update outdated, found by fixer tool). PR [#14739](https://github.com/fastapi/fastapi/pull/14739) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 🌐 Update translations for tr (update-outdated). PR [#14745](https://github.com/fastapi/fastapi/pull/14745) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update `llm-prompt.md` for Korean language. PR [#14763](https://github.com/fastapi/fastapi/pull/14763) by [@seuthootDev](https://github.com/seuthootDev).
|
||||
* 🌐 Update translations for ko (update outdated, found by fixer tool). PR [#14738](https://github.com/fastapi/fastapi/pull/14738) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 🌐 Update translations for de (update-outdated). PR [#14690](https://github.com/fastapi/fastapi/pull/14690) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update LLM prompt for Russian translations. PR [#14733](https://github.com/fastapi/fastapi/pull/14733) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 🌐 Update translations for ru (update-outdated). PR [#14693](https://github.com/fastapi/fastapi/pull/14693) by [@tiangolo](https://github.com/tiangolo).
|
||||
@@ -91,19 +36,6 @@ hide:
|
||||
|
||||
### Internal
|
||||
|
||||
* ⬇️ Downgrade LLM translations model to GPT-5 to reduce mistakes. PR [#14823](https://github.com/fastapi/fastapi/pull/14823) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🐛 Fix translation script commit in place. PR [#14818](https://github.com/fastapi/fastapi/pull/14818) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔨 Update translation script to retry if LLM-response doesn't pass validation with Translation Fixer tool. PR [#14749](https://github.com/fastapi/fastapi/pull/14749) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 👷 Run tests only on relevant code changes (not on docs). PR [#14813](https://github.com/fastapi/fastapi/pull/14813) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👷 Run mypy by pre-commit. PR [#14806](https://github.com/fastapi/fastapi/pull/14806) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* ⬆ Bump ruff from 0.14.3 to 0.14.14. PR [#14798](https://github.com/fastapi/fastapi/pull/14798) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump pyasn1 from 0.6.1 to 0.6.2. PR [#14804](https://github.com/fastapi/fastapi/pull/14804) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump sqlmodel from 0.0.27 to 0.0.31. PR [#14802](https://github.com/fastapi/fastapi/pull/14802) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump mkdocs-macros-plugin from 1.4.1 to 1.5.0. PR [#14801](https://github.com/fastapi/fastapi/pull/14801) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump gitpython from 3.1.45 to 3.1.46. PR [#14800](https://github.com/fastapi/fastapi/pull/14800) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump typer from 0.16.0 to 0.21.1. PR [#14799](https://github.com/fastapi/fastapi/pull/14799) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* 👥 Update FastAPI GitHub topic repositories. PR [#14803](https://github.com/fastapi/fastapi/pull/14803) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👥 Update FastAPI People - Contributors and Translators. PR [#14796](https://github.com/fastapi/fastapi/pull/14796) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Ensure that an edit to `uv.lock` gets the `internal` label. PR [#14759](https://github.com/fastapi/fastapi/pull/14759) by [@svlandeg](https://github.com/svlandeg).
|
||||
* 🔧 Update sponsors: remove Requestly. PR [#14735](https://github.com/fastapi/fastapi/pull/14735) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update sponsors, LambdaTest changes to TestMu AI. PR [#14734](https://github.com/fastapi/fastapi/pull/14734) by [@tiangolo](https://github.com/tiangolo).
|
||||
@@ -349,7 +281,7 @@ hide:
|
||||
|
||||
### Refactors
|
||||
|
||||
* 🔥 Remove dangling extra conditional no longer needed. PR [#14435](https://github.com/fastapi/fastapi/pull/14435) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔥 Remove dangling extra condiitonal no longer needed. PR [#14435](https://github.com/fastapi/fastapi/pull/14435) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ♻️ Refactor internals, update `is_coroutine` check to reuse internal supported variants (unwrap, check class). PR [#14434](https://github.com/fastapi/fastapi/pull/14434) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Translations
|
||||
@@ -484,7 +416,7 @@ hide:
|
||||
|
||||
### Docs
|
||||
|
||||
* 📝 Update docs for advanced dependencies with `yield`, noting the changes in 0.121.0, adding `scope`. PR [#14287](https://github.com/fastapi/fastapi/pull/14287) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 📝 Upate docs for advanced dependencies with `yield`, noting the changes in 0.121.0, adding `scope`. PR [#14287](https://github.com/fastapi/fastapi/pull/14287) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Internal
|
||||
|
||||
@@ -2712,7 +2644,7 @@ Read more in the [advisory: Content-Type Header ReDoS](https://github.com/tiango
|
||||
* 🌐 Add Japanese translation for `docs/ja/docs/tutorial/handling-errors.md`. PR [#1953](https://github.com/tiangolo/fastapi/pull/1953) by [@SwftAlpc](https://github.com/SwftAlpc).
|
||||
* 🌐 Add Japanese translation for `docs/ja/docs/tutorial/response-status-code.md`. PR [#1942](https://github.com/tiangolo/fastapi/pull/1942) by [@SwftAlpc](https://github.com/SwftAlpc).
|
||||
* 🌐 Add Japanese translation for `docs/ja/docs/tutorial/extra-models.md`. PR [#1941](https://github.com/tiangolo/fastapi/pull/1941) by [@SwftAlpc](https://github.com/SwftAlpc).
|
||||
* 🌐 Add Japanese translation for `docs/ja/docs/tutorial/schema-extra-example.md`. PR [#1931](https://github.com/tiangolo/fastapi/pull/1931) by [@SwftAlpc](https://github.com/SwftAlpc).
|
||||
* 🌐 Add Japanese tranlsation for `docs/ja/docs/tutorial/schema-extra-example.md`. PR [#1931](https://github.com/tiangolo/fastapi/pull/1931) by [@SwftAlpc](https://github.com/SwftAlpc).
|
||||
* 🌐 Add Japanese translation for `docs/ja/docs/tutorial/body-nested-models.md`. PR [#1930](https://github.com/tiangolo/fastapi/pull/1930) by [@SwftAlpc](https://github.com/SwftAlpc).
|
||||
* 🌐 Add Japanese translation for `docs/ja/docs/tutorial/body-fields.md`. PR [#1923](https://github.com/tiangolo/fastapi/pull/1923) by [@SwftAlpc](https://github.com/SwftAlpc).
|
||||
* 🌐 Add German translation for `docs/de/docs/tutorial/index.md`. PR [#9502](https://github.com/tiangolo/fastapi/pull/9502) by [@fhabers21](https://github.com/fhabers21).
|
||||
@@ -4088,7 +4020,7 @@ You hopefully updated to a supported version of Python a while ago. If you haven
|
||||
### Fixes
|
||||
|
||||
* 🐛 Fix `RuntimeError` raised when `HTTPException` has a status code with no content. PR [#5365](https://github.com/tiangolo/fastapi/pull/5365) by [@iudeen](https://github.com/iudeen).
|
||||
* 🐛 Fix empty response body when default `status_code` is empty but the a `Response` parameter with `response.status_code` is set. PR [#5360](https://github.com/tiangolo/fastapi/pull/5360) by [@tmeckel](https://github.com/tmeckel).
|
||||
* 🐛 Fix empty reponse body when default `status_code` is empty but the a `Response` parameter with `response.status_code` is set. PR [#5360](https://github.com/tiangolo/fastapi/pull/5360) by [@tmeckel](https://github.com/tmeckel).
|
||||
|
||||
### Docs
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
/// details | 🌐 Translation by AI and humans
|
||||
|
||||
This translation was made by AI guided by humans. 🤝
|
||||
|
||||
It could have mistakes of misunderstanding the original meaning, or looking unnatural, etc. 🤖
|
||||
|
||||
You can improve this translation by [helping us guide the AI LLM better](https://fastapi.tiangolo.com/contributing/#translations).
|
||||
|
||||
[English version](ENGLISH_VERSION_URL)
|
||||
|
||||
///
|
||||
@@ -102,16 +102,15 @@ Of course, you can also declare additional query parameters whenever you need, a
|
||||
|
||||
As, by default, singular values are interpreted as query parameters, you don't have to explicitly add a `Query`, you can just do:
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
Or in Python 3.9:
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
Or in Python 3.10 and above:
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ In these cases, it could make sense to store the tags in an `Enum`.
|
||||
|
||||
You can add a `summary` and `description`:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[18:19] *}
|
||||
|
||||
## Description from docstring { #description-from-docstring }
|
||||
|
||||
@@ -70,7 +70,7 @@ It will be used in the interactive docs:
|
||||
|
||||
You can specify the response description with the parameter `response_description`:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[19] *}
|
||||
|
||||
/// info
|
||||
|
||||
|
||||
@@ -317,16 +317,12 @@ extra:
|
||||
name: de - Deutsch
|
||||
- link: /es/
|
||||
name: es - español
|
||||
- link: /ja/
|
||||
name: ja - 日本語
|
||||
- link: /ko/
|
||||
name: ko - 한국어
|
||||
- link: /pt/
|
||||
name: pt - português
|
||||
- link: /ru/
|
||||
name: ru - русский язык
|
||||
- link: /tr/
|
||||
name: tr - Türkçe
|
||||
- link: /uk/
|
||||
name: uk - українська мова
|
||||
extra_css:
|
||||
|
||||
@@ -2,33 +2,17 @@
|
||||
|
||||
Puedes montar aplicaciones WSGI como viste con [Sub Aplicaciones - Mounts](sub-applications.md){.internal-link target=_blank}, [Detrás de un Proxy](behind-a-proxy.md){.internal-link target=_blank}.
|
||||
|
||||
Para eso, puedes usar el `WSGIMiddleware` y usarlo para envolver tu aplicación WSGI, por ejemplo, Flask, Django, etc.
|
||||
Para eso, puedes usar `WSGIMiddleware` y usarlo para envolver tu aplicación WSGI, por ejemplo, Flask, Django, etc.
|
||||
|
||||
## Usando `WSGIMiddleware` { #using-wsgimiddleware }
|
||||
|
||||
/// info | Información
|
||||
|
||||
Esto requiere instalar `a2wsgi`, por ejemplo con `pip install a2wsgi`.
|
||||
|
||||
///
|
||||
|
||||
Necesitas importar `WSGIMiddleware` de `a2wsgi`.
|
||||
Necesitas importar `WSGIMiddleware`.
|
||||
|
||||
Luego envuelve la aplicación WSGI (p. ej., Flask) con el middleware.
|
||||
|
||||
Y luego móntala bajo un path.
|
||||
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[1,3,23] *}
|
||||
|
||||
/// note | Nota
|
||||
|
||||
Anteriormente, se recomendaba usar `WSGIMiddleware` de `fastapi.middleware.wsgi`, pero ahora está deprecado.
|
||||
|
||||
Se aconseja usar el paquete `a2wsgi` en su lugar. El uso sigue siendo el mismo.
|
||||
|
||||
Solo asegúrate de tener instalado el paquete `a2wsgi` e importar `WSGIMiddleware` correctamente desde `a2wsgi`.
|
||||
|
||||
///
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[2:3,3] *}
|
||||
|
||||
## Revisa { #check-it }
|
||||
|
||||
|
||||
@@ -145,6 +145,8 @@ Existen otros formatos y herramientas para definir e instalar dependencias de pa
|
||||
* Crea un archivo `main.py` con:
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -156,7 +158,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -570,7 +572,7 @@ Si tienes una configuración simple, con un **contenedor único** que luego inic
|
||||
|
||||
### Imagen Base de Docker { #base-docker-image }
|
||||
|
||||
Solía haber una imagen official de Docker de FastAPI: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>. Pero ahora está obsoleta. ⛔️
|
||||
Solía haber una imagen official de Docker de FastAPI: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi-docker</a>. Pero ahora está obsoleta. ⛔️
|
||||
|
||||
Probablemente **no** deberías usar esta imagen base de Docker (o cualquier otra similar).
|
||||
|
||||
|
||||
@@ -161,6 +161,8 @@ $ pip install "fastapi[standard]"
|
||||
Crea un archivo `main.py` con:
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -172,7 +174,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -181,7 +183,9 @@ def read_item(item_id: int, q: str | None = None):
|
||||
|
||||
Si tu código usa `async` / `await`, usa `async def`:
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -193,7 +197,7 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: str | None = None):
|
||||
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -284,7 +288,9 @@ Ahora modifica el archivo `main.py` para recibir un body desde un request `PUT`.
|
||||
|
||||
Declara el body usando tipos estándar de Python, gracias a Pydantic.
|
||||
|
||||
```Python hl_lines="2 7-10 23-25"
|
||||
```Python hl_lines="4 9-12 25-27"
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -294,7 +300,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: bool | None = None
|
||||
is_offer: Union[bool, None] = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -303,7 +309,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
|
||||
@@ -101,13 +101,13 @@ Por supuesto, también puedes declarar parámetros adicionales de query siempre
|
||||
Como, por defecto, los valores singulares se interpretan como parámetros de query, no tienes que añadir explícitamente un `Query`, solo puedes hacer:
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
O en Python 3.9:
|
||||
O en Python 3.10 y superior:
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
Por ejemplo:
|
||||
|
||||
@@ -52,7 +52,7 @@ En estos casos, podría tener sentido almacenar las tags en un `Enum`.
|
||||
|
||||
Puedes añadir un `summary` y `description`:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[18:19] *}
|
||||
|
||||
## Descripción desde docstring { #description-from-docstring }
|
||||
|
||||
@@ -70,7 +70,7 @@ Será usado en la documentación interactiva:
|
||||
|
||||
Puedes especificar la descripción del response con el parámetro `response_description`:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[19] *}
|
||||
|
||||
/// info | Información
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Réponses supplémentaires dans OpenAPI { #additional-responses-in-openapi }
|
||||
# Réponses supplémentaires dans OpenAPI
|
||||
|
||||
/// warning | Alertes
|
||||
/// warning | Attention
|
||||
|
||||
Ceci concerne un sujet plutôt avancé.
|
||||
|
||||
@@ -14,9 +14,9 @@ Ces réponses supplémentaires seront incluses dans le schéma OpenAPI, elles ap
|
||||
|
||||
Mais pour ces réponses supplémentaires, vous devez vous assurer de renvoyer directement une `Response` comme `JSONResponse`, avec votre code HTTP et votre contenu.
|
||||
|
||||
## Réponse supplémentaire avec `model` { #additional-response-with-model }
|
||||
## Réponse supplémentaire avec `model`
|
||||
|
||||
Vous pouvez passer à vos décorateurs de *chemin d'accès* un paramètre `responses`.
|
||||
Vous pouvez ajouter à votre décorateur de *paramètre de chemin* un paramètre `responses`.
|
||||
|
||||
Il prend comme valeur un `dict` dont les clés sont des codes HTTP pour chaque réponse, comme `200`, et la valeur de ces clés sont d'autres `dict` avec des informations pour chacun d'eux.
|
||||
|
||||
@@ -26,7 +26,7 @@ Chacun de ces `dict` de réponse peut avoir une clé `model`, contenant un modè
|
||||
|
||||
Par exemple, pour déclarer une autre réponse avec un code HTTP `404` et un modèle Pydantic `Message`, vous pouvez écrire :
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial001_py39.py hl[18,22] *}
|
||||
{* ../../docs_src/additional_responses/tutorial001.py hl[18,22] *}
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
@@ -49,7 +49,7 @@ Le bon endroit est :
|
||||
|
||||
///
|
||||
|
||||
Les réponses générées au format OpenAPI pour ce *chemin d'accès* seront :
|
||||
Les réponses générées au format OpenAPI pour cette *opération de chemin* seront :
|
||||
|
||||
```JSON hl_lines="3-12"
|
||||
{
|
||||
@@ -169,13 +169,13 @@ Les schémas sont référencés à un autre endroit du modèle OpenAPI :
|
||||
}
|
||||
```
|
||||
|
||||
## Types de médias supplémentaires pour la réponse principale { #additional-media-types-for-the-main-response }
|
||||
## Types de médias supplémentaires pour la réponse principale
|
||||
|
||||
Vous pouvez utiliser ce même paramètre `responses` pour ajouter différents types de médias pour la même réponse principale.
|
||||
|
||||
Par exemple, vous pouvez ajouter un type de média supplémentaire `image/png`, en déclarant que votre *chemin d'accès* peut renvoyer un objet JSON (avec le type de média `application/json`) ou une image PNG :
|
||||
Par exemple, vous pouvez ajouter un type de média supplémentaire `image/png`, en déclarant que votre *opération de chemin* peut renvoyer un objet JSON (avec le type de média `application/json`) ou une image PNG :
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}
|
||||
{* ../../docs_src/additional_responses/tutorial002.py hl[19:24,28] *}
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
@@ -191,7 +191,7 @@ Mais si vous avez spécifié une classe de réponse personnalisée avec `None` c
|
||||
|
||||
///
|
||||
|
||||
## Combiner les informations { #combining-information }
|
||||
## Combinaison d'informations
|
||||
|
||||
Vous pouvez également combiner des informations de réponse provenant de plusieurs endroits, y compris les paramètres `response_model`, `status_code` et `responses`.
|
||||
|
||||
@@ -203,17 +203,17 @@ Par exemple, vous pouvez déclarer une réponse avec un code HTTP `404` qui util
|
||||
|
||||
Et une réponse avec un code HTTP `200` qui utilise votre `response_model`, mais inclut un `example` personnalisé :
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial003_py39.py hl[20:31] *}
|
||||
{* ../../docs_src/additional_responses/tutorial003.py hl[20:31] *}
|
||||
|
||||
Tout sera combiné et inclus dans votre OpenAPI, et affiché dans la documentation de l'API :
|
||||
|
||||
<img src="/img/tutorial/additional-responses/image01.png">
|
||||
|
||||
## Combinez les réponses prédéfinies et les réponses personnalisées { #combine-predefined-responses-and-custom-ones }
|
||||
## Combinez les réponses prédéfinies et les réponses personnalisées
|
||||
|
||||
Vous voulez peut-être avoir des réponses prédéfinies qui s'appliquent à de nombreux *chemins d'accès*, mais vous souhaitez les combiner avec des réponses personnalisées nécessaires à chaque *chemin d'accès*.
|
||||
Vous voulez peut-être avoir des réponses prédéfinies qui s'appliquent à de nombreux *paramètre de chemin*, mais vous souhaitez les combiner avec des réponses personnalisées nécessaires à chaque *opération de chemin*.
|
||||
|
||||
Dans ces cas, vous pouvez utiliser la technique Python « unpacking » d'un `dict` avec `**dict_to_unpack` :
|
||||
Dans ces cas, vous pouvez utiliser la technique Python "d'affection par décomposition" (appelé _unpacking_ en anglais) d'un `dict` avec `**dict_to_unpack` :
|
||||
|
||||
```Python
|
||||
old_dict = {
|
||||
@@ -233,15 +233,15 @@ Ici, `new_dict` contiendra toutes les paires clé-valeur de `old_dict` plus la n
|
||||
}
|
||||
```
|
||||
|
||||
Vous pouvez utiliser cette technique pour réutiliser certaines réponses prédéfinies dans vos *chemins d'accès* et les combiner avec des réponses personnalisées supplémentaires.
|
||||
Vous pouvez utiliser cette technique pour réutiliser certaines réponses prédéfinies dans vos *paramètres de chemin* et les combiner avec des réponses personnalisées supplémentaires.
|
||||
|
||||
Par exemple:
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}
|
||||
{* ../../docs_src/additional_responses/tutorial004.py hl[13:17,26] *}
|
||||
|
||||
## Plus d'informations sur les réponses OpenAPI { #more-information-about-openapi-responses }
|
||||
## Plus d'informations sur les réponses OpenAPI
|
||||
|
||||
Pour voir exactement ce que vous pouvez inclure dans les réponses, vous pouvez consulter ces sections dans la spécification OpenAPI :
|
||||
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object" class="external-link" target="_blank">Objet Responses de OpenAPI</a>, il inclut le `Response Object`.
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object" class="external-link" target="_blank">Objet Response de OpenAPI</a>, vous pouvez inclure n'importe quoi directement dans chaque réponse à l'intérieur de votre paramètre `responses`. Y compris `description`, `headers`, `content` (à l'intérieur de cela, vous déclarez différents types de médias et schémas JSON) et `links`.
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responsesObject" class="external-link" target="_blank">Objet Responses de OpenAPI </a>, il inclut le `Response Object`.
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responseObject" class="external-link" target="_blank">Objet Response de OpenAPI </a>, vous pouvez inclure n'importe quoi directement dans chaque réponse à l'intérieur de votre paramètre `responses`. Y compris `description`, `headers`, `content` (à l'intérieur de cela, vous déclarez différents types de médias et schémas JSON) et `links`.
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
# Codes HTTP supplémentaires { #additional-status-codes }
|
||||
# Codes HTTP supplémentaires
|
||||
|
||||
Par défaut, **FastAPI** renverra les réponses à l'aide d'une structure de données `JSONResponse`, en plaçant la réponse de votre *chemin d'accès* à l'intérieur de cette `JSONResponse`.
|
||||
|
||||
Il utilisera le code HTTP par défaut ou celui que vous avez défini dans votre *chemin d'accès*.
|
||||
|
||||
## Codes HTTP supplémentaires { #additional-status-codes_1 }
|
||||
## Codes HTTP supplémentaires
|
||||
|
||||
Si vous souhaitez renvoyer des codes HTTP supplémentaires en plus du code principal, vous pouvez le faire en renvoyant directement une `Response`, comme une `JSONResponse`, et en définissant directement le code HTTP supplémentaire.
|
||||
|
||||
Par exemple, disons que vous voulez avoir un *chemin d'accès* qui permet de mettre à jour les éléments et renvoie les codes HTTP 200 « OK » en cas de succès.
|
||||
Par exemple, disons que vous voulez avoir un *chemin d'accès* qui permet de mettre à jour les éléments et renvoie les codes HTTP 200 "OK" en cas de succès.
|
||||
|
||||
Mais vous voulez aussi qu'il accepte de nouveaux éléments. Et lorsque les éléments n'existaient pas auparavant, il les crée et renvoie un code HTTP de 201 « Créé ».
|
||||
Mais vous voulez aussi qu'il accepte de nouveaux éléments. Et lorsque les éléments n'existaient pas auparavant, il les crée et renvoie un code HTTP de 201 "Créé".
|
||||
|
||||
Pour y parvenir, importez `JSONResponse` et renvoyez-y directement votre contenu, en définissant le `status_code` que vous souhaitez :
|
||||
|
||||
{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}
|
||||
{* ../../docs_src/additional_status_codes/tutorial001.py hl[4,25] *}
|
||||
|
||||
/// warning | Alertes
|
||||
/// warning | Attention
|
||||
|
||||
Lorsque vous renvoyez une `Response` directement, comme dans l'exemple ci-dessus, elle sera renvoyée directement.
|
||||
|
||||
Elle ne sera pas sérialisée avec un modèle.
|
||||
|
||||
Assurez-vous qu'il contient les données souhaitées et que les valeurs sont dans un format JSON valide (si vous utilisez une `JSONResponse`).
|
||||
Assurez-vous qu'il contient les données souhaitées et que les valeurs soient dans un format JSON valides (si vous utilisez une `JSONResponse`).
|
||||
|
||||
///
|
||||
|
||||
@@ -30,12 +30,12 @@ Assurez-vous qu'il contient les données souhaitées et que les valeurs sont dan
|
||||
|
||||
Vous pouvez également utiliser `from starlette.responses import JSONResponse`.
|
||||
|
||||
Pour plus de commodités, **FastAPI** fournit les objets `starlette.responses` sous forme d'un alias accessible par `fastapi.responses`. Mais la plupart des réponses disponibles proviennent directement de Starlette. Il en est de même avec `status`.
|
||||
Pour plus de commodités, **FastAPI** fournit les objets `starlette.responses` sous forme d'un alias accessible par `fastapi.responses`. Mais la plupart des réponses disponibles proviennent directement de Starlette. Il en est de même avec l'objet `statut`.
|
||||
|
||||
///
|
||||
|
||||
## Documents OpenAPI et API { #openapi-and-api-docs }
|
||||
## Documents OpenAPI et API
|
||||
|
||||
Si vous renvoyez directement des codes HTTP et des réponses supplémentaires, ils ne seront pas inclus dans le schéma OpenAPI (la documentation de l'API), car FastAPI n'a aucun moyen de savoir à l'avance ce que vous allez renvoyer.
|
||||
|
||||
Mais vous pouvez documenter cela dans votre code, en utilisant : [Réponses supplémentaires](additional-responses.md){.internal-link target=_blank}.
|
||||
Mais vous pouvez documenter cela dans votre code, en utilisant : [Réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}.
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
# Guide de l'utilisateur avancé { #advanced-user-guide }
|
||||
# Guide de l'utilisateur avancé
|
||||
|
||||
## Caractéristiques supplémentaires { #additional-features }
|
||||
## Caractéristiques supplémentaires
|
||||
|
||||
Le [Tutoriel - Guide de l'utilisateur](../tutorial/index.md){.internal-link target=_blank} devrait suffire à vous faire découvrir toutes les fonctionnalités principales de **FastAPI**.
|
||||
|
||||
Dans les sections suivantes, vous verrez des options, configurations et fonctionnalités supplémentaires.
|
||||
|
||||
/// tip | Astuce
|
||||
/// note | Remarque
|
||||
|
||||
Les sections suivantes ne sont **pas nécessairement « avancées »**.
|
||||
Les sections de ce chapitre ne sont **pas nécessairement "avancées"**.
|
||||
|
||||
Et il est possible que, pour votre cas d'utilisation, la solution se trouve dans l'une d'entre elles.
|
||||
Et il est possible que pour votre cas d'utilisation, la solution se trouve dans l'un d'entre eux.
|
||||
|
||||
///
|
||||
|
||||
## Lire d'abord le tutoriel { #read-the-tutorial-first }
|
||||
## Lisez d'abord le didacticiel
|
||||
|
||||
Vous pouvez utiliser la plupart des fonctionnalités de **FastAPI** grâce aux connaissances du [Tutoriel - Guide de l'utilisateur](../tutorial/index.md){.internal-link target=_blank}.
|
||||
|
||||
Et les sections suivantes supposent que vous l'avez lu et que vous en connaissez les idées principales.
|
||||
|
||||
## Cours TestDriven.io
|
||||
|
||||
Si vous souhaitez suivre un cours pour débutants avancés pour compléter cette section de la documentation, vous pouvez consulter : <a href="https://testdrive.io/courses/tdd-fastapi/" class="external- link" target="_blank">Développement piloté par les tests avec FastAPI et Docker</a> par **TestDriven.io**.
|
||||
|
||||
10 % de tous les bénéfices de ce cours sont reversés au développement de **FastAPI**. 🎉 😄
|
||||
|
||||
@@ -1,108 +1,106 @@
|
||||
# Configuration avancée des chemins d'accès { #path-operation-advanced-configuration }
|
||||
# Configuration avancée des paramètres de chemin
|
||||
|
||||
## ID d’opération OpenAPI { #openapi-operationid }
|
||||
## ID d'opération OpenAPI
|
||||
|
||||
/// warning | Alertes
|
||||
/// warning | Attention
|
||||
|
||||
Si vous n’êtes pas un « expert » d’OpenAPI, vous n’en avez probablement pas besoin.
|
||||
Si vous n'êtes pas un "expert" en OpenAPI, vous n'en avez probablement pas besoin.
|
||||
|
||||
///
|
||||
|
||||
Vous pouvez définir l’OpenAPI `operationId` à utiliser dans votre chemin d’accès avec le paramètre `operation_id`.
|
||||
Dans OpenAPI, les chemins sont des ressources, tels que /users/ ou /items/, exposées par votre API, et les opérations sont les méthodes HTTP utilisées pour manipuler ces chemins, telles que GET, POST ou DELETE. Les operationId sont des chaînes uniques facultatives utilisées pour identifier une opération d'un chemin. Vous pouvez définir l'OpenAPI `operationId` à utiliser dans votre *opération de chemin* avec le paramètre `operation_id`.
|
||||
|
||||
Vous devez vous assurer qu’il est unique pour chaque opération.
|
||||
Vous devez vous assurer qu'il est unique pour chaque opération.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial001.py hl[6] *}
|
||||
|
||||
### Utiliser le nom de la fonction de chemin d’accès comme operationId { #using-the-path-operation-function-name-as-the-operationid }
|
||||
### Utilisation du nom *path operation function* comme operationId
|
||||
|
||||
Si vous souhaitez utiliser les noms de fonction de vos API comme `operationId`, vous pouvez les parcourir tous et remplacer l’`operation_id` de chaque chemin d’accès en utilisant leur `APIRoute.name`.
|
||||
Si vous souhaitez utiliser les noms de fonction de vos API comme `operationId`, vous pouvez les parcourir tous et remplacer chaque `operation_id` de l'*opération de chemin* en utilisant leur `APIRoute.name`.
|
||||
|
||||
Vous devez le faire après avoir ajouté tous vos chemins d’accès.
|
||||
Vous devriez le faire après avoir ajouté toutes vos *paramètres de chemin*.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial002.py hl[2,12:21,24] *}
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Si vous appelez manuellement `app.openapi()`, vous devez mettre à jour les `operationId` avant cela.
|
||||
Si vous appelez manuellement `app.openapi()`, vous devez mettre à jour les `operationId` avant.
|
||||
|
||||
///
|
||||
|
||||
/// warning | Alertes
|
||||
/// warning | Attention
|
||||
|
||||
Si vous faites cela, vous devez vous assurer que chacune de vos fonctions de chemin d’accès a un nom unique.
|
||||
Pour faire cela, vous devez vous assurer que chacun de vos *chemin* ait un nom unique.
|
||||
|
||||
Même si elles se trouvent dans des modules différents (fichiers Python).
|
||||
Même s'ils se trouvent dans des modules différents (fichiers Python).
|
||||
|
||||
///
|
||||
|
||||
## Exclusion d’OpenAPI { #exclude-from-openapi }
|
||||
## Exclusion d'OpenAPI
|
||||
|
||||
Pour exclure un chemin d’accès du schéma OpenAPI généré (et donc des systèmes de documentation automatiques), utilisez le paramètre `include_in_schema` et définissez-le à `False` :
|
||||
Pour exclure un *chemin* du schéma OpenAPI généré (et donc des systèmes de documentation automatiques), utilisez le paramètre `include_in_schema` et assignez-lui la valeur `False` :
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial003.py hl[6] *}
|
||||
|
||||
## Description avancée depuis la docstring { #advanced-description-from-docstring }
|
||||
## Description avancée de docstring
|
||||
|
||||
Vous pouvez limiter les lignes utilisées de la docstring d’une fonction de chemin d’accès pour OpenAPI.
|
||||
Vous pouvez limiter le texte utilisé de la docstring d'une *fonction de chemin* qui sera affiché sur OpenAPI.
|
||||
|
||||
L’ajout d’un `\f` (un caractère « saut de page » échappé) amène **FastAPI** à tronquer la sortie utilisée pour OpenAPI à cet endroit.
|
||||
L'ajout d'un `\f` (un caractère d'échappement "form feed") va permettre à **FastAPI** de tronquer la sortie utilisée pour OpenAPI à ce stade.
|
||||
|
||||
Cela n’apparaîtra pas dans la documentation, mais d’autres outils (comme Sphinx) pourront utiliser le reste.
|
||||
Il n'apparaîtra pas dans la documentation, mais d'autres outils (tel que Sphinx) pourront utiliser le reste.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial004.py hl[19:29] *}
|
||||
|
||||
## Réponses supplémentaires { #additional-responses }
|
||||
## Réponses supplémentaires
|
||||
|
||||
Vous avez probablement vu comment déclarer le `response_model` et le `status_code` pour un chemin d’accès.
|
||||
Vous avez probablement vu comment déclarer le `response_model` et le `status_code` pour une *opération de chemin*.
|
||||
|
||||
Cela définit les métadonnées sur la réponse principale d’un chemin d’accès.
|
||||
Cela définit les métadonnées sur la réponse principale d'une *opération de chemin*.
|
||||
|
||||
Vous pouvez également déclarer des réponses supplémentaires avec leurs modèles, codes de statut, etc.
|
||||
|
||||
Il y a un chapitre entier dans la documentation à ce sujet, vous pouvez le lire dans [Réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}.
|
||||
Il y a un chapitre entier ici dans la documentation à ce sujet, vous pouvez le lire sur [Réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}.
|
||||
|
||||
## OpenAPI supplémentaire { #openapi-extra }
|
||||
## OpenAPI supplémentaire
|
||||
|
||||
Lorsque vous déclarez un chemin d’accès dans votre application, **FastAPI** génère automatiquement les métadonnées pertinentes à propos de ce chemin d’accès à inclure dans le schéma OpenAPI.
|
||||
Lorsque vous déclarez un *chemin* dans votre application, **FastAPI** génère automatiquement les métadonnées concernant ce *chemin* à inclure dans le schéma OpenAPI.
|
||||
|
||||
/// note | Détails techniques
|
||||
|
||||
Dans la spécification OpenAPI, cela s’appelle l’<a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object" class="external-link" target="_blank">objet Operation</a>.
|
||||
La spécification OpenAPI appelle ces métadonnées des <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object" class="external-link" target="_blank">Objets d'opération</a>.
|
||||
|
||||
///
|
||||
|
||||
Il contient toutes les informations sur le chemin d’accès et est utilisé pour générer la documentation automatique.
|
||||
Il contient toutes les informations sur le *chemin* et est utilisé pour générer automatiquement la documentation.
|
||||
|
||||
Il inclut les `tags`, `parameters`, `requestBody`, `responses`, etc.
|
||||
|
||||
Ce schéma OpenAPI spécifique à un chemin d’accès est normalement généré automatiquement par **FastAPI**, mais vous pouvez également l’étendre.
|
||||
Ce schéma OpenAPI spécifique aux *operations* est normalement généré automatiquement par **FastAPI**, mais vous pouvez également l'étendre.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Ceci est un point d’extension de bas niveau.
|
||||
|
||||
Si vous avez seulement besoin de déclarer des réponses supplémentaires, un moyen plus pratique de le faire est d’utiliser [Réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}.
|
||||
Si vous avez seulement besoin de déclarer des réponses supplémentaires, un moyen plus pratique de le faire est d'utiliser les [réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}.
|
||||
|
||||
///
|
||||
|
||||
Vous pouvez étendre le schéma OpenAPI pour un chemin d’accès en utilisant le paramètre `openapi_extra`.
|
||||
Vous pouvez étendre le schéma OpenAPI pour une *opération de chemin* en utilisant le paramètre `openapi_extra`.
|
||||
|
||||
### Extensions OpenAPI { #openapi-extensions }
|
||||
### Extensions OpenAPI
|
||||
|
||||
Cet `openapi_extra` peut être utile, par exemple, pour déclarer des [Extensions OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) :
|
||||
Cet `openapi_extra` peut être utile, par exemple, pour déclarer [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) :
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py39.py hl[6] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial005.py hl[6] *}
|
||||
|
||||
Si vous ouvrez la documentation automatique de l’API, votre extension apparaîtra en bas du chemin d’accès spécifique.
|
||||
Si vous ouvrez la documentation automatique de l'API, votre extension apparaîtra au bas du *chemin* spécifique.
|
||||
|
||||
<img src="/img/tutorial/path-operation-advanced-configuration/image01.png">
|
||||
|
||||
Et si vous consultez l’OpenAPI résultant (à `/openapi.json` dans votre API), vous verrez également votre extension comme partie du chemin d’accès spécifique :
|
||||
Et dans le fichier openapi généré (`/openapi.json`), vous verrez également votre extension dans le cadre du *chemin* spécifique :
|
||||
|
||||
```JSON hl_lines="22"
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"openapi": "3.0.2",
|
||||
"info": {
|
||||
"title": "FastAPI",
|
||||
"version": "0.1.0"
|
||||
@@ -129,44 +127,44 @@ Et si vous consultez l’OpenAPI résultant (à `/openapi.json` dans votre API),
|
||||
}
|
||||
```
|
||||
|
||||
### Personnaliser le schéma OpenAPI d’un chemin d’accès { #custom-openapi-path-operation-schema }
|
||||
### Personnalisation du Schéma OpenAPI pour un chemin
|
||||
|
||||
Le dictionnaire dans `openapi_extra` sera fusionné en profondeur avec le schéma OpenAPI généré automatiquement pour le chemin d’accès.
|
||||
Le dictionnaire contenu dans la variable `openapi_extra` sera fusionné avec le schéma OpenAPI généré automatiquement pour l'*opération de chemin*.
|
||||
|
||||
Ainsi, vous pouvez ajouter des données supplémentaires au schéma généré automatiquement.
|
||||
|
||||
Par exemple, vous pourriez décider de lire et de valider la requête avec votre propre code, sans utiliser les fonctionnalités automatiques de FastAPI avec Pydantic, mais vous pourriez tout de même vouloir définir la requête dans le schéma OpenAPI.
|
||||
Par exemple, vous pouvez décider de lire et de valider la requête avec votre propre code, sans utiliser les fonctionnalités automatiques de validation proposée par Pydantic, mais vous pouvez toujours définir la requête dans le schéma OpenAPI.
|
||||
|
||||
Vous pourriez le faire avec `openapi_extra` :
|
||||
Vous pouvez le faire avec `openapi_extra` :
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial006.py hl[20:37,39:40] *}
|
||||
|
||||
Dans cet exemple, nous n’avons déclaré aucun modèle Pydantic. En fait, le corps de la requête n’est même pas <abbr title="converti d'un format simple, comme des octets, en objets Python">parsé</abbr> en JSON, il est lu directement en tant que `bytes`, et la fonction `magic_data_reader()` serait chargée de l’analyser d’une manière ou d’une autre.
|
||||
Dans cet exemple, nous n'avons déclaré aucun modèle Pydantic. En fait, le corps de la requête n'est même pas <abbr title="converti d'un format simple, comme des octets, en objets Python">parsé</abbr> en tant que JSON, il est lu directement en tant que `bytes`, et la fonction `magic_data_reader()` serait chargé de l'analyser d'une manière ou d'une autre.
|
||||
|
||||
Néanmoins, nous pouvons déclarer le schéma attendu pour le corps de la requête.
|
||||
|
||||
### Type de contenu OpenAPI personnalisé { #custom-openapi-content-type }
|
||||
### Type de contenu OpenAPI personnalisé
|
||||
|
||||
En utilisant cette même astuce, vous pourriez utiliser un modèle Pydantic pour définir le JSON Schema qui est ensuite inclus dans la section de schéma OpenAPI personnalisée pour le chemin d’accès.
|
||||
En utilisant cette même astuce, vous pouvez utiliser un modèle Pydantic pour définir le schéma JSON qui est ensuite inclus dans la section de schéma OpenAPI personnalisée pour le *chemin* concerné.
|
||||
|
||||
Et vous pourriez le faire même si le type de données dans la requête n’est pas du JSON.
|
||||
Et vous pouvez le faire même si le type de données dans la requête n'est pas au format JSON.
|
||||
|
||||
Par exemple, dans cette application nous n’utilisons pas la fonctionnalité intégrée de FastAPI pour extraire le JSON Schema des modèles Pydantic ni la validation automatique pour le JSON. En fait, nous déclarons le type de contenu de la requête comme YAML, pas JSON :
|
||||
Dans cet exemple, nous n'utilisons pas les fonctionnalités de FastAPI pour extraire le schéma JSON des modèles Pydantic ni la validation automatique pour JSON. En fait, nous déclarons le type de contenu de la requête en tant que YAML, et non JSON :
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007.py hl[17:22,24] *}
|
||||
|
||||
Néanmoins, bien que nous n’utilisions pas la fonctionnalité intégrée par défaut, nous utilisons toujours un modèle Pydantic pour générer manuellement le JSON Schema pour les données que nous souhaitons recevoir en YAML.
|
||||
Néanmoins, bien que nous n'utilisions pas la fonctionnalité par défaut, nous utilisons toujours un modèle Pydantic pour générer manuellement le schéma JSON pour les données que nous souhaitons recevoir en YAML.
|
||||
|
||||
Ensuite, nous utilisons directement la requête et extrayons le corps en tant que `bytes`. Cela signifie que FastAPI n’essaiera même pas d’analyser le payload de la requête en JSON.
|
||||
Ensuite, nous utilisons directement la requête et extrayons son contenu en tant qu'octets. Cela signifie que FastAPI n'essaiera même pas d'analyser le payload de la requête en tant que JSON.
|
||||
|
||||
Ensuite, dans notre code, nous analysons directement ce contenu YAML, puis nous utilisons à nouveau le même modèle Pydantic pour valider le contenu YAML :
|
||||
Et nous analysons directement ce contenu YAML, puis nous utilisons à nouveau le même modèle Pydantic pour valider le contenu YAML :
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007.py hl[26:33] *}
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Ici, nous réutilisons le même modèle Pydantic.
|
||||
|
||||
Mais de la même manière, nous aurions pu le valider autrement.
|
||||
Mais nous aurions pu tout aussi bien pu le valider d'une autre manière.
|
||||
|
||||
///
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
# Renvoyer directement une réponse { #return-a-response-directly }
|
||||
# Renvoyer directement une réponse
|
||||
|
||||
Lorsque vous créez un *chemin d'accès* **FastAPI**, vous pouvez normalement retourner n'importe quelle donnée : un `dict`, une `list`, un modèle Pydantic, un modèle de base de données, etc.
|
||||
Lorsque vous créez une *opération de chemins* **FastAPI**, vous pouvez normalement retourner n'importe quelle donnée : un `dict`, une `list`, un modèle Pydantic, un modèle de base de données, etc.
|
||||
|
||||
Par défaut, **FastAPI** convertirait automatiquement cette valeur de retour en JSON en utilisant le `jsonable_encoder` expliqué dans [Encodeur compatible JSON](../tutorial/encoder.md){.internal-link target=_blank}.
|
||||
Par défaut, **FastAPI** convertirait automatiquement cette valeur de retour en JSON en utilisant le `jsonable_encoder` expliqué dans [JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank}.
|
||||
|
||||
Ensuite, en arrière-plan, il mettra ces données JSON-compatible (par exemple un `dict`) à l'intérieur d'un `JSONResponse` qui sera utilisé pour envoyer la réponse au client.
|
||||
|
||||
Mais vous pouvez retourner une `JSONResponse` directement à partir de vos *chemins d'accès*.
|
||||
Mais vous pouvez retourner une `JSONResponse` directement à partir de vos *opérations de chemin*.
|
||||
|
||||
Cela peut être utile, par exemple, pour retourner des en-têtes personnalisés ou des cookies.
|
||||
|
||||
## Renvoyer une `Response` { #return-a-response }
|
||||
## Renvoyer une `Response`
|
||||
|
||||
En fait, vous pouvez retourner n'importe quelle `Response` ou n'importe quelle sous-classe de celle-ci.
|
||||
|
||||
/// tip | Astuce
|
||||
/// note | Remarque
|
||||
|
||||
`JSONResponse` est elle-même une sous-classe de `Response`.
|
||||
|
||||
@@ -24,27 +24,27 @@ Et quand vous retournez une `Response`, **FastAPI** la transmet directement.
|
||||
|
||||
Elle ne fera aucune conversion de données avec les modèles Pydantic, elle ne convertira pas le contenu en un type quelconque.
|
||||
|
||||
Cela vous donne beaucoup de flexibilité. Vous pouvez retourner n'importe quel type de données, surcharger n'importe quelle déclaration ou validation de données, etc.
|
||||
Cela vous donne beaucoup de flexibilité. Vous pouvez retourner n'importe quel type de données, surcharger n'importe quelle déclaration ou validation de données.
|
||||
|
||||
## Utiliser le `jsonable_encoder` dans une `Response` { #using-the-jsonable-encoder-in-a-response }
|
||||
## Utiliser le `jsonable_encoder` dans une `Response`
|
||||
|
||||
Parce que **FastAPI** n'apporte aucune modification à une `Response` que vous retournez, vous devez vous assurer que son contenu est prêt pour cela.
|
||||
Parce que **FastAPI** n'apporte aucune modification à une `Response` que vous retournez, vous devez vous assurer que son contenu est prêt à être utilisé (sérialisable).
|
||||
|
||||
Par exemple, vous ne pouvez pas mettre un modèle Pydantic dans une `JSONResponse` sans d'abord le convertir en un `dict` avec tous les types de données (comme `datetime`, `UUID`, etc.) convertis en types compatibles avec JSON.
|
||||
|
||||
Pour ces cas, vous pouvez utiliser le `jsonable_encoder` pour convertir vos données avant de les passer à une réponse :
|
||||
Pour ces cas, vous pouvez spécifier un appel à `jsonable_encoder` pour convertir vos données avant de les passer à une réponse :
|
||||
|
||||
{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}
|
||||
{* ../../docs_src/response_directly/tutorial001.py hl[6:7,21:22] *}
|
||||
|
||||
/// note | Détails techniques
|
||||
|
||||
Vous pouvez aussi utiliser `from starlette.responses import JSONResponse`.
|
||||
|
||||
**FastAPI** fournit le même `starlette.responses` que `fastapi.responses` juste par commodité pour vous, le développeur. Mais la plupart des réponses disponibles proviennent directement de Starlette.
|
||||
**FastAPI** fournit le même objet `starlette.responses` que `fastapi.responses` juste par commodité pour le développeur. Mais la plupart des réponses disponibles proviennent directement de Starlette.
|
||||
|
||||
///
|
||||
|
||||
## Renvoyer une `Response` personnalisée { #returning-a-custom-response }
|
||||
## Renvoyer une `Response` personnalisée
|
||||
|
||||
L'exemple ci-dessus montre toutes les parties dont vous avez besoin, mais il n'est pas encore très utile, car vous auriez pu retourner l'`item` directement, et **FastAPI** l'aurait mis dans une `JSONResponse` pour vous, en le convertissant en `dict`, etc. Tout cela par défaut.
|
||||
|
||||
@@ -54,9 +54,9 @@ Disons que vous voulez retourner une réponse <a href="https://en.wikipedia.org/
|
||||
|
||||
Vous pouvez mettre votre contenu XML dans une chaîne de caractères, la placer dans une `Response`, et la retourner :
|
||||
|
||||
{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
|
||||
{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *}
|
||||
|
||||
## Notes { #notes }
|
||||
## Notes
|
||||
|
||||
Lorsque vous renvoyez une `Response` directement, ses données ne sont pas validées, converties (sérialisées), ni documentées automatiquement.
|
||||
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
# Tests de performance { #benchmarks }
|
||||
# Test de performance
|
||||
|
||||
Les benchmarks indépendants de TechEmpower montrent que les applications **FastAPI** s’exécutant avec Uvicorn sont <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">parmi les frameworks Python les plus rapides disponibles</a>, seulement en dessous de Starlette et Uvicorn eux‑mêmes (tous deux utilisés en interne par FastAPI).
|
||||
Les tests de performance de TechEmpower montrent que les applications **FastAPI** tournant sous Uvicorn comme <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">étant l'un des frameworks Python les plus rapides disponibles</a>, seulement inférieur à Starlette et Uvicorn (tous deux utilisés au cœur de FastAPI). (*)
|
||||
|
||||
Mais en prêtant attention aux tests de performance et aux comparaisons, vous devez tenir compte de ce qui suit.
|
||||
Mais en prêtant attention aux tests de performance et aux comparaisons, il faut tenir compte de ce qu'il suit.
|
||||
|
||||
## Tests de performance et rapidité { #benchmarks-and-speed }
|
||||
## Tests de performance et rapidité
|
||||
|
||||
Lorsque vous vérifiez les tests de performance, il est commun de voir plusieurs outils de différents types comparés comme équivalents.
|
||||
|
||||
En particulier, on voit Uvicorn, Starlette et FastAPI comparés (parmi de nombreux autres outils).
|
||||
|
||||
Plus le problème résolu par un outil est simple, meilleures seront les performances obtenues. Et la plupart des tests de performance ne prennent pas en compte les fonctionnalités additionnelles fournies par les outils.
|
||||
Plus le problème résolu par un outil est simple, mieux seront les performances obtenues. Et la plupart des tests de performance ne prennent pas en compte les fonctionnalités additionnelles fournies par les outils.
|
||||
|
||||
La hiérarchie est la suivante :
|
||||
|
||||
* **Uvicorn** : un serveur ASGI
|
||||
* **Starlette** : (utilise Uvicorn) un microframework web
|
||||
* **FastAPI**: (utilise Starlette) un microframework pour API disposant de fonctionnalités additionnelles pour la création d'API, avec la validation des données, etc.
|
||||
* **Starlette** : (utilise Uvicorn) un micro-framework web
|
||||
* **FastAPI**: (utilise Starlette) un micro-framework pour API disposant de fonctionnalités additionnelles pour la création d'API, avec la validation des données, etc.
|
||||
|
||||
* **Uvicorn** :
|
||||
* A les meilleures performances, étant donné qu'il n'a pas beaucoup de code mis à part le serveur en lui‑même.
|
||||
* On n'écrit pas une application directement avec Uvicorn. Cela signifie que le code devrait inclure, au minimum, plus ou moins tout le code offert par Starlette (ou **FastAPI**). Et si on fait cela, l'application finale aura la même surcharge que si on avait utilisé un framework, tout en minimisant la quantité de code et les bugs.
|
||||
* Si on compare Uvicorn, il faut le comparer à d'autres serveurs d'applications comme Daphne, Hypercorn, uWSGI, etc.
|
||||
* A les meilleures performances, étant donné qu'il n'a pas beaucoup de code mis-à-part le serveur en lui-même.
|
||||
* On n'écrit pas une application avec uniquement Uvicorn. Cela signifie que le code devrait inclure plus ou moins, au minimum, tout le code offert par Starlette (ou **FastAPI**). Et si on fait cela, l'application finale apportera les mêmes complications que si on avait utilisé un framework et que l'on avait minimisé la quantité de code et de bugs.
|
||||
* Si on compare Uvicorn, il faut le comparer à d'autre applications de serveurs comme Daphne, Hypercorn, uWSGI, etc.
|
||||
* **Starlette** :
|
||||
* A les secondes meilleures performances après Uvicorn. En réalité, Starlette utilise Uvicorn. De ce fait, il ne peut qu’être plus « lent » qu'Uvicorn car il requiert l'exécution de plus de code.
|
||||
* Cependant, il apporte les outils pour construire une application web simple, avec un routage basé sur des chemins, etc.
|
||||
* Si on compare Starlette, il faut le comparer à d'autres frameworks web (ou microframeworks) comme Sanic, Flask, Django, etc.
|
||||
* A les seconde meilleures performances après Uvicorn. Starlette utilise en réalité Uvicorn. De ce fait, il ne peut qu’être plus "lent" qu'Uvicorn car il requiert l'exécution de plus de code.
|
||||
* Cependant il nous apporte les outils pour construire une application web simple, avec un routage basé sur des chemins, etc.
|
||||
* Si on compare Starlette, il faut le comparer à d'autres frameworks web (ou micorframework) comme Sanic, Flask, Django, etc.
|
||||
* **FastAPI** :
|
||||
* Comme Starlette utilise Uvicorn et ne peut donc pas être plus rapide que lui, **FastAPI** utilise Starlette et ne peut donc pas être plus rapide que lui.
|
||||
* FastAPI apporte des fonctionnalités supplémentaires à Starlette. Des fonctionnalités dont vous avez presque toujours besoin lors de la création d'une API, comme la validation des données et la sérialisation. En l'utilisant, vous obtenez une documentation automatique « gratuitement » (la documentation automatique n'ajoute même pas de surcharge à l’exécution, elle est générée au démarrage).
|
||||
* Si on n'utilisait pas FastAPI mais directement Starlette (ou un autre outil comme Sanic, Flask, Responder, etc.), il faudrait implémenter toute la validation des données et la sérialisation soi‑même. L'application finale aurait donc la même surcharge que si elle avait été construite avec FastAPI. Et dans de nombreux cas, cette validation des données et cette sérialisation représentent la plus grande quantité de code écrite dans les applications.
|
||||
* De ce fait, en utilisant FastAPI on minimise le temps de développement, les bugs, le nombre de lignes de code, et on obtient probablement les mêmes performances (voire de meilleures performances) que l'on aurait pu avoir sans ce framework (car il aurait fallu tout implémenter dans votre code).
|
||||
* Si on compare FastAPI, il faut le comparer à d'autres frameworks d’application web (ou ensembles d'outils) qui fournissent la validation des données, la sérialisation et la documentation, comme Flask-apispec, NestJS, Molten, etc. Des frameworks avec validation des données, sérialisation et documentation automatiques intégrées.
|
||||
* Comme Starlette, FastAPI utilise Uvicorn et ne peut donc pas être plus rapide que ce dernier.
|
||||
* FastAPI apporte des fonctionnalités supplémentaires à Starlette. Des fonctionnalités qui sont nécessaires presque systématiquement lors de la création d'une API, comme la validation des données, la sérialisation. En utilisant FastAPI, on obtient une documentation automatiquement (qui ne requiert aucune manipulation pour être mise en place).
|
||||
* Si on n'utilisait pas FastAPI mais directement Starlette (ou un outil équivalent comme Sanic, Flask, Responder, etc) il faudrait implémenter la validation des données et la sérialisation par nous-même. Le résultat serait donc le même dans les deux cas mais du travail supplémentaire serait à réaliser avec Starlette, surtout en considérant que la validation des données et la sérialisation représentent la plus grande quantité de code à écrire dans une application.
|
||||
* De ce fait, en utilisant FastAPI on minimise le temps de développement, les bugs, le nombre de lignes de code, et on obtient les mêmes performances (si ce n'est de meilleurs performances) que l'on aurait pu avoir sans ce framework (en ayant à implémenter de nombreuses fonctionnalités importantes par nous-mêmes).
|
||||
* Si on compare FastAPI, il faut le comparer à d'autres frameworks web (ou ensemble d'outils) qui fournissent la validation des données, la sérialisation et la documentation, comme Flask-apispec, NestJS, Molten, etc.
|
||||
|
||||
@@ -1,150 +1,75 @@
|
||||
# FastAPI dans des conteneurs - Docker { #fastapi-in-containers-docker }
|
||||
# Déployer avec Docker
|
||||
|
||||
Lors du déploiement d'applications FastAPI, une approche courante consiste à construire une **image de conteneur Linux**. C'est généralement fait avec <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a>. Vous pouvez ensuite déployer cette image de conteneur de plusieurs façons possibles.
|
||||
Dans cette section, vous verrez des instructions et des liens vers des guides pour savoir comment :
|
||||
|
||||
L'utilisation de conteneurs Linux présente plusieurs avantages, notamment la **sécurité**, la **réplicabilité**, la **simplicité**, entre autres.
|
||||
* Faire de votre application **FastAPI** une image/conteneur Docker avec une performance maximale. En environ **5 min**.
|
||||
* (Optionnellement) comprendre ce que vous, en tant que développeur, devez savoir sur HTTPS.
|
||||
* Configurer un cluster en mode Docker Swarm avec HTTPS automatique, même sur un simple serveur à 5 dollars US/mois. En environ **20 min**.
|
||||
* Générer et déployer une application **FastAPI** complète, en utilisant votre cluster Docker Swarm, avec HTTPS, etc. En environ **10 min**.
|
||||
|
||||
Vous pouvez utiliser <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a> pour le déploiement. Il présente plusieurs avantages comme la sécurité, la réplicabilité, la simplicité de développement, etc.
|
||||
|
||||
Si vous utilisez Docker, vous pouvez utiliser l'image Docker officielle :
|
||||
|
||||
## <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>
|
||||
|
||||
Cette image est dotée d'un mécanisme d'"auto-tuning", de sorte qu'il vous suffit d'ajouter votre code pour obtenir automatiquement des performances très élevées. Et sans faire de sacrifices.
|
||||
|
||||
Mais vous pouvez toujours changer et mettre à jour toutes les configurations avec des variables d'environnement ou des fichiers de configuration.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Vous êtes pressé et vous connaissez déjà tout ça ? Allez directement au [`Dockerfile` ci-dessous 👇](#build-a-docker-image-for-fastapi).
|
||||
Pour voir toutes les configurations et options, rendez-vous sur la page de l'image Docker : <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
|
||||
|
||||
///
|
||||
|
||||
<details>
|
||||
<summary>Aperçu du Dockerfile 👀</summary>
|
||||
## Créer un `Dockerfile`
|
||||
|
||||
* Allez dans le répertoire de votre projet.
|
||||
* Créez un `Dockerfile` avec :
|
||||
|
||||
```Dockerfile
|
||||
FROM python:3.9
|
||||
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
COPY ./app /code/app
|
||||
|
||||
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
|
||||
|
||||
# Si vous exécutez derrière un proxy comme Nginx ou Traefik, ajoutez --proxy-headers
|
||||
# CMD ["fastapi", "run", "app/main.py", "--port", "80", "--proxy-headers"]
|
||||
COPY ./app /app
|
||||
```
|
||||
|
||||
</details>
|
||||
### Applications plus larges
|
||||
|
||||
## Qu'est-ce qu'un conteneur { #what-is-a-container }
|
||||
Si vous avez suivi la section sur la création d' [Applications avec plusieurs fichiers](../tutorial/bigger-applications.md){.internal-link target=_blank}, votre `Dockerfile` pourrait ressembler à ceci :
|
||||
|
||||
Les conteneurs (principalement les conteneurs Linux) sont un moyen très **léger** d'empaqueter des applications, y compris toutes leurs dépendances et les fichiers nécessaires, tout en les isolant des autres conteneurs (autres applications ou composants) dans le même système.
|
||||
```Dockerfile
|
||||
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
|
||||
|
||||
Les conteneurs Linux s'exécutent en utilisant le même noyau Linux que l'hôte (machine, machine virtuelle, serveur cloud, etc.). Cela signifie simplement qu'ils sont très légers (comparés à des machines virtuelles complètes émulant un système d'exploitation entier).
|
||||
|
||||
Ainsi, les conteneurs consomment **peu de ressources**, une quantité comparable à l'exécution directe des processus (alors qu'une machine virtuelle consommerait beaucoup plus).
|
||||
|
||||
Les conteneurs ont également leurs propres processus d'exécution **isolés** (généralement un seul processus), leur système de fichiers et leur réseau, ce qui simplifie le déploiement, la sécurité, le développement, etc.
|
||||
|
||||
## Qu'est-ce qu'une image de conteneur { #what-is-a-container-image }
|
||||
|
||||
Un **conteneur** s'exécute à partir d'une **image de conteneur**.
|
||||
|
||||
Une image de conteneur est une version **statique** de tous les fichiers, des variables d'environnement et de la commande/le programme par défaut devant être présents dans un conteneur. Ici, **statique** signifie que l'**image** du conteneur ne s'exécute pas, elle n'est pas en cours d'exécution, ce ne sont que les fichiers et métadonnées empaquetés.
|
||||
|
||||
Par opposition à une « **image de conteneur** » qui correspond aux contenus statiques stockés, un « **conteneur** » fait normalement référence à l'instance en cours d'exécution, la chose qui est **exécutée**.
|
||||
|
||||
Lorsque le **conteneur** est démarré et en cours d'exécution (démarré à partir d'une **image de conteneur**), il peut créer ou modifier des fichiers, des variables d'environnement, etc. Ces changements n'existeront que dans ce conteneur, mais ne persisteront pas dans l'image de conteneur sous-jacente (ils ne seront pas enregistrés sur le disque).
|
||||
|
||||
Une image de conteneur est comparable au **programme** et à ses contenus, par exemple `python` et un fichier `main.py`.
|
||||
|
||||
Et le **conteneur** lui-même (par opposition à l'**image de conteneur**) est l'instance en cours d'exécution réelle de l'image, comparable à un **processus**. En fait, un conteneur ne fonctionne que lorsqu'il a un **processus en cours d'exécution** (et normalement, il s'agit d'un seul processus). Le conteneur s'arrête lorsqu'aucun processus n'y est en cours d'exécution.
|
||||
|
||||
## Images de conteneur { #container-images }
|
||||
|
||||
Docker a été l'un des principaux outils pour créer et gérer des **images de conteneur** et des **conteneurs**.
|
||||
|
||||
Et il existe un <a href="https://hub.docker.com/" class="external-link" target="_blank">Docker Hub</a> public avec des **images de conteneur officielles** pré-construites pour de nombreux outils, environnements, bases de données et applications.
|
||||
|
||||
Par exemple, il existe une <a href="https://hub.docker.com/_/python" class="external-link" target="_blank">image Python officielle</a>.
|
||||
|
||||
Et il existe beaucoup d'autres images pour différentes choses comme des bases de données, par exemple :
|
||||
|
||||
* <a href="https://hub.docker.com/_/postgres" class="external-link" target="_blank">PostgreSQL</a>
|
||||
* <a href="https://hub.docker.com/_/mysql" class="external-link" target="_blank">MySQL</a>
|
||||
* <a href="https://hub.docker.com/_/mongo" class="external-link" target="_blank">MongoDB</a>
|
||||
* <a href="https://hub.docker.com/_/redis" class="external-link" target="_blank">Redis</a>, etc.
|
||||
|
||||
En utilisant une image de conteneur pré-construite, il est très facile de **combiner** et d'utiliser différents outils. Par exemple, pour essayer une nouvelle base de données. Dans la plupart des cas, vous pouvez utiliser les **images officielles** et simplement les configurer avec des variables d'environnement.
|
||||
|
||||
Ainsi, dans de nombreux cas, vous pouvez apprendre les conteneurs et Docker et réutiliser ces connaissances avec de nombreux outils et composants différents.
|
||||
|
||||
Vous exécuteriez donc **plusieurs conteneurs** avec des éléments différents, comme une base de données, une application Python, un serveur web avec une application frontend React, et les connecter entre eux via leur réseau interne.
|
||||
|
||||
Tous les systèmes de gestion de conteneurs (comme Docker ou Kubernetes) disposent de ces fonctionnalités réseau intégrées.
|
||||
|
||||
## Conteneurs et processus { #containers-and-processes }
|
||||
|
||||
Une **image de conteneur** inclut normalement dans ses métadonnées le programme/la commande par défaut à exécuter lorsque le **conteneur** est démarré et les paramètres à transmettre à ce programme. Très similaire à ce que vous utiliseriez en ligne de commande.
|
||||
|
||||
Lorsqu'un **conteneur** est démarré, il exécutera cette commande/ce programme (bien que vous puissiez la/le remplacer et faire exécuter une autre commande/un autre programme).
|
||||
|
||||
Un conteneur fonctionne tant que le **processus principal** (commande ou programme) est en cours d'exécution.
|
||||
|
||||
Un conteneur a normalement un **seul processus**, mais il est aussi possible de démarrer des sous-processus à partir du processus principal, et ainsi vous aurez **plusieurs processus** dans le même conteneur.
|
||||
|
||||
Mais il n'est pas possible d'avoir un conteneur en cours d'exécution sans **au moins un processus en cours**. Si le processus principal s'arrête, le conteneur s'arrête.
|
||||
|
||||
## Construire une image Docker pour FastAPI { #build-a-docker-image-for-fastapi }
|
||||
|
||||
Très bien, construisons quelque chose maintenant ! 🚀
|
||||
|
||||
Je vais vous montrer comment construire une **image Docker** pour FastAPI **à partir de zéro**, basée sur l'image **officielle Python**.
|
||||
|
||||
C'est ce que vous voudrez faire dans **la plupart des cas**, par exemple :
|
||||
|
||||
* Utiliser **Kubernetes** ou des outils similaires
|
||||
* Exécuter sur un **Raspberry Pi**
|
||||
* Utiliser un service cloud qui exécuterait une image de conteneur pour vous, etc.
|
||||
|
||||
### Dépendances des paquets { #package-requirements }
|
||||
|
||||
Vous aurez normalement les **dépendances des paquets** de votre application dans un fichier.
|
||||
|
||||
Cela dépendra principalement de l'outil que vous utilisez pour **installer** ces dépendances.
|
||||
|
||||
La manière la plus courante consiste à avoir un fichier `requirements.txt` avec les noms des paquets et leurs versions, un par ligne.
|
||||
|
||||
Vous utiliserez bien sûr les mêmes idées que vous avez lues dans [À propos des versions de FastAPI](versions.md){.internal-link target=_blank} pour définir les plages de versions.
|
||||
|
||||
Par exemple, votre `requirements.txt` pourrait ressembler à :
|
||||
|
||||
```
|
||||
fastapi[standard]>=0.113.0,<0.114.0
|
||||
pydantic>=2.7.0,<3.0.0
|
||||
COPY ./app /app/app
|
||||
```
|
||||
|
||||
Et vous installerez normalement ces dépendances de paquets avec `pip`, par exemple :
|
||||
### Raspberry Pi et autres architectures
|
||||
|
||||
<div class="termy">
|
||||
Si vous utilisez Docker sur un Raspberry Pi (qui a un processeur ARM) ou toute autre architecture, vous pouvez créer un `Dockerfile` à partir de zéro, basé sur une image de base Python (qui est multi-architecture) et utiliser Uvicorn seul.
|
||||
|
||||
```console
|
||||
$ pip install -r requirements.txt
|
||||
---> 100%
|
||||
Successfully installed fastapi pydantic
|
||||
Dans ce cas, votre `Dockerfile` pourrait ressembler à ceci :
|
||||
|
||||
```Dockerfile
|
||||
FROM python:3.7
|
||||
|
||||
RUN pip install fastapi uvicorn
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
COPY ./app /app
|
||||
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
```
|
||||
|
||||
</div>
|
||||
## Créer le code **FastAPI**.
|
||||
|
||||
/// info
|
||||
|
||||
Il existe d'autres formats et outils pour définir et installer des dépendances de paquets.
|
||||
|
||||
///
|
||||
|
||||
### Créer le code **FastAPI** { #create-the-fastapi-code }
|
||||
|
||||
* Créez un répertoire `app` et entrez dedans.
|
||||
* Créez un fichier vide `__init__.py`.
|
||||
* Créez un fichier `main.py` avec :
|
||||
* Créer un répertoire `app` et y entrer.
|
||||
* Créez un fichier `main.py` avec :
|
||||
|
||||
```Python
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -156,168 +81,22 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
### Dockerfile { #dockerfile }
|
||||
|
||||
Maintenant, dans le même répertoire de projet, créez un fichier `Dockerfile` avec :
|
||||
|
||||
```{ .dockerfile .annotate }
|
||||
# (1)!
|
||||
FROM python:3.9
|
||||
|
||||
# (2)!
|
||||
WORKDIR /code
|
||||
|
||||
# (3)!
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
|
||||
# (4)!
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
# (5)!
|
||||
COPY ./app /code/app
|
||||
|
||||
# (6)!
|
||||
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
|
||||
```
|
||||
|
||||
1. Démarrer à partir de l'image de base Python officielle.
|
||||
|
||||
2. Définir le répertoire de travail courant sur `/code`.
|
||||
|
||||
C'est là que nous placerons le fichier `requirements.txt` et le répertoire `app`.
|
||||
|
||||
3. Copier le fichier des dépendances vers le répertoire `/code`.
|
||||
|
||||
Copier **uniquement** le fichier des dépendances en premier, pas le reste du code.
|
||||
|
||||
Comme ce fichier **ne change pas souvent**, Docker le détectera et utilisera le **cache** pour cette étape, ce qui activera le cache pour l'étape suivante aussi.
|
||||
|
||||
4. Installer les dépendances listées dans le fichier des dépendances.
|
||||
|
||||
L'option `--no-cache-dir` indique à `pip` de ne pas enregistrer localement les paquets téléchargés, car cela ne sert que si `pip` devait être relancé pour installer les mêmes paquets, mais ce n'est pas le cas lorsque l'on travaille avec des conteneurs.
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Le `--no-cache-dir` concerne uniquement `pip`, cela n'a rien à voir avec Docker ou les conteneurs.
|
||||
|
||||
///
|
||||
|
||||
L'option `--upgrade` indique à `pip` de mettre à niveau les paquets s'ils sont déjà installés.
|
||||
|
||||
Comme l'étape précédente de copie du fichier peut être détectée par le **cache Docker**, cette étape **utilisera également le cache Docker** lorsqu'il est disponible.
|
||||
|
||||
L'utilisation du cache à cette étape vous **fera gagner** beaucoup de **temps** lors de la reconstruction de l'image encore et encore pendant le développement, au lieu de **télécharger et installer** toutes les dépendances **à chaque fois**.
|
||||
|
||||
5. Copier le répertoire `./app` dans le répertoire `/code`.
|
||||
|
||||
Comme cela contient tout le code qui est ce qui **change le plus fréquemment**, le **cache** Docker ne sera pas facilement utilisé pour cette étape ou pour les **étapes suivantes**.
|
||||
|
||||
Il est donc important de placer cela **vers la fin** du `Dockerfile`, pour optimiser les temps de construction de l'image de conteneur.
|
||||
|
||||
6. Définir la **commande** pour utiliser `fastapi run`, qui utilise Uvicorn sous le capot.
|
||||
|
||||
`CMD` prend une liste de chaînes, chacune de ces chaînes correspond à ce que vous taperiez en ligne de commande séparé par des espaces.
|
||||
|
||||
Cette commande sera exécutée à partir du **répertoire de travail courant**, le même répertoire `/code` que vous avez défini plus haut avec `WORKDIR /code`.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Passez en revue ce que fait chaque ligne en cliquant sur chaque bulle numérotée dans le code. 👆
|
||||
|
||||
///
|
||||
|
||||
/// warning | Alertes
|
||||
|
||||
Vous devez vous assurer d'utiliser **toujours** la **forme exec** de l'instruction `CMD`, comme expliqué ci-dessous.
|
||||
|
||||
///
|
||||
|
||||
#### Utiliser `CMD` - Forme Exec { #use-cmd-exec-form }
|
||||
|
||||
L'instruction Docker <a href="https://docs.docker.com/reference/dockerfile/#cmd" class="external-link" target="_blank">`CMD`</a> peut être écrite sous deux formes :
|
||||
|
||||
✅ Forme **Exec** :
|
||||
|
||||
```Dockerfile
|
||||
# ✅ À faire
|
||||
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
|
||||
```
|
||||
|
||||
⛔️ Forme **Shell** :
|
||||
|
||||
```Dockerfile
|
||||
# ⛔️ À ne pas faire
|
||||
CMD fastapi run app/main.py --port 80
|
||||
```
|
||||
|
||||
Assurez-vous d'utiliser toujours la forme **exec** pour garantir que FastAPI peut s'arrêter proprement et que les [événements de cycle de vie](../advanced/events.md){.internal-link target=_blank} sont déclenchés.
|
||||
|
||||
Vous pouvez en lire davantage dans la <a href="https://docs.docker.com/reference/dockerfile/#shell-and-exec-form" class="external-link" target="_blank">documentation Docker sur les formes shell et exec</a>.
|
||||
|
||||
Cela peut être très visible lors de l'utilisation de `docker compose`. Voir cette section de la FAQ Docker Compose pour plus de détails techniques : <a href="https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop" class="external-link" target="_blank">Pourquoi mes services mettent-ils 10 secondes à se recréer ou à s'arrêter ?</a>.
|
||||
|
||||
#### Structure du répertoire { #directory-structure }
|
||||
|
||||
Vous devriez maintenant avoir une structure de répertoire comme :
|
||||
* Vous devriez maintenant avoir une structure de répertoire telle que :
|
||||
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ └── main.py
|
||||
├── Dockerfile
|
||||
└── requirements.txt
|
||||
└── Dockerfile
|
||||
```
|
||||
|
||||
#### Derrière un proxy de terminaison TLS { #behind-a-tls-termination-proxy }
|
||||
## Construire l'image Docker
|
||||
|
||||
Si vous exécutez votre conteneur derrière un proxy de terminaison TLS (load balancer) comme Nginx ou Traefik, ajoutez l'option `--proxy-headers`, cela indiquera à Uvicorn (via la CLI FastAPI) de faire confiance aux en-têtes envoyés par ce proxy lui indiquant que l'application s'exécute derrière HTTPS, etc.
|
||||
|
||||
```Dockerfile
|
||||
CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"]
|
||||
```
|
||||
|
||||
#### Cache Docker { #docker-cache }
|
||||
|
||||
Il y a une astuce importante dans ce `Dockerfile`, nous copions d'abord **le fichier des dépendances seul**, pas le reste du code. Laissez-moi vous expliquer pourquoi.
|
||||
|
||||
```Dockerfile
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
```
|
||||
|
||||
Docker et d'autres outils **construisent** ces images de conteneur **de manière incrémentale**, en ajoutant **une couche au-dessus de l'autre**, en commençant par le haut du `Dockerfile` et en ajoutant tous les fichiers créés par chacune des instructions du `Dockerfile`.
|
||||
|
||||
Docker et des outils similaires utilisent également un **cache interne** lors de la construction de l'image : si un fichier n'a pas changé depuis la dernière construction de l'image de conteneur, alors il va **réutiliser la même couche** créée la dernière fois, au lieu de recopier le fichier et créer une nouvelle couche à partir de zéro.
|
||||
|
||||
Éviter simplement la copie des fichiers n'améliore pas nécessairement les choses de manière significative, mais comme il a utilisé le cache pour cette étape, il peut **utiliser le cache pour l'étape suivante**. Par exemple, il peut utiliser le cache pour l'instruction qui installe les dépendances avec :
|
||||
|
||||
```Dockerfile
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
```
|
||||
|
||||
Le fichier des dépendances **ne changera pas fréquemment**. Ainsi, en copiant uniquement ce fichier, Docker pourra **utiliser le cache** pour cette étape.
|
||||
|
||||
Et ensuite, Docker pourra **utiliser le cache pour l'étape suivante** qui télécharge et installe ces dépendances. Et c'est là que nous **gagnons beaucoup de temps**. ✨ ... et évitons l'ennui en attendant. 😪😆
|
||||
|
||||
Télécharger et installer les dépendances de paquets **peut prendre des minutes**, mais utiliser le **cache** ne **prendra que quelques secondes** au plus.
|
||||
|
||||
Et comme vous reconstruirez l'image de conteneur encore et encore pendant le développement pour vérifier que vos modifications de code fonctionnent, cela vous fera gagner beaucoup de temps cumulé.
|
||||
|
||||
Ensuite, vers la fin du `Dockerfile`, nous copions tout le code. Comme c'est ce qui **change le plus fréquemment**, nous le plaçons vers la fin, car presque toujours, tout ce qui suit cette étape ne pourra pas utiliser le cache.
|
||||
|
||||
```Dockerfile
|
||||
COPY ./app /code/app
|
||||
```
|
||||
|
||||
### Construire l'image Docker { #build-the-docker-image }
|
||||
|
||||
Maintenant que tous les fichiers sont en place, construisons l'image de conteneur.
|
||||
|
||||
* Allez dans le répertoire du projet (là où se trouve votre `Dockerfile`, contenant votre répertoire `app`).
|
||||
* Allez dans le répertoire du projet (dans lequel se trouve votre `Dockerfile`, contenant votre répertoire `app`).
|
||||
* Construisez votre image FastAPI :
|
||||
|
||||
<div class="termy">
|
||||
@@ -330,17 +109,9 @@ $ docker build -t myimage .
|
||||
|
||||
</div>
|
||||
|
||||
/// tip | Astuce
|
||||
## Démarrer le conteneur Docker
|
||||
|
||||
Remarquez le `.` à la fin, équivalent à `./`, il indique à Docker le répertoire à utiliser pour construire l'image de conteneur.
|
||||
|
||||
Dans ce cas, c'est le même répertoire courant (`.`).
|
||||
|
||||
///
|
||||
|
||||
### Démarrer le conteneur Docker { #start-the-docker-container }
|
||||
|
||||
* Exécutez un conteneur basé sur votre image :
|
||||
* Exécutez un conteneur basé sur votre image :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -350,269 +121,65 @@ $ docker run -d --name mycontainer -p 80:80 myimage
|
||||
|
||||
</div>
|
||||
|
||||
## Vérifier { #check-it }
|
||||
Vous disposez maintenant d'un serveur FastAPI optimisé dans un conteneur Docker. Configuré automatiquement pour votre
|
||||
serveur actuel (et le nombre de cœurs du CPU).
|
||||
|
||||
Vous devriez pouvoir le vérifier via l'URL de votre conteneur Docker, par exemple : <a href="http://192.168.99.100/items/5?q=somequery" class="external-link" target="_blank">http://192.168.99.100/items/5?q=somequery</a> ou <a href="http://127.0.0.1/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1/items/5?q=somequery</a> (ou équivalent, en utilisant votre hôte Docker).
|
||||
## Vérifier
|
||||
|
||||
Vous verrez quelque chose comme :
|
||||
Vous devriez pouvoir accéder à votre application via l'URL de votre conteneur Docker, par exemple : <a href="http://192.168.99.100/items/5?q=somequery" class="external-link" target="_blank">http://192.168.99.100/items/5?q=somequery</a> ou <a href="http://127.0.0.1/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1/items/5?q=somequery</a> (ou équivalent, en utilisant votre hôte Docker).
|
||||
|
||||
Vous verrez quelque chose comme :
|
||||
|
||||
```JSON
|
||||
{"item_id": 5, "q": "somequery"}
|
||||
```
|
||||
|
||||
## Documentation interactive de l'API { #interactive-api-docs }
|
||||
## Documentation interactive de l'API
|
||||
|
||||
Vous pouvez maintenant aller sur <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> ou <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a> (ou équivalent, en utilisant votre hôte Docker).
|
||||
Vous pouvez maintenant visiter <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> ou <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a> (ou équivalent, en utilisant votre hôte Docker).
|
||||
|
||||
Vous verrez la documentation interactive automatique de l'API (fournie par <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>) :
|
||||
Vous verrez la documentation interactive automatique de l'API (fournie par <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>) :
|
||||
|
||||

|
||||
|
||||
## Documentation alternative de l'API { #alternative-api-docs }
|
||||
## Documentation de l'API alternative
|
||||
|
||||
Et vous pouvez aussi aller sur <a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> ou <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a> (ou équivalent, en utilisant votre hôte Docker).
|
||||
Et vous pouvez également aller sur <a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> ou <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a> (ou équivalent, en utilisant votre hôte Docker).
|
||||
|
||||
Vous verrez la documentation automatique alternative (fournie par <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>) :
|
||||
Vous verrez la documentation automatique alternative (fournie par <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>) :
|
||||
|
||||

|
||||
|
||||
## Construire une image Docker avec un FastAPI mono-fichier { #build-a-docker-image-with-a-single-file-fastapi }
|
||||
## Traefik
|
||||
|
||||
Si votre FastAPI est un seul fichier, par exemple `main.py` sans répertoire `./app`, votre structure de fichiers pourrait ressembler à ceci :
|
||||
<a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a> est un reverse proxy/load balancer
|
||||
haute performance. Il peut faire office de "Proxy de terminaison TLS" (entre autres fonctionnalités).
|
||||
|
||||
```
|
||||
.
|
||||
├── Dockerfile
|
||||
├── main.py
|
||||
└── requirements.txt
|
||||
```
|
||||
Il est intégré à Let's Encrypt. Ainsi, il peut gérer toutes les parties HTTPS, y compris l'acquisition et le renouvellement des certificats.
|
||||
|
||||
Vous n'auriez alors qu'à changer les chemins correspondants pour copier le fichier dans le `Dockerfile` :
|
||||
|
||||
```{ .dockerfile .annotate hl_lines="10 13" }
|
||||
FROM python:3.9
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
# (1)!
|
||||
COPY ./main.py /code/
|
||||
|
||||
# (2)!
|
||||
CMD ["fastapi", "run", "main.py", "--port", "80"]
|
||||
```
|
||||
|
||||
1. Copier le fichier `main.py` directement dans le répertoire `/code` (sans répertoire `./app`).
|
||||
|
||||
2. Utiliser `fastapi run` pour servir votre application dans le fichier unique `main.py`.
|
||||
|
||||
Lorsque vous passez le fichier à `fastapi run`, il détectera automatiquement qu'il s'agit d'un fichier unique et non d'un package et saura comment l'importer et servir votre application FastAPI. 😎
|
||||
|
||||
## Concepts de déploiement { #deployment-concepts }
|
||||
|
||||
Parlons à nouveau de certains des mêmes [Concepts de déploiement](concepts.md){.internal-link target=_blank} en termes de conteneurs.
|
||||
|
||||
Les conteneurs sont principalement un outil pour simplifier le processus de **construction et de déploiement** d'une application, mais ils n'imposent pas une approche particulière pour gérer ces **concepts de déploiement**, et il existe plusieurs stratégies possibles.
|
||||
|
||||
La **bonne nouvelle**, c'est qu'avec chaque stratégie différente, il existe un moyen de couvrir tous les concepts de déploiement. 🎉
|
||||
|
||||
Passons en revue ces **concepts de déploiement** en termes de conteneurs :
|
||||
|
||||
* HTTPS
|
||||
* Exécution au démarrage
|
||||
* Redémarrages
|
||||
* Réplication (le nombre de processus en cours d'exécution)
|
||||
* Mémoire
|
||||
* Étapes préalables au démarrage
|
||||
|
||||
## HTTPS { #https }
|
||||
|
||||
Si l'on se concentre uniquement sur l'**image de conteneur** pour une application FastAPI (et plus tard sur le **conteneur** en cours d'exécution), HTTPS serait normalement géré **à l'extérieur** par un autre outil.
|
||||
|
||||
Cela pourrait être un autre conteneur, par exemple avec <a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a>, gérant **HTTPS** et l'acquisition **automatique** des **certificats**.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Traefik s'intègre avec Docker, Kubernetes, et d'autres, donc il est très facile de configurer HTTPS pour vos conteneurs avec lui.
|
||||
|
||||
///
|
||||
|
||||
Alternativement, HTTPS pourrait être géré par un fournisseur cloud comme l'un de leurs services (tout en exécutant l'application dans un conteneur).
|
||||
|
||||
## Exécution au démarrage et redémarrages { #running-on-startup-and-restarts }
|
||||
|
||||
Il y a normalement un autre outil chargé de **démarrer et exécuter** votre conteneur.
|
||||
|
||||
Cela pourrait être **Docker** directement, **Docker Compose**, **Kubernetes**, un **service cloud**, etc.
|
||||
|
||||
Dans la plupart (ou toutes) des situations, il existe une option simple pour activer l'exécution du conteneur au démarrage et activer les redémarrages en cas d'échec. Par exemple, dans Docker, c'est l'option de ligne de commande `--restart`.
|
||||
|
||||
Sans utiliser de conteneurs, faire en sorte que les applications s'exécutent au démarrage et avec redémarrages peut être fastidieux et difficile. Mais en **travaillant avec des conteneurs**, dans la plupart des cas, cette fonctionnalité est incluse par défaut. ✨
|
||||
|
||||
## Réplication - Nombre de processus { #replication-number-of-processes }
|
||||
|
||||
Si vous avez un <abbr title="Un groupe de machines configurées pour être connectées et fonctionner ensemble d'une certaine manière.">cluster</abbr> de machines avec **Kubernetes**, Docker Swarm Mode, Nomad, ou un autre système complexe similaire pour gérer des conteneurs distribués sur plusieurs machines, alors vous voudrez probablement **gérer la réplication** au **niveau du cluster** plutôt que d'utiliser un **gestionnaire de processus** (comme Uvicorn avec workers) dans chaque conteneur.
|
||||
|
||||
L'un de ces systèmes de gestion de conteneurs distribués comme Kubernetes dispose normalement d'une manière intégrée de gérer la **réplication des conteneurs** tout en supportant l'**équilibrage de charge** des requêtes entrantes. Le tout au **niveau du cluster**.
|
||||
|
||||
Dans ces cas, vous voudrez probablement construire une **image Docker à partir de zéro** comme [expliqué ci-dessus](#dockerfile), en installant vos dépendances et en exécutant **un seul processus Uvicorn** au lieu d'utiliser plusieurs workers Uvicorn.
|
||||
|
||||
### Équilibreur de charge { #load-balancer }
|
||||
|
||||
Lors de l'utilisation de conteneurs, vous aurez normalement un composant **à l'écoute sur le port principal**. Cela pourrait être un autre conteneur qui est également un **proxy de terminaison TLS** pour gérer **HTTPS** ou un outil similaire.
|
||||
|
||||
Comme ce composant prend la **charge** des requêtes et la distribue entre les workers de façon (espérons-le) **équilibrée**, on l'appelle également communément un **équilibreur de charge**.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Le même composant de **proxy de terminaison TLS** utilisé pour HTTPS sera probablement aussi un **équilibreur de charge**.
|
||||
|
||||
///
|
||||
|
||||
Et en travaillant avec des conteneurs, le même système que vous utilisez pour les démarrer et les gérer dispose déjà d'outils internes pour transmettre la **communication réseau** (par ex. les requêtes HTTP) depuis cet **équilibreur de charge** (qui peut aussi être un **proxy de terminaison TLS**) vers le ou les conteneurs avec votre application.
|
||||
|
||||
### Un équilibreur de charge - Plusieurs conteneurs worker { #one-load-balancer-multiple-worker-containers }
|
||||
|
||||
Lorsque vous travaillez avec **Kubernetes** ou des systèmes de gestion de conteneurs distribués similaires, l'utilisation de leurs mécanismes réseau internes permet au **seul équilibreur de charge** à l'écoute sur le **port** principal de transmettre la communication (les requêtes) vers potentiellement **plusieurs conteneurs** exécutant votre application.
|
||||
|
||||
Chacun de ces conteneurs exécutant votre application aura normalement **un seul processus** (par ex. un processus Uvicorn exécutant votre application FastAPI). Ils seront tous des **conteneurs identiques**, exécutant la même chose, mais chacun avec son propre processus, sa mémoire, etc. De cette façon, vous profiterez de la **parallélisation** sur **différents cœurs** du CPU, voire sur **différentes machines**.
|
||||
|
||||
Et le système de conteneurs distribués avec l'**équilibreur de charge** **distribuera les requêtes** à chacun des conteneurs exécutant votre application **à tour de rôle**. Ainsi, chaque requête pourrait être traitée par l'un des multiples **conteneurs répliqués** exécutant votre application.
|
||||
|
||||
Et normalement cet **équilibreur de charge** pourra gérer des requêtes qui vont vers *d'autres* applications dans votre cluster (par ex. vers un autre domaine, ou sous un autre préfixe de chemin d'URL), et transmettra cette communication aux bons conteneurs pour *cette autre* application s'exécutant dans votre cluster.
|
||||
|
||||
### Un processus par conteneur { #one-process-per-container }
|
||||
|
||||
Dans ce type de scénario, vous voudrez probablement avoir **un seul processus (Uvicorn) par conteneur**, puisque vous gérez déjà la réplication au niveau du cluster.
|
||||
|
||||
Donc, dans ce cas, vous **ne voudrez pas** avoir plusieurs workers dans le conteneur, par exemple avec l'option de ligne de commande `--workers`. Vous voudrez avoir **un seul processus Uvicorn** par conteneur (mais probablement plusieurs conteneurs).
|
||||
|
||||
Avoir un autre gestionnaire de processus à l'intérieur du conteneur (comme ce serait le cas avec plusieurs workers) n'ajouterait que de la **complexité inutile** que vous gérez très probablement déjà avec votre système de cluster.
|
||||
|
||||
### Conteneurs avec plusieurs processus et cas particuliers { #containers-with-multiple-processes-and-special-cases }
|
||||
|
||||
Bien sûr, il existe des **cas particuliers** où vous pourriez vouloir avoir **un conteneur** avec plusieurs **processus worker Uvicorn** à l'intérieur.
|
||||
|
||||
Dans ces cas, vous pouvez utiliser l'option de ligne de commande `--workers` pour définir le nombre de workers que vous souhaitez exécuter :
|
||||
|
||||
```{ .dockerfile .annotate }
|
||||
FROM python:3.9
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
COPY ./app /code/app
|
||||
|
||||
# (1)!
|
||||
CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"]
|
||||
```
|
||||
|
||||
1. Ici, nous utilisons l'option de ligne de commande `--workers` pour définir le nombre de workers à 4.
|
||||
|
||||
Voici quelques exemples où cela pourrait avoir du sens :
|
||||
|
||||
#### Une application simple { #a-simple-app }
|
||||
|
||||
Vous pourriez vouloir un gestionnaire de processus dans le conteneur si votre application est **suffisamment simple** pour s'exécuter sur un **seul serveur**, pas un cluster.
|
||||
|
||||
#### Docker Compose { #docker-compose }
|
||||
|
||||
Vous pourriez déployer sur un **seul serveur** (pas un cluster) avec **Docker Compose**, donc vous n'auriez pas un moyen simple de gérer la réplication des conteneurs (avec Docker Compose) tout en préservant le réseau partagé et l'**équilibrage de charge**.
|
||||
|
||||
Vous pourriez alors vouloir avoir **un seul conteneur** avec un **gestionnaire de processus** qui démarre **plusieurs processus worker** à l'intérieur.
|
||||
Il est également intégré à Docker. Ainsi, vous pouvez déclarer vos domaines dans les configurations de chaque application et faire en sorte qu'elles lisent ces configurations, génèrent les certificats HTTPS et servent via HTTPS à votre application automatiquement, sans nécessiter aucune modification de leurs configurations.
|
||||
|
||||
---
|
||||
|
||||
L'idée principale est que **rien** de tout cela ne sont des **règles gravées dans la pierre** que vous devez suivre aveuglément. Vous pouvez utiliser ces idées pour **évaluer votre propre cas d'usage** et décider de la meilleure approche pour votre système, en vérifiant comment gérer les concepts suivants :
|
||||
Avec ces informations et ces outils, passez à la section suivante pour tout combiner.
|
||||
|
||||
* Sécurité - HTTPS
|
||||
* Exécution au démarrage
|
||||
* Redémarrages
|
||||
* Réplication (le nombre de processus en cours d'exécution)
|
||||
* Mémoire
|
||||
* Étapes préalables au démarrage
|
||||
## Cluster en mode Docker Swarm avec Traefik et HTTPS
|
||||
|
||||
## Mémoire { #memory }
|
||||
Vous pouvez avoir un cluster en mode Docker Swarm configuré en quelques minutes (environ 20 min) avec un processus Traefik principal gérant HTTPS (y compris l'acquisition et le renouvellement des certificats).
|
||||
|
||||
Si vous exécutez **un seul processus par conteneur**, vous aurez une quantité de mémoire consommée plus ou moins bien définie, stable et limitée par chacun de ces conteneurs (plus d'un s'ils sont répliqués).
|
||||
En utilisant le mode Docker Swarm, vous pouvez commencer par un "cluster" d'une seule machine (il peut même s'agir
|
||||
d'un serveur à 5 USD/mois) et ensuite vous pouvez vous développer autant que vous le souhaitez en ajoutant d'autres serveurs.
|
||||
|
||||
Vous pouvez alors définir ces mêmes limites et exigences de mémoire dans vos configurations pour votre système de gestion de conteneurs (par exemple dans **Kubernetes**). De cette façon, il pourra **répliquer les conteneurs** sur les **machines disponibles** en tenant compte de la quantité de mémoire dont ils ont besoin et de la quantité disponible sur les machines du cluster.
|
||||
Pour configurer un cluster en mode Docker Swarm avec Traefik et la gestion de HTTPS, suivez ce guide :
|
||||
|
||||
Si votre application est **simple**, cela ne sera probablement **pas un problème**, et vous n'aurez peut-être pas besoin de spécifier des limites de mémoire strictes. Mais si vous **utilisez beaucoup de mémoire** (par exemple avec des modèles de **machine learning**), vous devez vérifier combien de mémoire vous consommez et ajuster le **nombre de conteneurs** qui s'exécutent sur **chaque machine** (et peut-être ajouter plus de machines à votre cluster).
|
||||
### <a href="https://medium.com/@tiangolo/docker-swarm-mode-and-traefik-for-a-https-cluster-20328dba6232" class="external-link" target="_blank">Docker Swarm Mode et Traefik pour un cluster HTTPS</a>
|
||||
|
||||
Si vous exécutez **plusieurs processus par conteneur**, vous devez vous assurer que le nombre de processus démarrés ne **consomme pas plus de mémoire** que ce qui est disponible.
|
||||
### Déployer une application FastAPI
|
||||
|
||||
## Étapes préalables au démarrage et conteneurs { #previous-steps-before-starting-and-containers }
|
||||
La façon la plus simple de tout mettre en place, serait d'utiliser les [**Générateurs de projet FastAPI**](../project-generation.md){.internal-link target=_blank}.
|
||||
|
||||
Si vous utilisez des conteneurs (par ex. Docker, Kubernetes), alors il existe deux approches principales que vous pouvez utiliser.
|
||||
Le génerateur de projet adéquat est conçu pour être intégré à ce cluster Docker Swarm avec Traefik et HTTPS décrit ci-dessus.
|
||||
|
||||
### Plusieurs conteneurs { #multiple-containers }
|
||||
Vous pouvez générer un projet en 2 min environ.
|
||||
|
||||
Si vous avez **plusieurs conteneurs**, probablement chacun exécutant un **seul processus** (par exemple, dans un cluster **Kubernetes**), alors vous voudrez probablement avoir un **conteneur séparé** effectuant le travail des **étapes préalables** dans un seul conteneur, exécutant un seul processus, **avant** d'exécuter les conteneurs worker répliqués.
|
||||
|
||||
/// info
|
||||
|
||||
Si vous utilisez Kubernetes, ce sera probablement un <a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/" class="external-link" target="_blank">Init Container</a>.
|
||||
|
||||
///
|
||||
|
||||
Si, dans votre cas d'usage, il n'y a pas de problème à exécuter ces étapes préalables **plusieurs fois en parallèle** (par exemple si vous n'exécutez pas de migrations de base de données, mais vérifiez simplement si la base de données est prête), alors vous pourriez aussi simplement les mettre dans chaque conteneur juste avant de démarrer le processus principal.
|
||||
|
||||
### Un seul conteneur { #single-container }
|
||||
|
||||
Si vous avez une configuration simple, avec **un seul conteneur** qui démarre ensuite plusieurs **processus worker** (ou un seul processus aussi), vous pouvez alors exécuter ces étapes préalables dans le même conteneur, juste avant de démarrer le processus avec l'application.
|
||||
|
||||
### Image Docker de base { #base-docker-image }
|
||||
|
||||
Il existait une image Docker officielle FastAPI : <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>. Mais elle est désormais dépréciée. ⛔️
|
||||
|
||||
Vous ne devriez probablement **pas** utiliser cette image Docker de base (ni aucune autre similaire).
|
||||
|
||||
Si vous utilisez **Kubernetes** (ou autres) et que vous définissez déjà la **réplication** au niveau du cluster, avec plusieurs **conteneurs**. Dans ces cas, il est préférable de **construire une image à partir de zéro** comme décrit ci-dessus : [Construire une image Docker pour FastAPI](#build-a-docker-image-for-fastapi).
|
||||
|
||||
Et si vous devez avoir plusieurs workers, vous pouvez simplement utiliser l'option de ligne de commande `--workers`.
|
||||
|
||||
/// note | Détails techniques
|
||||
|
||||
L'image Docker a été créée à une époque où Uvicorn ne supportait pas la gestion et le redémarrage des workers morts, il fallait donc utiliser Gunicorn avec Uvicorn, ce qui ajoutait pas mal de complexité, uniquement pour que Gunicorn gère et redémarre les processus worker Uvicorn.
|
||||
|
||||
Mais maintenant qu'Uvicorn (et la commande `fastapi`) supporte l'usage de `--workers`, il n'y a plus de raison d'utiliser une image Docker de base au lieu de construire la vôtre (c'est à peu près la même quantité de code 😅).
|
||||
|
||||
///
|
||||
|
||||
## Déployer l'image de conteneur { #deploy-the-container-image }
|
||||
|
||||
Après avoir une image de conteneur (Docker), il existe plusieurs façons de la déployer.
|
||||
|
||||
Par exemple :
|
||||
|
||||
* Avec **Docker Compose** sur un seul serveur
|
||||
* Avec un cluster **Kubernetes**
|
||||
* Avec un cluster Docker Swarm Mode
|
||||
* Avec un autre outil comme Nomad
|
||||
* Avec un service cloud qui prend votre image de conteneur et la déploie
|
||||
|
||||
## Image Docker avec `uv` { #docker-image-with-uv }
|
||||
|
||||
Si vous utilisez <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a> pour installer et gérer votre projet, vous pouvez suivre leur <a href="https://docs.astral.sh/uv/guides/integration/docker/" class="external-link" target="_blank">guide Docker pour uv</a>.
|
||||
|
||||
## Récapitulatif { #recap }
|
||||
|
||||
Avec les systèmes de conteneurs (par ex. avec **Docker** et **Kubernetes**), il devient assez simple de gérer tous les **concepts de déploiement** :
|
||||
|
||||
* HTTPS
|
||||
* Exécution au démarrage
|
||||
* Redémarrages
|
||||
* Réplication (le nombre de processus en cours d'exécution)
|
||||
* Mémoire
|
||||
* Étapes préalables au démarrage
|
||||
|
||||
Dans la plupart des cas, vous ne voudrez probablement pas utiliser d'image de base, et au contraire **construire une image de conteneur à partir de zéro** basée sur l'image Docker Python officielle.
|
||||
|
||||
En prenant soin de l'**ordre** des instructions dans le `Dockerfile` et du **cache Docker**, vous pouvez **minimiser les temps de construction**, maximiser votre productivité (et éviter l'ennui). 😎
|
||||
Le projet généré a des instructions pour le déployer et le faire prend 2 min de plus.
|
||||
|
||||
@@ -1,231 +1,56 @@
|
||||
# À propos de HTTPS { #about-https }
|
||||
# À propos de HTTPS
|
||||
|
||||
Il est facile de supposer que HTTPS est quelque chose qui est simplement « activé » ou non.
|
||||
Il est facile de penser que HTTPS peut simplement être "activé" ou non.
|
||||
|
||||
Mais c'est beaucoup plus complexe que cela.
|
||||
|
||||
/// tip | Astuce
|
||||
/// tip
|
||||
|
||||
Si vous êtes pressé ou si cela ne vous intéresse pas, continuez avec les sections suivantes pour obtenir des instructions étape par étape afin de tout configurer avec différentes techniques.
|
||||
Si vous êtes pressé ou si cela ne vous intéresse pas, passez aux sections suivantes pour obtenir des instructions étape par étape afin de tout configurer avec différentes techniques.
|
||||
|
||||
///
|
||||
|
||||
Pour apprendre les bases du HTTPS, du point de vue d'un utilisateur, consultez <a href="https://howhttps.works/" class="external-link" target="_blank">https://howhttps.works/</a>.
|
||||
Pour apprendre les bases du HTTPS, du point de vue d'un utilisateur, consultez <a href="https://howhttps.works/"
|
||||
class="external-link" target="_blank">https://howhttps.works/</a>.
|
||||
|
||||
Maintenant, du point de vue d'un développeur, voici plusieurs choses à avoir en tête en pensant au HTTPS :
|
||||
|
||||
* Pour le HTTPS, **le serveur** doit **disposer de « certificats »** générés par une **tierce partie**.
|
||||
* Ces certificats sont en réalité **acquis** auprès de la tierce partie, et non « générés ».
|
||||
* Les certificats ont une **durée de vie**.
|
||||
* Ils **expirent**.
|
||||
* Puis ils doivent être **renouvelés**, **acquis à nouveau** auprès de la tierce partie.
|
||||
* Le cryptage de la connexion se fait au **niveau TCP**.
|
||||
* C'est une couche **en dessous de HTTP**.
|
||||
* Donc, la gestion du **certificat et du cryptage** est effectuée **avant HTTP**.
|
||||
* **TCP ne connaît pas les « domaines »**. Il ne connaît que les adresses IP.
|
||||
* L'information sur le **domaine spécifique** demandé se trouve dans les **données HTTP**.
|
||||
* Les **certificats HTTPS** « certifient » un **certain domaine**, mais le protocole et le cryptage se font au niveau TCP, **avant de savoir** quel domaine est traité.
|
||||
* **Par défaut**, cela signifie que vous ne pouvez avoir qu'**un seul certificat HTTPS par adresse IP**.
|
||||
* Quelle que soit la taille de votre serveur ou la petitesse de chacune des applications qu'il contient.
|
||||
* Il existe cependant une **solution** à ce problème.
|
||||
* Il existe une **extension** du protocole **TLS** (celui qui gère le cryptage au niveau TCP, avant HTTP) appelée **<a href="https://en.wikipedia.org/wiki/Server_Name_Indication" class="external-link" target="_blank"><abbr title="Server Name Indication - Indication du nom du serveur">SNI</abbr></a>**.
|
||||
* Cette extension SNI permet à un seul serveur (avec une **seule adresse IP**) d'avoir **plusieurs certificats HTTPS** et de servir **plusieurs domaines/applications HTTPS**.
|
||||
* Pour que cela fonctionne, un **seul** composant (programme) fonctionnant sur le serveur, écoutant sur l'**adresse IP publique**, doit avoir **tous les certificats HTTPS** du serveur.
|
||||
* **Après** l'établissement d'une connexion sécurisée, le protocole de communication est **toujours HTTP**.
|
||||
* Le contenu est **crypté**, même s'il est envoyé avec le **protocole HTTP**.
|
||||
* Pour le HTTPS, le serveur a besoin de "certificats" générés par une tierce partie.
|
||||
* Ces certificats sont en fait acquis auprès de la tierce partie, et non "générés".
|
||||
* Les certificats ont une durée de vie.
|
||||
* Ils expirent.
|
||||
* Puis ils doivent être renouvelés et acquis à nouveau auprès de la tierce partie.
|
||||
* Le cryptage de la connexion se fait au niveau du protocole TCP.
|
||||
* C'est une couche en dessous de HTTP.
|
||||
* Donc, le certificat et le traitement du cryptage sont faits avant HTTP.
|
||||
* TCP ne connaît pas les "domaines", seulement les adresses IP.
|
||||
* L'information sur le domaine spécifique demandé se trouve dans les données HTTP.
|
||||
* Les certificats HTTPS "certifient" un certain domaine, mais le protocole et le cryptage se font au niveau TCP, avant de savoir quel domaine est traité.
|
||||
* Par défaut, cela signifie que vous ne pouvez avoir qu'un seul certificat HTTPS par adresse IP.
|
||||
* Quelle que soit la taille de votre serveur ou la taille de chacune des applications qu'il contient.
|
||||
* Il existe cependant une solution à ce problème.
|
||||
* Il existe une extension du protocole TLS (celui qui gère le cryptage au niveau TCP, avant HTTP) appelée <a
|
||||
href="https://fr.wikipedia.org/wiki/Server_Name_Indication" class="external-link" target="_blank"><abbr
|
||||
title="Server Name Indication (indication du nom du serveur)">SNI (indication du nom du serveur)</abbr></a>.
|
||||
* Cette extension SNI permet à un seul serveur (avec une seule adresse IP) d'avoir plusieurs certificats HTTPS et de servir plusieurs domaines/applications HTTPS.
|
||||
* Pour que cela fonctionne, un seul composant (programme) fonctionnant sur le serveur, écoutant sur l'adresse IP publique, doit avoir tous les certificats HTTPS du serveur.
|
||||
* Après avoir obtenu une connexion sécurisée, le protocole de communication est toujours HTTP.
|
||||
* Le contenu est crypté, même s'il est envoyé avec le protocole HTTP.
|
||||
|
||||
Il est courant d'avoir **un seul programme/serveur HTTP** fonctionnant sur le serveur (la machine, l'hôte, etc.) et **gérant toutes les parties HTTPS** : recevoir les **requêtes HTTPS chiffrées**, envoyer les **requêtes HTTP déchiffrées** à l'application HTTP réelle fonctionnant sur le même serveur (l'application **FastAPI**, dans ce cas), prendre la **réponse HTTP** de l'application, la **chiffrer** en utilisant le **certificat HTTPS** approprié et la renvoyer au client en utilisant **HTTPS**. Ce serveur est souvent appelé un **<a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" class="external-link" target="_blank">Proxy de terminaison TLS</a>**.
|
||||
Il est courant d'avoir un seul programme/serveur HTTP fonctionnant sur le serveur (la machine, l'hôte, etc.) et
|
||||
gérant toutes les parties HTTPS : envoyer les requêtes HTTP décryptées à l'application HTTP réelle fonctionnant sur
|
||||
le même serveur (dans ce cas, l'application **FastAPI**), prendre la réponse HTTP de l'application, la crypter en utilisant le certificat approprié et la renvoyer au client en utilisant HTTPS. Ce serveur est souvent appelé un <a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" class="external-link" target="_blank">Proxy de terminaison TLS</a>.
|
||||
|
||||
Parmi les options que vous pourriez utiliser comme Proxy de terminaison TLS :
|
||||
## Let's Encrypt
|
||||
|
||||
* Traefik (qui peut également gérer les renouvellements de certificats)
|
||||
* Caddy (qui peut également gérer les renouvellements de certificats)
|
||||
* Nginx
|
||||
* HAProxy
|
||||
Avant Let's Encrypt, ces certificats HTTPS étaient vendus par des tiers de confiance.
|
||||
|
||||
## Let's Encrypt { #lets-encrypt }
|
||||
Le processus d'acquisition d'un de ces certificats était auparavant lourd, nécessitait pas mal de paperasses et les certificats étaient assez chers.
|
||||
|
||||
Avant Let's Encrypt, ces **certificats HTTPS** étaient vendus par des tiers de confiance.
|
||||
Mais ensuite, <a href="https://letsencrypt.org/" class="external-link" target="_blank">Let's Encrypt</a> a été créé.
|
||||
|
||||
Le processus d'acquisition de l'un de ces certificats était auparavant lourd, nécessitait pas mal de paperasses et les certificats étaient assez chers.
|
||||
|
||||
Mais ensuite, **<a href="https://letsencrypt.org/" class="external-link" target="_blank">Let's Encrypt</a>** a été créé.
|
||||
|
||||
Il s'agit d'un projet de la Fondation Linux. Il fournit **des certificats HTTPS gratuitement**, de manière automatisée. Ces certificats utilisent toutes les sécurités cryptographiques standard et ont une durée de vie courte (environ 3 mois), de sorte que la **sécurité est en fait meilleure** en raison de leur durée de vie réduite.
|
||||
Il s'agit d'un projet de la Fondation Linux. Il fournit des certificats HTTPS gratuitement. De manière automatisée. Ces certificats utilisent toutes les sécurités cryptographiques standard et ont une durée de vie courte (environ 3 mois), de sorte que la sécurité est en fait meilleure en raison de leur durée de vie réduite.
|
||||
|
||||
Les domaines sont vérifiés de manière sécurisée et les certificats sont générés automatiquement. Cela permet également d'automatiser le renouvellement de ces certificats.
|
||||
|
||||
L'idée est d'automatiser l'acquisition et le renouvellement de ces certificats, afin que vous puissiez disposer d'un **HTTPS sécurisé, gratuitement et pour toujours**.
|
||||
|
||||
## HTTPS pour les développeurs { #https-for-developers }
|
||||
|
||||
Voici un exemple de ce à quoi pourrait ressembler une API HTTPS, étape par étape, en portant principalement attention aux idées importantes pour les développeurs.
|
||||
|
||||
### Nom de domaine { #domain-name }
|
||||
|
||||
Tout commencerait probablement par le fait que vous **acquériez** un **nom de domaine**. Ensuite, vous le configureriez dans un serveur DNS (possiblement le même que votre fournisseur cloud).
|
||||
|
||||
Vous obtiendriez probablement un serveur cloud (une machine virtuelle) ou quelque chose de similaire, et il aurait une adresse IP **publique** <abbr title="Qui ne change pas">fixe</abbr>.
|
||||
|
||||
Dans le ou les serveurs DNS, vous configureriez un enregistrement (un « `A record` ») pour faire pointer **votre domaine** vers l'**adresse IP publique de votre serveur**.
|
||||
|
||||
Vous feriez probablement cela une seule fois, la première fois, lors de la mise en place de l'ensemble.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Cette partie relative au nom de domaine intervient bien avant HTTPS, mais comme tout dépend du domaine et de l'adresse IP, il vaut la peine de la mentionner ici.
|
||||
|
||||
///
|
||||
|
||||
### DNS { #dns }
|
||||
|
||||
Concentrons-nous maintenant sur toutes les parties réellement liées à HTTPS.
|
||||
|
||||
D'abord, le navigateur vérifierait auprès des **serveurs DNS** quelle est l'**IP du domaine**, dans ce cas, `someapp.example.com`.
|
||||
|
||||
Les serveurs DNS indiqueraient au navigateur d'utiliser une **adresse IP** spécifique. Ce serait l'adresse IP publique utilisée par votre serveur, celle que vous avez configurée dans les serveurs DNS.
|
||||
|
||||
<img src="/img/deployment/https/https01.drawio.svg">
|
||||
|
||||
### Début de la négociation TLS (Handshake) { #tls-handshake-start }
|
||||
|
||||
Le navigateur communiquerait ensuite avec cette adresse IP sur le **port 443** (le port HTTPS).
|
||||
|
||||
La première partie de la communication consiste simplement à établir la connexion entre le client et le serveur et à décider des clés cryptographiques qu'ils utiliseront, etc.
|
||||
|
||||
<img src="/img/deployment/https/https02.drawio.svg">
|
||||
|
||||
Cette interaction entre le client et le serveur pour établir la connexion TLS s'appelle la **négociation TLS (TLS handshake)**.
|
||||
|
||||
### TLS avec l'extension SNI { #tls-with-sni-extension }
|
||||
|
||||
**Un seul processus** sur le serveur peut écouter sur un **port** spécifique d'une **adresse IP** spécifique. Il pourrait y avoir d'autres processus écoutant sur d'autres ports de la même adresse IP, mais un seul pour chaque combinaison d'adresse IP et de port.
|
||||
|
||||
TLS (HTTPS) utilise par défaut le port spécifique `443`. C'est donc le port dont nous aurions besoin.
|
||||
|
||||
Comme un seul processus peut écouter sur ce port, le processus qui le ferait serait le **Proxy de terminaison TLS**.
|
||||
|
||||
Le Proxy de terminaison TLS aurait accès à un ou plusieurs **certificats TLS** (certificats HTTPS).
|
||||
|
||||
En utilisant l'**extension SNI** mentionnée plus haut, le Proxy de terminaison TLS vérifierait lequel des certificats TLS (HTTPS) disponibles il devrait utiliser pour cette connexion, en choisissant celui qui correspond au domaine attendu par le client.
|
||||
|
||||
Dans ce cas, il utiliserait le certificat pour `someapp.example.com`.
|
||||
|
||||
<img src="/img/deployment/https/https03.drawio.svg">
|
||||
|
||||
Le client **fait déjà confiance** à l'entité qui a généré ce certificat TLS (dans ce cas Let's Encrypt, mais nous y reviendrons plus tard), il peut donc **vérifier** que le certificat est valide.
|
||||
|
||||
Ensuite, en utilisant le certificat, le client et le Proxy de terminaison TLS **décident comment chiffrer** le reste de la **communication TCP**. Cela termine la partie **négociation TLS**.
|
||||
|
||||
Après cela, le client et le serveur disposent d'une **connexion TCP chiffrée**, c'est ce que fournit TLS. Ils peuvent alors utiliser cette connexion pour démarrer la **communication HTTP** proprement dite.
|
||||
|
||||
Et c'est ce qu'est **HTTPS** : c'est simplement du **HTTP** à l'intérieur d'une **connexion TLS sécurisée** au lieu d'une connexion TCP pure (non chiffrée).
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Remarquez que le cryptage de la communication se produit au **niveau TCP**, pas au niveau HTTP.
|
||||
|
||||
///
|
||||
|
||||
### Requête HTTPS { #https-request }
|
||||
|
||||
Maintenant que le client et le serveur (spécifiquement le navigateur et le Proxy de terminaison TLS) ont une **connexion TCP chiffrée**, ils peuvent démarrer la **communication HTTP**.
|
||||
|
||||
Ainsi, le client envoie une **requête HTTPS**. Ce n'est qu'une requête HTTP à travers une connexion TLS chiffrée.
|
||||
|
||||
<img src="/img/deployment/https/https04.drawio.svg">
|
||||
|
||||
### Déchiffrer la requête { #decrypt-the-request }
|
||||
|
||||
Le Proxy de terminaison TLS utiliserait le chiffrement convenu pour **déchiffrer la requête**, et transmettrait la **requête HTTP en clair (déchiffrée)** au processus exécutant l'application (par exemple un processus avec Uvicorn exécutant l'application FastAPI).
|
||||
|
||||
<img src="/img/deployment/https/https05.drawio.svg">
|
||||
|
||||
### Réponse HTTP { #http-response }
|
||||
|
||||
L'application traiterait la requête et enverrait une **réponse HTTP en clair (non chiffrée)** au Proxy de terminaison TLS.
|
||||
|
||||
<img src="/img/deployment/https/https06.drawio.svg">
|
||||
|
||||
### Réponse HTTPS { #https-response }
|
||||
|
||||
Le Proxy de terminaison TLS **chiffrerait ensuite la réponse** en utilisant la cryptographie convenue auparavant (qui a commencé avec le certificat pour `someapp.example.com`), et la renverrait au navigateur.
|
||||
|
||||
Ensuite, le navigateur vérifierait que la réponse est valide et chiffrée avec la bonne clé cryptographique, etc. Il **déchiffrerait la réponse** et la traiterait.
|
||||
|
||||
<img src="/img/deployment/https/https07.drawio.svg">
|
||||
|
||||
Le client (navigateur) saura que la réponse provient du bon serveur parce qu'elle utilise la cryptographie convenue auparavant à l'aide du **certificat HTTPS**.
|
||||
|
||||
### Applications multiples { #multiple-applications }
|
||||
|
||||
Sur le même serveur (ou les mêmes serveurs), il pourrait y avoir **plusieurs applications**, par exemple d'autres programmes d'API ou une base de données.
|
||||
|
||||
Un seul processus peut gérer l'adresse IP et le port spécifiques (le Proxy de terminaison TLS dans notre exemple), mais les autres applications/processus peuvent également s'exécuter sur le ou les serveurs, tant qu'ils n'essaient pas d'utiliser la même **combinaison d'adresse IP publique et de port**.
|
||||
|
||||
<img src="/img/deployment/https/https08.drawio.svg">
|
||||
|
||||
De cette façon, le Proxy de terminaison TLS pourrait gérer HTTPS et les certificats pour **plusieurs domaines**, pour plusieurs applications, puis transmettre les requêtes à la bonne application dans chaque cas.
|
||||
|
||||
### Renouvellement des certificats { #certificate-renewal }
|
||||
|
||||
À un moment donné dans le futur, chaque certificat **expirerait** (environ 3 mois après son acquisition).
|
||||
|
||||
Ensuite, il y aurait un autre programme (dans certains cas c'est un autre programme, dans d'autres cas cela pourrait être le même Proxy de terminaison TLS) qui communiquerait avec Let's Encrypt et renouvellerait le ou les certificats.
|
||||
|
||||
<img src="/img/deployment/https/https.drawio.svg">
|
||||
|
||||
Les **certificats TLS** sont **associés à un nom de domaine**, pas à une adresse IP.
|
||||
|
||||
Ainsi, pour renouveler les certificats, le programme de renouvellement doit **prouver** à l'autorité (Let's Encrypt) qu'il **« possède » et contrôle ce domaine**.
|
||||
|
||||
Pour ce faire, et pour s'adapter aux différents besoins des applications, il existe plusieurs façons de procéder. Parmi les plus courantes :
|
||||
|
||||
* **Modifier certains enregistrements DNS**.
|
||||
* Pour cela, le programme de renouvellement doit prendre en charge les API du fournisseur DNS ; ainsi, selon le fournisseur DNS que vous utilisez, cela peut être ou non une option.
|
||||
* **S'exécuter comme un serveur** (au moins pendant le processus d'acquisition du certificat) sur l'adresse IP publique associée au domaine.
|
||||
* Comme nous l'avons dit plus haut, un seul processus peut écouter sur une adresse IP et un port spécifiques.
|
||||
* C'est l'une des raisons pour lesquelles il est très utile que le même Proxy de terminaison TLS prenne également en charge le processus de renouvellement des certificats.
|
||||
* Sinon, vous pourriez avoir à arrêter le Proxy de terminaison TLS momentanément, démarrer le programme de renouvellement pour acquérir les certificats, puis les configurer avec le Proxy de terminaison TLS, et ensuite redémarrer le Proxy de terminaison TLS. Ce n'est pas idéal, car votre/vos application(s) ne seront pas disponibles pendant le temps où le Proxy de terminaison TLS est arrêté.
|
||||
|
||||
Tout ce processus de renouvellement, tout en continuant à servir l'application, est l'une des principales raisons pour lesquelles vous voudriez avoir un **système séparé pour gérer HTTPS** avec un Proxy de terminaison TLS, au lieu d'utiliser directement les certificats TLS avec le serveur d'application (par exemple Uvicorn).
|
||||
|
||||
## En-têtes Proxy Forwarded { #proxy-forwarded-headers }
|
||||
|
||||
Lorsque vous utilisez un proxy pour gérer HTTPS, votre **serveur d'application** (par exemple Uvicorn via FastAPI CLI) ne connaît rien du processus HTTPS, il communique en HTTP en clair avec le **Proxy de terminaison TLS**.
|
||||
|
||||
Ce **proxy** définirait normalement certains en-têtes HTTP à la volée avant de transmettre la requête au **serveur d'application**, pour informer le serveur d'application que la requête est **transmise** par le proxy.
|
||||
|
||||
/// note | Détails techniques
|
||||
|
||||
Les en-têtes du proxy sont :
|
||||
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For" class="external-link" target="_blank">X-Forwarded-For</a>
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto" class="external-link" target="_blank">X-Forwarded-Proto</a>
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host" class="external-link" target="_blank">X-Forwarded-Host</a>
|
||||
|
||||
///
|
||||
|
||||
Néanmoins, comme le **serveur d'application** ne sait pas qu'il se trouve derrière un **proxy** de confiance, par défaut, il ne ferait pas confiance à ces en-têtes.
|
||||
|
||||
Mais vous pouvez configurer le **serveur d'application** pour qu'il fasse confiance aux en-têtes transmis (*forwarded*) envoyés par le **proxy**. Si vous utilisez FastAPI CLI, vous pouvez utiliser l'*option CLI* `--forwarded-allow-ips` pour lui indiquer à partir de quelles IP il doit faire confiance à ces en-têtes transmis.
|
||||
|
||||
Par exemple, si le **serveur d'application** ne reçoit des communications que du **proxy** de confiance, vous pouvez définir `--forwarded-allow-ips="*"` pour lui faire faire confiance à toutes les IP entrantes, puisqu'il ne recevra des requêtes que depuis l'IP utilisée par le **proxy**.
|
||||
|
||||
De cette façon, l'application sera en mesure de savoir quelle est sa propre URL publique, si elle utilise HTTPS, le domaine, etc.
|
||||
|
||||
Cela serait utile, par exemple, pour gérer correctement les redirections.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Vous pouvez en savoir plus dans la documentation [Derrière un proxy - Activer les en-têtes transmis par le proxy](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers){.internal-link target=_blank}
|
||||
|
||||
///
|
||||
|
||||
## Récapitulatif { #recap }
|
||||
|
||||
Disposer de **HTTPS** est très important, et assez **critique** dans la plupart des cas. La majeure partie de l'effort que vous, en tant que développeur, devez fournir autour de HTTPS consiste simplement à **comprendre ces concepts** et leur fonctionnement.
|
||||
|
||||
Mais une fois que vous connaissez les informations de base sur **HTTPS pour les développeurs**, vous pouvez facilement combiner et configurer différents outils pour vous aider à tout gérer simplement.
|
||||
|
||||
Dans certains des prochains chapitres, je vous montrerai plusieurs exemples concrets de configuration de **HTTPS** pour des applications **FastAPI**. 🔒
|
||||
L'idée est d'automatiser l'acquisition et le renouvellement de ces certificats, afin que vous puissiez disposer d'un HTTPS sécurisé, gratuitement et pour toujours.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Déploiement { #deployment }
|
||||
# Déploiement
|
||||
|
||||
Le déploiement d'une application **FastAPI** est relativement simple.
|
||||
|
||||
## Que signifie le déploiement { #what-does-deployment-mean }
|
||||
## Que signifie le déploiement
|
||||
|
||||
**Déployer** une application signifie effectuer les étapes nécessaires pour la rendre **disponible pour les
|
||||
utilisateurs**.
|
||||
@@ -14,7 +14,7 @@ l'application efficacement et sans interruption ni problème.
|
||||
Ceci contraste avec les étapes de **développement**, où vous êtes constamment en train de modifier le code, de le casser
|
||||
et de le réparer, d'arrêter et de redémarrer le serveur de développement, _etc._
|
||||
|
||||
## Stratégies de déploiement { #deployment-strategies }
|
||||
## Stratégies de déploiement
|
||||
|
||||
Il existe plusieurs façons de procéder, en fonction de votre cas d'utilisation spécifique et des outils que vous
|
||||
utilisez.
|
||||
@@ -22,8 +22,6 @@ utilisez.
|
||||
Vous pouvez **déployer un serveur** vous-même en utilisant une combinaison d'outils, vous pouvez utiliser un **service
|
||||
cloud** qui fait une partie du travail pour vous, ou encore d'autres options possibles.
|
||||
|
||||
Par exemple, nous, l'équipe derrière FastAPI, avons créé <a href="https://fastapicloud.com" class="external-link" target="_blank">**FastAPI Cloud**</a>, pour rendre le déploiement d'applications FastAPI dans le cloud aussi fluide que possible, avec la même expérience développeur que lorsque vous travaillez avec FastAPI.
|
||||
|
||||
Je vais vous montrer certains des principaux concepts que vous devriez probablement avoir à l'esprit lors du déploiement
|
||||
d'une application **FastAPI** (bien que la plupart de ces concepts s'appliquent à tout autre type d'application web).
|
||||
|
||||
|
||||
@@ -1,82 +1,33 @@
|
||||
# Exécuter un serveur manuellement { #run-a-server-manually }
|
||||
# Exécuter un serveur manuellement - Uvicorn
|
||||
|
||||
## Utiliser la commande `fastapi run` { #use-the-fastapi-run-command }
|
||||
La principale chose dont vous avez besoin pour exécuter une application **FastAPI** sur une machine serveur distante est un programme serveur ASGI tel que **Uvicorn**.
|
||||
|
||||
En bref, utilisez `fastapi run` pour servir votre application FastAPI :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ <font color="#4E9A06">fastapi</font> run <u style="text-decoration-style:solid">main.py</u>
|
||||
|
||||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting production server 🚀
|
||||
|
||||
Searching for package file structure from directories
|
||||
with <font color="#3465A4">__init__.py</font> files
|
||||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with
|
||||
the following code:
|
||||
|
||||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000/docs</u></font>
|
||||
|
||||
Logs:
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>2306215</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C
|
||||
to quit<b>)</b>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Cela fonctionnerait pour la plupart des cas. 😎
|
||||
|
||||
Vous pourriez utiliser cette commande par exemple pour démarrer votre application **FastAPI** dans un conteneur, sur un serveur, etc.
|
||||
|
||||
## Serveurs ASGI { #asgi-servers }
|
||||
|
||||
Allons un peu plus en détail.
|
||||
|
||||
FastAPI utilise un standard pour construire des frameworks web Python et des serveurs appelé <abbr title="Asynchronous Server Gateway Interface - Interface passerelle serveur asynchrone">ASGI</abbr>. FastAPI est un framework web ASGI.
|
||||
|
||||
La principale chose dont vous avez besoin pour exécuter une application **FastAPI** (ou toute autre application ASGI) sur une machine serveur distante est un programme serveur ASGI comme **Uvicorn**, c'est celui utilisé par défaut par la commande `fastapi`.
|
||||
|
||||
Il existe plusieurs alternatives, notamment :
|
||||
Il existe 3 principales alternatives :
|
||||
|
||||
* <a href="https://www.uvicorn.dev/" class="external-link" target="_blank">Uvicorn</a> : un serveur ASGI haute performance.
|
||||
* <a href="https://hypercorn.readthedocs.io/" class="external-link" target="_blank">Hypercorn</a> : un serveur ASGI compatible avec HTTP/2 et Trio entre autres fonctionnalités.
|
||||
* <a href="https://github.com/django/daphne" class="external-link" target="_blank">Daphne</a> : le serveur ASGI conçu pour Django Channels.
|
||||
* <a href="https://github.com/emmett-framework/granian" class="external-link" target="_blank">Granian</a> : un serveur HTTP Rust pour les applications Python.
|
||||
* <a href="https://unit.nginx.org/howto/fastapi/" class="external-link" target="_blank">NGINX Unit</a> : NGINX Unit est un environnement d'exécution d'applications web léger et polyvalent.
|
||||
* <a href="https://hypercorn.readthedocs.io/" class="external-link" target="_blank">Hypercorn</a> : un serveur
|
||||
ASGI compatible avec HTTP/2 et Trio entre autres fonctionnalités.
|
||||
* <a href="https://github.com/django/daphne" class="external-link" target="_blank">Daphne</a> : le serveur ASGI
|
||||
conçu pour Django Channels.
|
||||
|
||||
## Machine serveur et programme serveur { #server-machine-and-server-program }
|
||||
## Machine serveur et programme serveur
|
||||
|
||||
Il y a un petit détail sur les noms à garder à l'esprit. 💡
|
||||
|
||||
Le mot « serveur » est couramment utilisé pour désigner à la fois l'ordinateur distant/cloud (la machine physique ou virtuelle) et également le programme qui s'exécute sur cette machine (par exemple, Uvicorn).
|
||||
Le mot "**serveur**" est couramment utilisé pour désigner à la fois l'ordinateur distant/cloud (la machine physique ou virtuelle) et également le programme qui s'exécute sur cette machine (par exemple, Uvicorn).
|
||||
|
||||
Gardez cela à l'esprit lorsque vous lisez « serveur » en général, cela pourrait faire référence à l'une de ces deux choses.
|
||||
Gardez cela à l'esprit lorsque vous lisez "serveur" en général, cela pourrait faire référence à l'une de ces deux choses.
|
||||
|
||||
Lorsqu'on se réfère à la machine distante, il est courant de l'appeler **serveur**, mais aussi **machine**, **VM** (machine virtuelle), **nœud**. Tout cela fait référence à un type de machine distante, exécutant normalement Linux, sur laquelle vous exécutez des programmes.
|
||||
Lorsqu'on se réfère à la machine distante, il est courant de l'appeler **serveur**, mais aussi **machine**, **VM** (machine virtuelle), **nœud**. Tout cela fait référence à un type de machine distante, exécutant Linux, en règle générale, sur laquelle vous exécutez des programmes.
|
||||
|
||||
## Installer le programme serveur { #install-the-server-program }
|
||||
|
||||
Lorsque vous installez FastAPI, il est fourni avec un serveur de production, Uvicorn, et vous pouvez le démarrer avec la commande `fastapi run`.
|
||||
## Installer le programme serveur
|
||||
|
||||
Mais vous pouvez également installer un serveur ASGI manuellement.
|
||||
Vous pouvez installer un serveur compatible ASGI avec :
|
||||
|
||||
Vous devez créer un [environnement virtuel](../virtual-environments.md){.internal-link target=_blank}, l'activer, puis vous pouvez installer l'application serveur.
|
||||
//// tab | Uvicorn
|
||||
|
||||
Par exemple, pour installer Uvicorn :
|
||||
* <a href="https://www.uvicorn.dev/" class="external-link" target="_blank">Uvicorn</a>, un serveur ASGI rapide comme l'éclair, basé sur uvloop et httptools.
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -88,21 +39,39 @@ $ pip install "uvicorn[standard]"
|
||||
|
||||
</div>
|
||||
|
||||
Un processus similaire s'appliquerait à tout autre programme de serveur ASGI.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
En ajoutant `standard`, Uvicorn va installer et utiliser quelques dépendances supplémentaires recommandées.
|
||||
|
||||
Cela inclut `uvloop`, le remplaçant hautes performances de `asyncio`, qui fournit le gros gain de performance en matière de concurrence.
|
||||
|
||||
Lorsque vous installez FastAPI avec quelque chose comme `pip install "fastapi[standard]"`, vous obtenez déjà `uvicorn[standard]` aussi.
|
||||
Cela inclut `uvloop`, le remplaçant performant de `asyncio`, qui fournit le gros gain de performance en matière de concurrence.
|
||||
|
||||
///
|
||||
|
||||
## Exécuter le programme serveur { #run-the-server-program }
|
||||
////
|
||||
|
||||
Si vous avez installé un serveur ASGI manuellement, vous devrez normalement passer une chaîne d'import dans un format spécial pour qu'il importe votre application FastAPI :
|
||||
//// tab | Hypercorn
|
||||
|
||||
* <a href="https://github.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>, un serveur ASGI également compatible avec HTTP/2.
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install hypercorn
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
...ou tout autre serveur ASGI.
|
||||
|
||||
////
|
||||
|
||||
## Exécutez le programme serveur
|
||||
|
||||
Vous pouvez ensuite exécuter votre application de la même manière que vous l'avez fait dans les tutoriels, mais sans l'option `--reload`, par exemple :
|
||||
|
||||
//// tab | Uvicorn
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -114,44 +83,85 @@ $ uvicorn main:app --host 0.0.0.0 --port 80
|
||||
|
||||
</div>
|
||||
|
||||
/// note | Remarque
|
||||
////
|
||||
|
||||
La commande `uvicorn main:app` fait référence à :
|
||||
//// tab | Hypercorn
|
||||
|
||||
* `main` : le fichier `main.py` (le « module » Python).
|
||||
* `app` : l'objet créé dans `main.py` avec la ligne `app = FastAPI()`.
|
||||
<div class="termy">
|
||||
|
||||
C'est équivalent à :
|
||||
```console
|
||||
$ hypercorn main:app --bind 0.0.0.0:80
|
||||
|
||||
```Python
|
||||
from main import app
|
||||
Running on 0.0.0.0:8080 over http (CTRL + C to quit)
|
||||
```
|
||||
|
||||
///
|
||||
</div>
|
||||
|
||||
Chaque programme de serveur ASGI alternatif aurait une commande similaire, vous pouvez en lire plus dans leur documentation respective.
|
||||
////
|
||||
|
||||
/// warning | Alertes
|
||||
/// warning
|
||||
|
||||
Uvicorn et d'autres serveurs prennent en charge une option `--reload` utile pendant le développement.
|
||||
N'oubliez pas de supprimer l'option `--reload` si vous l'utilisiez.
|
||||
|
||||
L'option `--reload` consomme beaucoup plus de ressources, est plus instable, etc.
|
||||
L'option `--reload` consomme beaucoup plus de ressources, est plus instable, etc.
|
||||
|
||||
Cela aide beaucoup pendant le **développement**, mais vous **ne devriez pas** l'utiliser en **production**.
|
||||
Cela aide beaucoup pendant le **développement**, mais vous **ne devriez pas** l'utiliser en **production**.
|
||||
|
||||
///
|
||||
|
||||
## Concepts de déploiement { #deployment-concepts }
|
||||
## Hypercorn avec Trio
|
||||
|
||||
Ces exemples exécutent le programme serveur (par exemple Uvicorn), en démarrant **un seul processus**, à l'écoute sur toutes les IP (`0.0.0.0`) sur un port prédéfini (par exemple `80`).
|
||||
Starlette et **FastAPI** sont basés sur
|
||||
<a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>, qui les rend
|
||||
compatibles avec <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a>, de la bibliothèque standard Python et
|
||||
<a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a>.
|
||||
|
||||
C'est l'idée de base. Mais vous voudrez probablement vous occuper de certaines choses supplémentaires, comme :
|
||||
Néanmoins, Uvicorn n'est actuellement compatible qu'avec asyncio, et il utilise normalement <a href="https://github.
|
||||
com/MagicStack/uvloop" class="external-link" target="_blank">`uvloop`</a >, le remplaçant hautes performances de `asyncio`.
|
||||
|
||||
* Sécurité - HTTPS
|
||||
* Exécution au démarrage
|
||||
* Redémarrages
|
||||
* Réplication (le nombre de processus en cours d'exécution)
|
||||
* Mémoire
|
||||
* Étapes précédant le démarrage
|
||||
Mais si vous souhaitez utiliser directement **Trio**, vous pouvez utiliser **Hypercorn** car il le prend en charge. ✨
|
||||
|
||||
Je vous en dirai plus sur chacun de ces concepts, sur la manière d'y réfléchir, et donnerai quelques exemples concrets avec des stratégies pour les gérer dans les prochains chapitres. 🚀
|
||||
### Installer Hypercorn avec Trio
|
||||
|
||||
Vous devez d'abord installer Hypercorn avec le support Trio :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install "hypercorn[trio]"
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### Exécuter avec Trio
|
||||
|
||||
Ensuite, vous pouvez passer l'option de ligne de commande `--worker-class` avec la valeur `trio` :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ hypercorn main:app --worker-class trio
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Et cela démarrera Hypercorn avec votre application en utilisant Trio comme backend.
|
||||
|
||||
Vous pouvez désormais utiliser Trio en interne dans votre application. Ou mieux encore, vous pouvez utiliser AnyIO pour que votre code reste compatible avec Trio et asyncio. 🎉
|
||||
|
||||
## Concepts de déploiement
|
||||
|
||||
Ces exemples lancent le programme serveur (e.g. Uvicorn), démarrant **un seul processus**, sur toutes les IPs (`0.0.
|
||||
0.0`) sur un port prédéfini (par example, `80`).
|
||||
|
||||
C'est l'idée de base. Mais vous vous préoccuperez probablement de certains concepts supplémentaires, tels que ... :
|
||||
|
||||
* la sécurité - HTTPS
|
||||
* l'exécution au démarrage
|
||||
* les redémarrages
|
||||
* la réplication (le nombre de processus en cours d'exécution)
|
||||
* la mémoire
|
||||
* les étapes précédant le démarrage
|
||||
|
||||
Je vous en dirai plus sur chacun de ces concepts, sur la façon de les aborder, et donnerai quelques exemples concrets avec des stratégies pour les traiter dans les prochains chapitres. 🚀
|
||||
|
||||
@@ -1,93 +1,101 @@
|
||||
# À propos des versions de FastAPI { #about-fastapi-versions }
|
||||
# À propos des versions de FastAPI
|
||||
|
||||
**FastAPI** est déjà utilisé en production dans de nombreuses applications et de nombreux systèmes. Et la couverture de tests est maintenue à 100 %. Mais son développement avance toujours rapidement.
|
||||
**FastAPI** est déjà utilisé en production dans de nombreuses applications et systèmes. Et la couverture de test est maintenue à 100 %. Mais son développement est toujours aussi rapide.
|
||||
|
||||
De nouvelles fonctionnalités sont ajoutées fréquemment, des bogues sont corrigés régulièrement et le code s'améliore continuellement.
|
||||
De nouvelles fonctionnalités sont ajoutées fréquemment, des bogues sont corrigés régulièrement et le code est
|
||||
amélioré continuellement.
|
||||
|
||||
C'est pourquoi les versions actuelles sont toujours `0.x.x`, cela reflète que chaque version pourrait potentiellement comporter des changements non rétrocompatibles. Cela suit les conventions de <a href="https://semver.org/" class="external-link" target="_blank">versionnage sémantique</a>.
|
||||
C'est pourquoi les versions actuelles sont toujours `0.x.x`, cela reflète que chaque version peut potentiellement
|
||||
recevoir des changements non rétrocompatibles. Cela suit les conventions de <a href="https://semver.org/" class="external-link"
|
||||
target="_blank">versionnage sémantique</a>.
|
||||
|
||||
Vous pouvez créer des applications de production avec **FastAPI** dès maintenant (et vous le faites probablement depuis un certain temps), vous devez juste vous assurer que vous utilisez une version qui fonctionne correctement avec le reste de votre code.
|
||||
|
||||
## Épingler votre version de `fastapi` { #pin-your-fastapi-version }
|
||||
## Épinglez votre version de `fastapi`
|
||||
|
||||
La première chose que vous devez faire est « épingler » la version de **FastAPI** que vous utilisez à la dernière version spécifique dont vous savez qu’elle fonctionne correctement pour votre application.
|
||||
Tout d'abord il faut "épingler" la version de **FastAPI** que vous utilisez à la dernière version dont vous savez
|
||||
qu'elle fonctionne correctement pour votre application.
|
||||
|
||||
Par exemple, disons que vous utilisez la version `0.112.0` dans votre application.
|
||||
Par exemple, disons que vous utilisez la version `0.45.0` dans votre application.
|
||||
|
||||
Si vous utilisez un fichier `requirements.txt`, vous pouvez spécifier la version avec :
|
||||
Si vous utilisez un fichier `requirements.txt`, vous pouvez spécifier la version avec :
|
||||
|
||||
```txt
|
||||
fastapi[standard]==0.112.0
|
||||
fastapi==0.45.0
|
||||
```
|
||||
|
||||
ce qui signifierait que vous utiliseriez exactement la version `0.112.0`.
|
||||
ce qui signifierait que vous utiliseriez exactement la version `0.45.0`.
|
||||
|
||||
Ou vous pourriez aussi l'épingler avec :
|
||||
|
||||
```txt
|
||||
fastapi[standard]>=0.112.0,<0.113.0
|
||||
```
|
||||
|
||||
cela signifierait que vous utiliseriez les versions `0.112.0` ou supérieures, mais inférieures à `0.113.0`, par exemple, une version `0.112.2` serait toujours acceptée.
|
||||
|
||||
Si vous utilisez un autre outil pour gérer vos installations, comme `uv`, Poetry, Pipenv, ou autres, ils ont tous un moyen que vous pouvez utiliser pour définir des versions spécifiques pour vos paquets.
|
||||
|
||||
## Versions disponibles { #available-versions }
|
||||
|
||||
Vous pouvez consulter les versions disponibles (par exemple, pour vérifier quelle est la dernière version en date) dans les [Notes de version](../release-notes.md){.internal-link target=_blank}.
|
||||
|
||||
## À propos des versions { #about-versions }
|
||||
|
||||
Suivant les conventions de versionnage sémantique, toute version inférieure à `1.0.0` peut potentiellement ajouter des changements non rétrocompatibles.
|
||||
|
||||
FastAPI suit également la convention selon laquelle tout changement de version « PATCH » concerne des corrections de bogues et des changements rétrocompatibles.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Le « PATCH » est le dernier chiffre, par exemple, dans `0.2.3`, la version PATCH est `3`.
|
||||
|
||||
///
|
||||
|
||||
Donc, vous devriez être en mesure d'épingler une version comme suit :
|
||||
Ou vous pourriez aussi l'épingler avec :
|
||||
|
||||
```txt
|
||||
fastapi>=0.45.0,<0.46.0
|
||||
```
|
||||
|
||||
Les changements non rétrocompatibles et les nouvelles fonctionnalités sont ajoutés dans les versions « MINOR ».
|
||||
cela signifierait que vous utiliseriez les versions `0.45.0` ou supérieures, mais inférieures à `0.46.0`, par exemple, une version `0.45.2` serait toujours acceptée.
|
||||
|
||||
Si vous utilisez un autre outil pour gérer vos installations, comme Poetry, Pipenv, ou autres, ils ont tous un moyen que vous pouvez utiliser pour définir des versions spécifiques pour vos paquets.
|
||||
|
||||
## Versions disponibles
|
||||
|
||||
Vous pouvez consulter les versions disponibles (par exemple, pour vérifier quelle est la dernière version en date) dans les [Notes de version](../release-notes.md){.internal-link target=_blank}.
|
||||
|
||||
## À propos des versions
|
||||
|
||||
Suivant les conventions de versionnage sémantique, toute version inférieure à `1.0.0` peut potentiellement ajouter
|
||||
des changements non rétrocompatibles.
|
||||
|
||||
FastAPI suit également la convention que tout changement de version "PATCH" est pour des corrections de bogues et
|
||||
des changements rétrocompatibles.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Le « MINOR » est le numéro au milieu, par exemple, dans `0.2.3`, la version MINOR est `2`.
|
||||
Le "PATCH" est le dernier chiffre, par exemple, dans `0.2.3`, la version PATCH est `3`.
|
||||
|
||||
///
|
||||
|
||||
## Mettre à niveau les versions de FastAPI { #upgrading-the-fastapi-versions }
|
||||
Donc, vous devriez être capable d'épingler une version comme suit :
|
||||
|
||||
Vous devez ajouter des tests pour votre application.
|
||||
```txt
|
||||
fastapi>=0.45.0,<0.46.0
|
||||
```
|
||||
|
||||
Avec **FastAPI** c'est très facile (merci à Starlette), consultez les documents : [Tests](../tutorial/testing.md){.internal-link target=_blank}
|
||||
Les changements non rétrocompatibles et les nouvelles fonctionnalités sont ajoutés dans les versions "MINOR".
|
||||
|
||||
Après avoir des tests, vous pouvez mettre à niveau la version de **FastAPI** vers une version plus récente et vous assurer que tout votre code fonctionne correctement en exécutant vos tests.
|
||||
/// tip | Astuce
|
||||
|
||||
Si tout fonctionne, ou après avoir effectué les changements nécessaires, et que tous vos tests passent, vous pouvez alors épingler votre `fastapi` à cette nouvelle version récente.
|
||||
Le "MINOR" est le numéro au milieu, par exemple, dans `0.2.3`, la version MINOR est `2`.
|
||||
|
||||
## À propos de Starlette { #about-starlette }
|
||||
///
|
||||
|
||||
Vous ne devez pas épingler la version de `starlette`.
|
||||
## Mise à jour des versions FastAPI
|
||||
|
||||
Vous devriez tester votre application.
|
||||
|
||||
Avec **FastAPI** c'est très facile (merci à Starlette), consultez la documentation : [Testing](../tutorial/testing.md){.internal-link target=_blank}
|
||||
|
||||
Après avoir effectué des tests, vous pouvez mettre à jour la version **FastAPI** vers une version plus récente, et vous assurer que tout votre code fonctionne correctement en exécutant vos tests.
|
||||
|
||||
Si tout fonctionne, ou après avoir fait les changements nécessaires, et que tous vos tests passent, vous pouvez
|
||||
épingler votre version de `fastapi` à cette nouvelle version récente.
|
||||
|
||||
## À propos de Starlette
|
||||
|
||||
Vous ne devriez pas épingler la version de `starlette`.
|
||||
|
||||
Différentes versions de **FastAPI** utiliseront une version spécifique plus récente de Starlette.
|
||||
|
||||
Ainsi, vous pouvez simplement laisser **FastAPI** utiliser la bonne version de Starlette.
|
||||
|
||||
## À propos de Pydantic { #about-pydantic }
|
||||
## À propos de Pydantic
|
||||
|
||||
Pydantic inclut les tests pour **FastAPI** avec ses propres tests, ainsi les nouvelles versions de Pydantic (au-dessus de `1.0.0`) sont toujours compatibles avec FastAPI.
|
||||
Pydantic inclut des tests pour **FastAPI** avec ses propres tests, ainsi les nouvelles versions de Pydantic (au-dessus
|
||||
de `1.0.0`) sont toujours compatibles avec **FastAPI**.
|
||||
|
||||
Vous pouvez épingler Pydantic à toute version supérieure à `1.0.0` qui fonctionne pour vous.
|
||||
Vous pouvez épingler Pydantic à toute version supérieure à `1.0.0` qui fonctionne pour vous et inférieure à `2.0.0`.
|
||||
|
||||
Par exemple :
|
||||
Par exemple :
|
||||
|
||||
```txt
|
||||
pydantic>=2.7.0,<3.0.0
|
||||
pydantic>=1.2.0,<2.0.0
|
||||
```
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# FastAPI { #fastapi }
|
||||
# FastAPI
|
||||
|
||||
<style>
|
||||
.md-content .md-typeset h1 { display: none; }
|
||||
</style>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://fastapi.tiangolo.com/fr"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
|
||||
<a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<em>Framework FastAPI, haute performance, facile à apprendre, rapide à coder, prêt pour la production</em>
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
---
|
||||
|
||||
**Documentation** : <a href="https://fastapi.tiangolo.com/fr" target="_blank">https://fastapi.tiangolo.com/fr</a>
|
||||
**Documentation** : <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a>
|
||||
|
||||
**Code Source** : <a href="https://github.com/fastapi/fastapi" target="_blank">https://github.com/fastapi/fastapi</a>
|
||||
|
||||
@@ -37,130 +37,128 @@ FastAPI est un framework web moderne et rapide (haute performance) pour la créa
|
||||
|
||||
Les principales fonctionnalités sont :
|
||||
|
||||
* **Rapide** : très hautes performances, au niveau de **NodeJS** et **Go** (grâce à Starlette et Pydantic). [L'un des frameworks Python les plus rapides](#performance).
|
||||
* **Rapide à coder** : augmente la vitesse de développement des fonctionnalités d'environ 200 % à 300 %. *
|
||||
* **Moins de bugs** : réduit d'environ 40 % les erreurs induites par le développeur. *
|
||||
* **Intuitif** : excellente compatibilité avec les éditeurs. <abbr title="également appelé autocomplétion, IntelliSense">Autocomplétion</abbr> partout. Moins de temps passé à déboguer.
|
||||
* **Facile** : conçu pour être facile à utiliser et à apprendre. Moins de temps passé à lire les documents.
|
||||
* **Concis** : diminue la duplication de code. Plusieurs fonctionnalités à partir de chaque déclaration de paramètre. Moins de bugs.
|
||||
* **Robuste** : obtenez un code prêt pour la production. Avec une documentation interactive automatique.
|
||||
* **Basé sur des normes** : basé sur (et entièrement compatible avec) les standards ouverts pour les APIs : <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (précédemment connu sous le nom de Swagger) et <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
|
||||
* **Rapidité** : De très hautes performances, au niveau de **NodeJS** et **Go** (grâce à Starlette et Pydantic). [L'un des frameworks Python les plus rapides](#performance).
|
||||
* **Rapide à coder** : Augmente la vitesse de développement des fonctionnalités d'environ 200 % à 300 %. *
|
||||
* **Moins de bugs** : Réduit d'environ 40 % les erreurs induites par le développeur. *
|
||||
* **Intuitif** : Excellente compatibilité avec les IDE. <abbr title="également connu sous le nom d'auto-complétion, autocomplétion, IntelliSense">Complétion</abbr> complète. Moins de temps passé à déboguer.
|
||||
* **Facile** : Conçu pour être facile à utiliser et à apprendre. Moins de temps passé à lire la documentation.
|
||||
* **Concis** : Diminue la duplication de code. De nombreuses fonctionnalités liées à la déclaration de chaque paramètre. Moins de bugs.
|
||||
* **Robuste** : Obtenez un code prêt pour la production. Avec une documentation interactive automatique.
|
||||
* **Basé sur des normes** : Basé sur (et entièrement compatible avec) les standards ouverts pour les APIs : <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (précédemment connu sous le nom de Swagger) et <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
|
||||
|
||||
<small>* estimation basée sur des tests d'une équipe de développement interne, construisant des applications de production.</small>
|
||||
|
||||
## Sponsors { #sponsors }
|
||||
## Sponsors
|
||||
|
||||
<!-- sponsors -->
|
||||
|
||||
### Sponsor clé de voûte { #keystone-sponsor }
|
||||
|
||||
{% for sponsor in sponsors.keystone -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
|
||||
{% endfor -%}
|
||||
|
||||
### Sponsors Or et Argent { #gold-and-silver-sponsors }
|
||||
|
||||
{% if sponsors %}
|
||||
{% for sponsor in sponsors.gold -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
|
||||
{% endfor -%}
|
||||
{%- for sponsor in sponsors.silver -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<!-- /sponsors -->
|
||||
|
||||
<a href="https://fastapi.tiangolo.com/fr/fastapi-people/#sponsors" class="external-link" target="_blank">Autres sponsors</a>
|
||||
<a href="https://fastapi.tiangolo.com/fastapi-people/#sponsors" class="external-link" target="_blank">Other sponsors</a>
|
||||
|
||||
## Opinions { #opinions }
|
||||
## Opinions
|
||||
|
||||
« _[...] J'utilise beaucoup **FastAPI** ces derniers temps. [...] Je prévois de l'utiliser dans mon équipe pour tous les **services de ML chez Microsoft**. Certains d'entre eux sont intégrés au cœur de **Windows** et à certains produits **Office**._ »
|
||||
"_[...] J'utilise beaucoup **FastAPI** ces derniers temps. [...] Je prévois de l'utiliser dans mon équipe pour tous les **services de ML chez Microsoft**. Certains d'entre eux seront intégrés dans le coeur de **Windows** et dans certains produits **Office**._"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Kabir Khan - <strong>Microsoft</strong> <a href="https://github.com/fastapi/fastapi/pull/26" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
« _Nous avons adopté la bibliothèque **FastAPI** pour créer un serveur **REST** qui peut être interrogé pour obtenir des **prédictions**. [pour Ludwig]_ »
|
||||
"_Nous avons adopté la bibliothèque **FastAPI** pour créer un serveur **REST** qui peut être interrogé pour obtenir des **prédictions**. [pour Ludwig]_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, et Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
|
||||
<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin et Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
« _**Netflix** est heureux d'annoncer la publication en open source de notre framework d'orchestration de **gestion de crise** : **Dispatch** ! [construit avec **FastAPI**]_ »
|
||||
"_**Netflix** a le plaisir d'annoncer la sortie en open-source de notre framework d'orchestration de **gestion de crise** : **Dispatch** ! [construit avec **FastAPI**]_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href="https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
« _Je suis plus qu'enthousiaste à propos de **FastAPI**. C'est tellement fun !_ »
|
||||
"_Je suis très enthousiaste à propos de **FastAPI**. C'est un bonheur !_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong>Animateur du podcast <a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a></strong> <a href="https://x.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
|
||||
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong>Auteur du podcast <a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a></strong> <a href="https://x.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
« _Honnêtement, ce que vous avez construit a l'air super solide et soigné. À bien des égards, c'est ce que je voulais que **Hug** soit — c'est vraiment inspirant de voir quelqu'un construire ça._ »
|
||||
"_Honnêtement, ce que vous avez construit a l'air super solide et élégant. A bien des égards, c'est comme ça que je voulais que **Hug** soit - c'est vraiment inspirant de voir quelqu'un construire ça._"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong>Créateur de <a href="https://github.com/hugapi/hug" target="_blank">Hug</a></strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
|
||||
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong> Créateur de <a href="https://github.com/hugapi/hug" target="_blank">Hug</a></strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
« _Si vous cherchez à apprendre un **framework moderne** pour créer des APIs REST, regardez **FastAPI** [...] C'est rapide, facile à utiliser et facile à apprendre [...]_ »
|
||||
"_Si vous cherchez à apprendre un **framework moderne** pour créer des APIs REST, regardez **FastAPI** [...] C'est rapide, facile à utiliser et à apprendre [...]_"
|
||||
|
||||
« _Nous sommes passés à **FastAPI** pour nos **APIs** [...] Je pense que vous l'aimerez [...]_ »
|
||||
"_Nous sommes passés à **FastAPI** pour nos **APIs** [...] Je pense que vous l'aimerez [...]_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong>Fondateurs de <a href="https://explosion.ai" target="_blank">Explosion AI</a> - Créateurs de <a href="https://spacy.io" target="_blank">spaCy</a></strong> <a href="https://x.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://x.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
« _Si quelqu'un cherche à construire une API Python de production, je recommande vivement **FastAPI**. Il est **magnifiquement conçu**, **simple à utiliser** et **hautement scalable**. Il est devenu un **composant clé** de notre stratégie de développement API-first et alimente de nombreuses automatisations et services tels que notre ingénieur TAC virtuel._ »
|
||||
"_Si quelqu'un cherche à construire une API Python de production, je recommande vivement **FastAPI**. Il est **bien conçu**, **simple à utiliser** et **très évolutif**. Il est devenu un **composant clé** dans notre stratégie de développement API first et il est à l'origine de nombreux automatismes et services tels que notre ingénieur virtuel TAC._"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Deon Pillsbury - <strong>Cisco</strong> <a href="https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
## Mini documentaire FastAPI { #fastapi-mini-documentary }
|
||||
|
||||
Un <a href="https://www.youtube.com/watch?v=mpR8ngthqiE" class="external-link" target="_blank">mini documentaire FastAPI</a> est sorti fin 2025, vous pouvez le regarder en ligne :
|
||||
|
||||
<a href="https://www.youtube.com/watch?v=mpR8ngthqiE" target="_blank"><img src="https://fastapi.tiangolo.com/img/fastapi-documentary.jpg" alt="FastAPI Mini Documentary"></a>
|
||||
|
||||
## **Typer**, le FastAPI des CLIs { #typer-the-fastapi-of-clis }
|
||||
## **Typer**, le FastAPI des <abbr title="Command Line Interface">CLI</abbr>
|
||||
|
||||
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
|
||||
|
||||
Si vous construisez une application <abbr title="Command Line Interface - Interface en ligne de commande">CLI</abbr> à utiliser dans un terminal au lieu d'une API web, regardez <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
|
||||
Si vous souhaitez construire une application <abbr title="Command Line Interface">CLI</abbr> utilisable dans un terminal au lieu d'une API web, regardez <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
|
||||
|
||||
**Typer** est le petit frère de FastAPI. Et il est destiné à être le **FastAPI des CLIs**. ⌨️ 🚀
|
||||
**Typer** est le petit frère de FastAPI. Et il est destiné à être le **FastAPI des <abbr title="Command Line Interface">CLI</abbr>**. ⌨️ 🚀
|
||||
|
||||
## Prérequis { #requirements }
|
||||
## Prérequis
|
||||
|
||||
FastAPI repose sur les épaules de géants :
|
||||
|
||||
* <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a> pour les parties web.
|
||||
* <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> pour les parties données.
|
||||
|
||||
## Installation { #installation }
|
||||
|
||||
Créez et activez un <a href="https://fastapi.tiangolo.com/fr/virtual-environments/" class="external-link" target="_blank">environnement virtuel</a> puis installez FastAPI :
|
||||
## Installation
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install "fastapi[standard]"
|
||||
$ pip install fastapi
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
**Remarque** : Vous devez vous assurer de mettre « fastapi[standard] » entre guillemets pour garantir que cela fonctionne dans tous les terminaux.
|
||||
Vous aurez également besoin d'un serveur ASGI pour la production tel que <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a> ou <a href="https://github.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>.
|
||||
|
||||
## Exemple { #example }
|
||||
<div class="termy">
|
||||
|
||||
### Créer { #create-it }
|
||||
```console
|
||||
$ pip install "uvicorn[standard]"
|
||||
|
||||
Créez un fichier `main.py` avec :
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Exemple
|
||||
|
||||
### Créez
|
||||
|
||||
* Créez un fichier `main.py` avec :
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -172,16 +170,18 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
<details markdown="1">
|
||||
<summary>Ou utilisez <code>async def</code>...</summary>
|
||||
<summary>Ou utilisez <code>async def</code> ...</summary>
|
||||
|
||||
Si votre code utilise `async` / `await`, utilisez `async def` :
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -193,41 +193,28 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: str | None = None):
|
||||
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
**Remarque** :
|
||||
**Note**
|
||||
|
||||
Si vous ne savez pas, consultez la section « Vous êtes pressés ? » à propos de <a href="https://fastapi.tiangolo.com/fr/async/#in-a-hurry" target="_blank">`async` et `await` dans la documentation</a>.
|
||||
Si vous n'êtes pas familier avec cette notion, consultez la section _"Vous êtes pressés ?"_ à propos de <a href="https://fastapi.tiangolo.com/fr/async/#vous-etes-presses" target="_blank">`async` et `await` dans la documentation</a>.
|
||||
|
||||
</details>
|
||||
|
||||
### Lancer { #run-it }
|
||||
### Lancez
|
||||
|
||||
Lancez le serveur avec :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi dev main.py
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
╭────────── FastAPI CLI - Development mode ───────────╮
|
||||
│ │
|
||||
│ Serving at: http://127.0.0.1:8000 │
|
||||
│ │
|
||||
│ API docs: http://127.0.0.1:8000/docs │
|
||||
│ │
|
||||
│ Running in development mode, for production use: │
|
||||
│ │
|
||||
│ fastapi run │
|
||||
│ │
|
||||
╰─────────────────────────────────────────────────────╯
|
||||
|
||||
INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
|
||||
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
INFO: Started reloader process [2248755] using WatchFiles
|
||||
INFO: Started server process [2248757]
|
||||
INFO: Started reloader process [28720]
|
||||
INFO: Started server process [28722]
|
||||
INFO: Waiting for application startup.
|
||||
INFO: Application startup complete.
|
||||
```
|
||||
@@ -235,34 +222,34 @@ INFO: Application startup complete.
|
||||
</div>
|
||||
|
||||
<details markdown="1">
|
||||
<summary>À propos de la commande <code>fastapi dev main.py</code>...</summary>
|
||||
<summary>À propos de la commande <code>uvicorn main:app --reload</code> ...</summary>
|
||||
|
||||
La commande `fastapi dev` lit votre fichier `main.py`, détecte l'application **FastAPI** qu'il contient et lance un serveur avec <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a>.
|
||||
La commande `uvicorn main:app` fait référence à :
|
||||
|
||||
Par défaut, `fastapi dev` démarre avec le rechargement automatique activé pour le développement local.
|
||||
|
||||
Vous pouvez en savoir plus dans la <a href="https://fastapi.tiangolo.com/fr/fastapi-cli/" target="_blank">documentation de la CLI FastAPI</a>.
|
||||
* `main` : le fichier `main.py` (le "module" Python).
|
||||
* `app` : l'objet créé à l'intérieur de `main.py` avec la ligne `app = FastAPI()`.
|
||||
* `--reload` : fait redémarrer le serveur après des changements de code. À n'utiliser que pour le développement.
|
||||
|
||||
</details>
|
||||
|
||||
### Vérifier { #check-it }
|
||||
### Vérifiez
|
||||
|
||||
Ouvrez votre navigateur à l'adresse <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
|
||||
|
||||
Vous verrez la réponse JSON :
|
||||
Vous obtenez alors cette réponse <abbr title="JavaScript Object Notation">JSON</abbr> :
|
||||
|
||||
```JSON
|
||||
{"item_id": 5, "q": "somequery"}
|
||||
```
|
||||
|
||||
Vous avez déjà créé une API qui :
|
||||
Vous venez de créer une API qui :
|
||||
|
||||
* Reçoit des requêtes HTTP sur les _chemins_ `/` et `/items/{item_id}`.
|
||||
* Les deux _chemins_ acceptent des <em>opérations</em> `GET` (également connues sous le nom de _méthodes_ HTTP).
|
||||
* Le _chemin_ `/items/{item_id}` a un _paramètre de chemin_ `item_id` qui doit être un `int`.
|
||||
* Le _chemin_ `/items/{item_id}` a un _paramètre de requête_ optionnel `q` de type `str`.
|
||||
* Reçoit les requêtes HTTP pour les _chemins_ `/` et `/items/{item_id}`.
|
||||
* Les deux _chemins_ acceptent des <em>opérations</em> `GET` (également connu sous le nom de _méthodes_ HTTP).
|
||||
* Le _chemin_ `/items/{item_id}` a un _<abbr title="en anglais : path parameter">paramètre</abbr>_ `item_id` qui doit être un `int`.
|
||||
* Le _chemin_ `/items/{item_id}` a un _<abbr title="en anglais : query param">paramètre de requête</abbr>_ optionnel `q` de type `str`.
|
||||
|
||||
### Documentation API interactive { #interactive-api-docs }
|
||||
### Documentation API interactive
|
||||
|
||||
Maintenant, rendez-vous sur <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
@@ -270,21 +257,23 @@ Vous verrez la documentation interactive automatique de l'API (fournie par <a hr
|
||||
|
||||

|
||||
|
||||
### Documentation API alternative { #alternative-api-docs }
|
||||
### Documentation API alternative
|
||||
|
||||
Et maintenant, rendez-vous sur <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
|
||||
|
||||
Vous verrez la documentation alternative automatique (fournie par <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>) :
|
||||
Vous verrez la documentation interactive automatique de l'API (fournie par <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>) :
|
||||
|
||||

|
||||
|
||||
## Mettre à niveau l'exemple { #example-upgrade }
|
||||
## Exemple plus poussé
|
||||
|
||||
Modifiez maintenant le fichier `main.py` pour recevoir un corps depuis une requête `PUT`.
|
||||
Maintenant, modifiez le fichier `main.py` pour recevoir <abbr title="en anglais : body">le corps</abbr> d'une requête `PUT`.
|
||||
|
||||
Déclarez le corps en utilisant les types Python standard, grâce à Pydantic.
|
||||
Déclarez ce corps en utilisant les types Python standards, grâce à Pydantic.
|
||||
|
||||
```Python hl_lines="4 9-12 25-27"
|
||||
from typing import Union
|
||||
|
||||
```Python hl_lines="2 7-10 23-25"
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -294,7 +283,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: bool | None = None
|
||||
is_offer: Union[bool, None] = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -303,7 +292,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
@@ -312,35 +301,35 @@ def update_item(item_id: int, item: Item):
|
||||
return {"item_name": item.name, "item_id": item_id}
|
||||
```
|
||||
|
||||
Le serveur `fastapi dev` devrait se recharger automatiquement.
|
||||
Le serveur se recharge normalement automatiquement (car vous avez pensé à `--reload` dans la commande `uvicorn` ci-dessus).
|
||||
|
||||
### Mettre à niveau la documentation API interactive { #interactive-api-docs-upgrade }
|
||||
### Plus loin avec la documentation API interactive
|
||||
|
||||
Maintenant, rendez-vous sur <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
* La documentation interactive de l'API sera automatiquement mise à jour, y compris le nouveau corps :
|
||||
* La documentation interactive de l'API sera automatiquement mise à jour, y compris le nouveau corps de la requête :
|
||||
|
||||

|
||||
|
||||
* Cliquez sur le bouton « Try it out », il vous permet de renseigner les paramètres et d'interagir directement avec l'API :
|
||||
* Cliquez sur le bouton "Try it out", il vous permet de renseigner les paramètres et d'interagir directement avec l'API :
|
||||
|
||||

|
||||
|
||||
* Cliquez ensuite sur le bouton « Execute », l'interface utilisateur communiquera avec votre API, enverra les paramètres, obtiendra les résultats et les affichera à l'écran :
|
||||
* Cliquez ensuite sur le bouton "Execute", l'interface utilisateur communiquera avec votre API, enverra les paramètres, obtiendra les résultats et les affichera à l'écran :
|
||||
|
||||

|
||||
|
||||
### Mettre à niveau la documentation API alternative { #alternative-api-docs-upgrade }
|
||||
### Plus loin avec la documentation API alternative
|
||||
|
||||
Et maintenant, rendez-vous sur <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
|
||||
|
||||
* La documentation alternative reflètera également le nouveau paramètre de requête et le nouveau corps :
|
||||
* La documentation alternative reflétera également le nouveau paramètre de requête et le nouveau corps :
|
||||
|
||||

|
||||
|
||||
### En résumé { #recap }
|
||||
### En résumé
|
||||
|
||||
En résumé, vous déclarez **une fois** les types de paramètres, le corps, etc. en tant que paramètres de fonction.
|
||||
En résumé, vous déclarez **une fois** les types de paramètres, <abbr title="en anglais : body">le corps</abbr> de la requête, etc. en tant que paramètres de fonction.
|
||||
|
||||
Vous faites cela avec les types Python standard modernes.
|
||||
|
||||
@@ -348,7 +337,7 @@ Vous n'avez pas à apprendre une nouvelle syntaxe, les méthodes ou les classes
|
||||
|
||||
Juste du **Python** standard.
|
||||
|
||||
Par exemple, pour un `int` :
|
||||
Par exemple, pour un `int`:
|
||||
|
||||
```Python
|
||||
item_id: int
|
||||
@@ -362,54 +351,54 @@ item: Item
|
||||
|
||||
... et avec cette déclaration unique, vous obtenez :
|
||||
|
||||
* Une assistance dans l'éditeur, notamment :
|
||||
* l'autocomplétion.
|
||||
* Une assistance dans votre IDE, notamment :
|
||||
* la complétion.
|
||||
* la vérification des types.
|
||||
* La validation des données :
|
||||
* des erreurs automatiques et claires lorsque les données ne sont pas valides.
|
||||
* une validation même pour les objets JSON profondément imbriqués.
|
||||
* <abbr title="aussi connu sous le nom de : serialization, parsing, marshalling">Conversion</abbr> des données d'entrée : venant du réseau vers les données et types Python. Lecture depuis :
|
||||
* JSON.
|
||||
* Paramètres de chemin.
|
||||
* Paramètres de requête.
|
||||
* Cookies.
|
||||
* En-têtes.
|
||||
* Formulaires.
|
||||
* Fichiers.
|
||||
* <abbr title="aussi connu sous le nom de : serialization, parsing, marshalling">Conversion</abbr> des données de sortie : conversion des données et types Python en données réseau (au format JSON) :
|
||||
* Conversion des types Python (`str`, `int`, `float`, `bool`, `list`, etc).
|
||||
* Objets `datetime`.
|
||||
* Objets `UUID`.
|
||||
* Modèles de base de données.
|
||||
* ... et bien plus.
|
||||
* Documentation API interactive automatique, avec 2 interfaces utilisateur au choix :
|
||||
* une validation même pour les objets <abbr title="JavaScript Object Notation">JSON</abbr> profondément imbriqués.
|
||||
* <abbr title="aussi connu sous le nom de : serialization, parsing, marshalling">Une conversion</abbr> des données d'entrée : venant du réseau et allant vers les données et types de Python, permettant de lire :
|
||||
* le <abbr title="JavaScript Object Notation">JSON</abbr>.
|
||||
* <abbr title="en anglais : path parameters">les paramètres du chemin</abbr>.
|
||||
* <abbr title="en anglais : query parameters">les paramètres de la requête</abbr>.
|
||||
* les cookies.
|
||||
* <abbr title="en anglais : headers">les en-têtes</abbr>.
|
||||
* <abbr title="en anglais : forms">les formulaires</abbr>.
|
||||
* <abbr title="en anglais : files">les fichiers</abbr>.
|
||||
* <abbr title="aussi connu sous le nom de : serialization, parsing, marshalling">La conversion</abbr> des données de sortie : conversion des données et types Python en données réseau (au format <abbr title="JavaScript Object Notation">JSON</abbr>), permettant de convertir :
|
||||
* les types Python (`str`, `int`, `float`, `bool`, `list`, etc).
|
||||
* les objets `datetime`.
|
||||
* les objets `UUID`.
|
||||
* les modèles de base de données.
|
||||
* ... et beaucoup plus.
|
||||
* La documentation API interactive automatique, avec 2 interfaces utilisateur au choix :
|
||||
* Swagger UI.
|
||||
* ReDoc.
|
||||
|
||||
---
|
||||
|
||||
Pour revenir à l'exemple de code précédent, **FastAPI** va :
|
||||
Pour revenir à l'exemple de code précédent, **FastAPI** permet de :
|
||||
|
||||
* Valider la présence d'un `item_id` dans le chemin pour les requêtes `GET` et `PUT`.
|
||||
* Valider que `item_id` existe dans le chemin des requêtes `GET` et `PUT`.
|
||||
* Valider que `item_id` est de type `int` pour les requêtes `GET` et `PUT`.
|
||||
* Si ce n'est pas le cas, le client verra une erreur utile et claire.
|
||||
* Vérifier s'il existe un paramètre de requête optionnel nommé `q` (comme dans `http://127.0.0.1:8000/items/foo?q=somequery`) pour les requêtes `GET`.
|
||||
* Comme le paramètre `q` est déclaré avec `= None`, il est optionnel.
|
||||
* Sans le `None`, il serait requis (comme l'est le corps dans le cas de `PUT`).
|
||||
* Pour les requêtes `PUT` vers `/items/{item_id}`, lire le corps au format JSON :
|
||||
* Vérifier qu'il a un attribut obligatoire `name` qui doit être un `str`.
|
||||
* Vérifier qu'il a un attribut obligatoire `price` qui doit être un `float`.
|
||||
* Vérifier qu'il a un attribut optionnel `is_offer`, qui doit être un `bool`, s'il est présent.
|
||||
* Tout cela fonctionne également pour les objets JSON profondément imbriqués.
|
||||
* Convertir automatiquement depuis et vers JSON.
|
||||
* Tout documenter avec OpenAPI, qui peut être utilisé par :
|
||||
* des systèmes de documentation interactive.
|
||||
* des systèmes de génération automatique de clients, pour de nombreux langages.
|
||||
* Si ce n'est pas le cas, le client voit une erreur utile et claire.
|
||||
* Vérifier qu'il existe un paramètre de requête facultatif nommé `q` (comme dans `http://127.0.0.1:8000/items/foo?q=somequery`) pour les requêtes `GET`.
|
||||
* Puisque le paramètre `q` est déclaré avec `= None`, il est facultatif.
|
||||
* Sans le `None`, il serait nécessaire (comme l'est <abbr title="en anglais : body">le corps</abbr> de la requête dans le cas du `PUT`).
|
||||
* Pour les requêtes `PUT` vers `/items/{item_id}`, de lire <abbr title="en anglais : body">le corps</abbr> en <abbr title="JavaScript Object Notation">JSON</abbr> :
|
||||
* Vérifier qu'il a un attribut obligatoire `name` qui devrait être un `str`.
|
||||
* Vérifier qu'il a un attribut obligatoire `prix` qui doit être un `float`.
|
||||
* Vérifier qu'il a un attribut facultatif `is_offer`, qui devrait être un `bool`, s'il est présent.
|
||||
* Tout cela fonctionnerait également pour les objets <abbr title="JavaScript Object Notation">JSON</abbr> profondément imbriqués.
|
||||
* Convertir de et vers <abbr title="JavaScript Object Notation">JSON</abbr> automatiquement.
|
||||
* Documenter tout avec OpenAPI, qui peut être utilisé par :
|
||||
* Les systèmes de documentation interactifs.
|
||||
* Les systèmes de génération automatique de code client, pour de nombreuses langues.
|
||||
* Fournir directement 2 interfaces web de documentation interactive.
|
||||
|
||||
---
|
||||
|
||||
Nous n'avons fait qu'effleurer la surface, mais vous avez déjà une idée de la façon dont tout fonctionne.
|
||||
Nous n'avons fait qu'effleurer la surface, mais vous avez déjà une idée de la façon dont tout cela fonctionne.
|
||||
|
||||
Essayez de changer la ligne contenant :
|
||||
|
||||
@@ -423,137 +412,61 @@ Essayez de changer la ligne contenant :
|
||||
... "item_name": item.name ...
|
||||
```
|
||||
|
||||
... à :
|
||||
... vers :
|
||||
|
||||
```Python
|
||||
... "item_price": item.price ...
|
||||
```
|
||||
|
||||
... et voyez comment votre éditeur complète automatiquement les attributs et connaît leurs types :
|
||||
... et voyez comment votre éditeur complétera automatiquement les attributs et connaîtra leurs types :
|
||||
|
||||

|
||||

|
||||
|
||||
Pour un exemple plus complet comprenant plus de fonctionnalités, voir le <a href="https://fastapi.tiangolo.com/fr/tutorial/">Tutoriel - Guide utilisateur</a>.
|
||||
|
||||
**Alerte spoiler** : le tutoriel - guide utilisateur inclut :
|
||||
**Spoiler alert** : le tutoriel - guide utilisateur inclut :
|
||||
|
||||
* Déclaration de **paramètres** provenant d'autres emplacements comme : **en-têtes**, **cookies**, **champs de formulaire** et **fichiers**.
|
||||
* Comment définir des **contraintes de validation** comme `maximum_length` ou `regex`.
|
||||
* Un système **<abbr title="aussi connu sous le nom de composants, ressources, fournisseurs, services, injectables">d'injection de dépendances</abbr>** très puissant et facile à utiliser.
|
||||
* Sécurité et authentification, y compris la prise en charge de **OAuth2** avec des **JWT tokens** et l'authentification **HTTP Basic**.
|
||||
* Des techniques plus avancées (mais tout aussi faciles) pour déclarer des **modèles JSON profondément imbriqués** (grâce à Pydantic).
|
||||
* Intégration **GraphQL** avec <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> et d'autres bibliothèques.
|
||||
* De nombreuses fonctionnalités supplémentaires (grâce à Starlette) comme :
|
||||
* Déclaration de **paramètres** provenant d'autres endroits différents comme : **<abbr title="en anglais : headers">en-têtes</abbr>.**, **cookies**, **champs de formulaire** et **fichiers**.
|
||||
* L'utilisation de **contraintes de validation** comme `maximum_length` ou `regex`.
|
||||
* Un **<abbr title="aussi connu sous le nom de composants, ressources, fournisseurs, services, injectables">système d'injection de dépendance </abbr>** très puissant et facile à utiliser .
|
||||
* Sécurité et authentification, y compris la prise en charge de **OAuth2** avec les **<abbr title="en anglais : JWT tokens">jetons <abbr title="JSON Web Tokens">JWT</abbr></abbr>** et l'authentification **HTTP Basic**.
|
||||
* Des techniques plus avancées (mais tout aussi faciles) pour déclarer les **modèles <abbr title="JavaScript Object Notation">JSON</abbr> profondément imbriqués** (grâce à Pydantic).
|
||||
* Intégration de **GraphQL** avec <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> et d'autres bibliothèques.
|
||||
* D'obtenir de nombreuses fonctionnalités supplémentaires (grâce à Starlette) comme :
|
||||
* **WebSockets**
|
||||
* des tests extrêmement faciles basés sur HTTPX et `pytest`
|
||||
* **CORS**
|
||||
* de tester le code très facilement avec `requests` et `pytest`
|
||||
* **<abbr title="Cross-Origin Resource Sharing">CORS</abbr>**
|
||||
* **Cookie Sessions**
|
||||
* ... et plus encore.
|
||||
|
||||
### Déployer votre application (optionnel) { #deploy-your-app-optional }
|
||||
## Performance
|
||||
|
||||
Vous pouvez, si vous le souhaitez, déployer votre application FastAPI sur <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>, allez vous inscrire sur la liste d'attente si ce n'est pas déjà fait. 🚀
|
||||
|
||||
Si vous avez déjà un compte **FastAPI Cloud** (nous vous avons invité depuis la liste d'attente 😉), vous pouvez déployer votre application avec une seule commande.
|
||||
|
||||
Avant de déployer, assurez-vous d'être connecté :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi login
|
||||
|
||||
You are logged in to FastAPI Cloud 🚀
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Puis déployez votre application :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi deploy
|
||||
|
||||
Deploying to FastAPI Cloud...
|
||||
|
||||
✅ Deployment successful!
|
||||
|
||||
🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
C'est tout ! Vous pouvez maintenant accéder à votre application à cette URL. ✨
|
||||
|
||||
#### À propos de FastAPI Cloud { #about-fastapi-cloud }
|
||||
|
||||
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>** est construit par le même auteur et la même équipe derrière **FastAPI**.
|
||||
|
||||
Il simplifie le processus de **construction**, de **déploiement** et **d'accès** à une API avec un effort minimal.
|
||||
|
||||
Il apporte la même **expérience développeur** de la création d'applications avec FastAPI au **déploiement** dans le cloud. 🎉
|
||||
|
||||
FastAPI Cloud est le principal sponsor et financeur des projets open source *FastAPI and friends*. ✨
|
||||
|
||||
#### Déployer sur d'autres fournisseurs cloud { #deploy-to-other-cloud-providers }
|
||||
|
||||
FastAPI est open source et basé sur des standards. Vous pouvez déployer des applications FastAPI sur n'importe quel fournisseur cloud de votre choix.
|
||||
|
||||
Suivez les guides de votre fournisseur cloud pour y déployer des applications FastAPI. 🤓
|
||||
|
||||
## Performance { #performance }
|
||||
|
||||
Les benchmarks TechEmpower indépendants montrent que les applications **FastAPI** s'exécutant sous Uvicorn sont <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">parmi les frameworks Python les plus rapides</a>, juste derrière Starlette et Uvicorn eux-mêmes (utilisés en interne par FastAPI). (*)
|
||||
Les benchmarks TechEmpower indépendants montrent que les applications **FastAPI** s'exécutant sous Uvicorn sont <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank"> parmi les frameworks existants en Python les plus rapides </a>, juste derrière Starlette et Uvicorn (utilisés en interne par FastAPI). (*)
|
||||
|
||||
Pour en savoir plus, consultez la section <a href="https://fastapi.tiangolo.com/fr/benchmarks/" class="internal-link" target="_blank">Benchmarks</a>.
|
||||
|
||||
## Dépendances { #dependencies }
|
||||
## Dépendances facultatives
|
||||
|
||||
FastAPI dépend de Pydantic et Starlette.
|
||||
Utilisées par Pydantic:
|
||||
|
||||
### Dépendances `standard` { #standard-dependencies }
|
||||
|
||||
Lorsque vous installez FastAPI avec `pip install "fastapi[standard]"`, il inclut le groupe `standard` de dépendances optionnelles :
|
||||
|
||||
Utilisées par Pydantic :
|
||||
|
||||
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email-validator</code></a> - pour la validation des adresses e-mail.
|
||||
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email-validator</code></a> - pour la validation des adresses email.
|
||||
|
||||
Utilisées par Starlette :
|
||||
|
||||
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Obligatoire si vous souhaitez utiliser le `TestClient`.
|
||||
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Obligatoire si vous souhaitez utiliser `TestClient`.
|
||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Obligatoire si vous souhaitez utiliser la configuration de template par défaut.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Obligatoire si vous souhaitez prendre en charge l’<abbr title="convertir la chaîne issue d'une requête HTTP en données Python">« parsing »</abbr> de formulaires avec `request.form()`.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Obligatoire si vous souhaitez supporter le <abbr title="convertit la chaine de caractère d'une requête HTTP en donnée Python">"décodage"</abbr> de formulaire avec `request.form()`.
|
||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Obligatoire pour la prise en charge de `SessionMiddleware`.
|
||||
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Obligatoire pour le support `SchemaGenerator` de Starlette (vous n'en avez probablement pas besoin avec FastAPI).
|
||||
|
||||
Utilisées par FastAPI :
|
||||
Utilisées par FastAPI / Starlette :
|
||||
|
||||
* <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> - pour le serveur qui charge et sert votre application. Cela inclut `uvicorn[standard]`, qui comprend certaines dépendances (par ex. `uvloop`) nécessaires pour une haute performance.
|
||||
* `fastapi-cli[standard]` - pour fournir la commande `fastapi`.
|
||||
* Cela inclut `fastapi-cloud-cli`, qui vous permet de déployer votre application FastAPI sur <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>.
|
||||
|
||||
### Sans les dépendances `standard` { #without-standard-dependencies }
|
||||
|
||||
Si vous ne souhaitez pas inclure les dépendances optionnelles `standard`, vous pouvez installer avec `pip install fastapi` au lieu de `pip install "fastapi[standard]"`.
|
||||
|
||||
### Sans `fastapi-cloud-cli` { #without-fastapi-cloud-cli }
|
||||
|
||||
Si vous souhaitez installer FastAPI avec les dépendances standard mais sans `fastapi-cloud-cli`, vous pouvez installer avec `pip install "fastapi[standard-no-fastapi-cloud-cli]"`.
|
||||
|
||||
### Dépendances optionnelles supplémentaires { #additional-optional-dependencies }
|
||||
|
||||
Il existe des dépendances supplémentaires que vous pourriez vouloir installer.
|
||||
|
||||
Dépendances optionnelles supplémentaires pour Pydantic :
|
||||
|
||||
* <a href="https://docs.pydantic.dev/latest/usage/pydantic_settings/" target="_blank"><code>pydantic-settings</code></a> - pour la gestion des paramètres.
|
||||
* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - pour des types supplémentaires à utiliser avec Pydantic.
|
||||
|
||||
Dépendances optionnelles supplémentaires pour FastAPI :
|
||||
|
||||
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - Obligatoire si vous souhaitez utiliser `ORJSONResponse`.
|
||||
* <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> - Pour le serveur qui charge et sert votre application.
|
||||
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - Obligatoire si vous voulez utiliser `ORJSONResponse`.
|
||||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - Obligatoire si vous souhaitez utiliser `UJSONResponse`.
|
||||
|
||||
## Licence { #license }
|
||||
Vous pouvez tout installer avec `pip install fastapi[all]`.
|
||||
|
||||
## Licence
|
||||
|
||||
Ce projet est soumis aux termes de la licence MIT.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Apprendre { #learn }
|
||||
# Apprendre
|
||||
|
||||
Voici les sections introductives et les tutoriels pour apprendre **FastAPI**.
|
||||
|
||||
Vous pouvez considérer ceci comme un **livre**, un **cours**, la **méthode officielle** et recommandée pour apprendre FastAPI. 😎
|
||||
Vous pouvez considérer ceci comme un **manuel**, un **cours**, la **méthode officielle** et recommandée pour appréhender FastAPI. 😎
|
||||
|
||||
@@ -1,28 +1,84 @@
|
||||
# Modèle Full Stack FastAPI { #full-stack-fastapi-template }
|
||||
# Génération de projets - Modèle
|
||||
|
||||
Les modèles, bien qu'ils soient généralement livrés avec une configuration spécifique, sont conçus pour être flexibles et personnalisables. Cela vous permet de les modifier et de les adapter aux exigences de votre projet, ce qui en fait un excellent point de départ. 🏁
|
||||
Vous pouvez utiliser un générateur de projet pour commencer, qui réalisera pour vous la mise en place de bases côté architecture globale, sécurité, base de données et premières routes d'API.
|
||||
|
||||
Vous pouvez utiliser ce modèle pour démarrer, car il inclut une grande partie de la configuration initiale, la sécurité, la base de données et quelques endpoints d'API déjà prêts pour vous.
|
||||
Un générateur de projet fera toujours une mise en place très subjective que vous devriez modifier et adapter suivant vos besoins, mais cela reste un bon point de départ pour vos projets.
|
||||
|
||||
Dépôt GitHub : <a href="https://github.com/tiangolo/full-stack-fastapi-template" class="external-link" target="_blank">Modèle Full Stack FastAPI</a>
|
||||
## Full Stack FastAPI PostgreSQL
|
||||
|
||||
## Modèle Full Stack FastAPI - Pile technologique et fonctionnalités { #full-stack-fastapi-template-technology-stack-and-features }
|
||||
GitHub : <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-postgresql</a>
|
||||
|
||||
- ⚡ [**FastAPI**](https://fastapi.tiangolo.com/fr) pour l'API backend Python.
|
||||
- 🧰 [SQLModel](https://sqlmodel.tiangolo.com) pour les interactions avec la base de données SQL en Python (ORM).
|
||||
- 🔍 [Pydantic](https://docs.pydantic.dev), utilisé par FastAPI, pour la validation des données et la gestion des paramètres.
|
||||
- 💾 [PostgreSQL](https://www.postgresql.org) comme base de données SQL.
|
||||
- 🚀 [React](https://react.dev) pour le frontend.
|
||||
- 💃 Utilisation de TypeScript, des hooks, de Vite et d'autres éléments d'un stack frontend moderne.
|
||||
- 🎨 [Tailwind CSS](https://tailwindcss.com) et [shadcn/ui](https://ui.shadcn.com) pour les composants frontend.
|
||||
- 🤖 Un client frontend généré automatiquement.
|
||||
- 🧪 [Playwright](https://playwright.dev) pour les tests de bout en bout.
|
||||
- 🦇 Prise en charge du mode sombre.
|
||||
- 🐋 [Docker Compose](https://www.docker.com) pour le développement et la production.
|
||||
- 🔒 Hachage sécurisé des mots de passe par défaut.
|
||||
- 🔑 Authentification JWT (JSON Web Token).
|
||||
- 📫 Récupération de mot de passe par e-mail.
|
||||
- ✅ Tests avec [Pytest](https://pytest.org).
|
||||
- 📞 [Traefik](https://traefik.io) comme proxy inverse / répartiteur de charge.
|
||||
- 🚢 Instructions de déploiement avec Docker Compose, y compris la configuration d'un proxy Traefik frontal pour gérer les certificats HTTPS automatiques.
|
||||
- 🏭 CI (intégration continue) et CD (déploiement continu) basés sur GitHub Actions.
|
||||
### Full Stack FastAPI PostgreSQL - Fonctionnalités
|
||||
|
||||
* Intégration **Docker** complète (basée sur Docker).
|
||||
* Déploiement Docker en mode <a href="https://docs.docker.com/engine/swarm/" class="external-link" target="_blank">Swarm</a>
|
||||
* Intégration **Docker Compose** et optimisation pour développement local.
|
||||
* Serveur web Python **prêt au déploiement** utilisant Uvicorn et Gunicorn.
|
||||
* Backend Python <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">**FastAPI**</a> :
|
||||
* **Rapide** : Très hautes performances, comparables à **NodeJS** ou **Go** (grâce à Starlette et Pydantic).
|
||||
* **Intuitif** : Excellent support des éditeurs. <abbr title="aussi appelée auto-complétion, autocomplétion, IntelliSense...">Complétion</abbr> partout. Moins de temps passé à déboguer.
|
||||
* **Facile** : Fait pour être facile à utiliser et apprendre. Moins de temps passé à lire de la documentation.
|
||||
* **Concis** : Minimise la duplication de code. Plusieurs fonctionnalités à chaque déclaration de paramètre.
|
||||
* **Robuste** : Obtenez du code prêt pour être utilisé en production. Avec de la documentation automatique interactive.
|
||||
* **Basé sur des normes** : Basé sur (et totalement compatible avec) les normes ouvertes pour les APIs : <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> et <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
|
||||
* <a href="https://fastapi.tiangolo.com/features/" class="external-link" target="_blank">**Et bien d'autres fonctionnalités**</a> comme la validation automatique, la sérialisation, l'authentification avec OAuth2 JWT tokens, etc.
|
||||
* Hashage de **mots de passe sécurisé** par défaut.
|
||||
* Authentification par **jetons JWT**.
|
||||
* Modèles **SQLAlchemy** (indépendants des extensions Flask, afin qu'ils puissent être utilisés directement avec des *workers* Celery).
|
||||
* Modèle de démarrages basiques pour les utilisateurs (à modifier et supprimer au besoin).
|
||||
* Migrations **Alembic**.
|
||||
* **CORS** (partage des ressources entre origines multiples, ou *Cross Origin Resource Sharing*).
|
||||
* *Worker* **Celery** pouvant importer et utiliser les modèles et le code du reste du backend.
|
||||
* Tests du backend REST basés sur **Pytest**, intégrés dans Docker, pour que vous puissiez tester toutes les interactions de l'API indépendamment de la base de données. Étant exécutés dans Docker, les tests peuvent utiliser un nouvel entrepôt de données créé de zéro à chaque fois (vous pouvez donc utiliser ElasticSearch, MongoDB, CouchDB, etc. et juste tester que l'API fonctionne).
|
||||
* Intégration Python facile avec **Jupyter Kernels** pour le développement à distance ou intra-Docker avec des extensions comme Atom Hydrogen ou Visual Studio Code Jupyter.
|
||||
* Frontend **Vue** :
|
||||
* Généré avec Vue CLI.
|
||||
* Gestion de l'**Authentification JWT**.
|
||||
* Page de connexion.
|
||||
* Après la connexion, page de tableau de bord principal.
|
||||
* Tableau de bord principal avec création et modification d'utilisateurs.
|
||||
* Modification de ses propres caractéristiques utilisateur.
|
||||
* **Vuex**.
|
||||
* **Vue-router**.
|
||||
* **Vuetify** pour de magnifiques composants *material design*.
|
||||
* **TypeScript**.
|
||||
* Serveur Docker basé sur **Nginx** (configuré pour être facilement manipulé avec Vue-router).
|
||||
* Utilisation de *Docker multi-stage building*, pour ne pas avoir besoin de sauvegarder ou *commit* du code compilé.
|
||||
* Tests frontend exécutés à la compilation (pouvant être désactivés).
|
||||
* Fait aussi modulable que possible, pour pouvoir fonctionner comme tel, tout en pouvant être utilisé qu'en partie grâce à Vue CLI.
|
||||
* **PGAdmin** pour les bases de données PostgreSQL, facilement modifiable pour utiliser PHPMYAdmin ou MySQL.
|
||||
* **Flower** pour la surveillance de tâches Celery.
|
||||
* Équilibrage de charge entre le frontend et le backend avec **Traefik**, afin de pouvoir avoir les deux sur le même domaine, séparés par chemins, mais servis par différents conteneurs.
|
||||
* Intégration Traefik, comprenant la génération automatique de certificat **HTTPS** Let's Encrypt.
|
||||
* GitLab **CI** (intégration continue), comprenant des tests pour le frontend et le backend.
|
||||
|
||||
## Full Stack FastAPI Couchbase
|
||||
|
||||
GitHub : <a href="https://github.com/tiangolo/full-stack-fastapi-couchbase" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-couchbase</a>
|
||||
|
||||
⚠️ **ATTENTION** ⚠️
|
||||
|
||||
Si vous démarrez un nouveau projet de zéro, allez voir les alternatives au début de cette page.
|
||||
|
||||
Par exemple, le générateur de projet <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" class="external-link" target="_blank">Full Stack FastAPI PostgreSQL</a> peut être une meilleure alternative, étant activement maintenu et utilisé et comprenant toutes les nouvelles fonctionnalités et améliorations.
|
||||
|
||||
Vous êtes toujours libre d'utiliser le générateur basé sur Couchbase si vous le voulez, cela devrait probablement fonctionner correctement, et si vous avez déjà un projet généré en utilisant ce dernier, cela devrait fonctionner aussi (et vous l'avez déjà probablement mis à jour suivant vos besoins).
|
||||
|
||||
Vous pouvez en apprendre plus dans la documentation du dépôt GithHub.
|
||||
|
||||
## Full Stack FastAPI MongoDB
|
||||
|
||||
...viendra surement plus tard, suivant le temps que j'ai. 😅 🎉
|
||||
|
||||
## Modèles d'apprentissage automatique avec spaCy et FastAPI
|
||||
|
||||
GitHub : <a href="https://github.com/microsoft/cookiecutter-spacy-fastapi" class="external-link" target="_blank">https://github.com/microsoft/cookiecutter-spacy-fastapi</a>
|
||||
|
||||
## Modèles d'apprentissage automatique avec spaCy et FastAPI - Fonctionnalités
|
||||
|
||||
* Intégration d'un modèle NER **spaCy**.
|
||||
* Formatage de requête pour **Azure Cognitive Search**.
|
||||
* Serveur Python web **prêt à utiliser en production** utilisant Uvicorn et Gunicorn.
|
||||
* Déploiement CI/CD Kubernetes pour **Azure DevOps** (AKS).
|
||||
* **Multilangues**. Choisissez facilement l'une des langues intégrées à spaCy durant la mise en place du projet.
|
||||
* **Facilement généralisable** à d'autres bibliothèques similaires (Pytorch, Tensorflow), et non juste spaCy.
|
||||
|
||||
@@ -1,68 +1,70 @@
|
||||
# Introduction aux types Python { #python-types-intro }
|
||||
# Introduction aux Types Python
|
||||
|
||||
Python prend en charge des « type hints » (aussi appelées « annotations de type ») facultatives.
|
||||
Python supporte des annotations de type (ou *type hints*) optionnelles.
|
||||
|
||||
Ces « type hints » ou annotations sont une syntaxe spéciale qui permet de déclarer le <abbr title="par exemple : str, int, float, bool">type</abbr> d'une variable.
|
||||
Ces annotations de type constituent une syntaxe spéciale qui permet de déclarer le <abbr title="par exemple : str, int, float, bool">type</abbr> d'une variable.
|
||||
|
||||
En déclarant les types de vos variables, les éditeurs et outils peuvent vous offrir un meilleur support.
|
||||
En déclarant les types de vos variables, cela permet aux différents outils comme les éditeurs de texte d'offrir un meilleur support.
|
||||
|
||||
Ceci est un **tutoriel rapide / rappel** à propos des annotations de type Python. Il couvre uniquement le minimum nécessaire pour les utiliser avec **FastAPI** ... ce qui est en réalité très peu.
|
||||
Ce chapitre n'est qu'un **tutoriel rapide / rappel** sur les annotations de type Python.
|
||||
Seulement le minimum nécessaire pour les utiliser avec **FastAPI** sera couvert... ce qui est en réalité très peu.
|
||||
|
||||
**FastAPI** est totalement basé sur ces annotations de type, elles lui donnent de nombreux avantages et bénéfices.
|
||||
**FastAPI** est totalement basé sur ces annotations de type, qui lui donnent de nombreux avantages.
|
||||
|
||||
Mais même si vous n'utilisez jamais **FastAPI**, vous auriez intérêt à en apprendre un peu à leur sujet.
|
||||
Mais même si vous n'utilisez pas ou n'utiliserez jamais **FastAPI**, vous pourriez bénéficier d'apprendre quelques choses sur ces dernières.
|
||||
|
||||
/// note | Remarque
|
||||
/// note
|
||||
|
||||
Si vous êtes un expert Python, et que vous savez déjà tout sur les annotations de type, passez au chapitre suivant.
|
||||
Si vous êtes un expert Python, et que vous savez déjà **tout** sur les annotations de type, passez au chapitre suivant.
|
||||
|
||||
///
|
||||
|
||||
## Motivation { #motivation }
|
||||
## Motivations
|
||||
|
||||
Commençons par un exemple simple :
|
||||
Prenons un exemple simple :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial001_py39.py *}
|
||||
{*../../docs_src/python_types/tutorial001.py*}
|
||||
|
||||
Exécuter ce programme affiche :
|
||||
Exécuter ce programe affiche :
|
||||
|
||||
```
|
||||
John Doe
|
||||
```
|
||||
|
||||
La fonction fait ce qui suit :
|
||||
La fonction :
|
||||
|
||||
* Prend un `first_name` et un `last_name`.
|
||||
* Convertit la première lettre de chacun en majuscule avec `title()`.
|
||||
* <abbr title="Les met ensemble, en un seul. Avec le contenu de l'un après l'autre.">Concatène</abbr> ces deux valeurs avec un espace au milieu.
|
||||
* Convertit la première lettre de chaque paramètre en majuscules grâce à `title()`.
|
||||
* Concatène les résultats avec un espace entre les deux.
|
||||
|
||||
{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *}
|
||||
{*../../docs_src/python_types/tutorial001.py hl[2] *}
|
||||
|
||||
### Modifier le code { #edit-it }
|
||||
### Limitations
|
||||
|
||||
C'est un programme très simple.
|
||||
|
||||
Mais maintenant imaginez que vous l'écriviez de zéro.
|
||||
|
||||
À un certain moment, vous auriez commencé la définition de la fonction, vous aviez les paramètres prêts ...
|
||||
À un certain point vous auriez commencé la définition de la fonction, vous aviez les paramètres prêts.
|
||||
|
||||
Mais ensuite vous devez appeler « cette méthode qui convertit la première lettre en majuscule ».
|
||||
Mais vous aviez besoin de "cette méthode qui convertit la première lettre en majuscule".
|
||||
|
||||
Était-ce `upper` ? Était-ce `uppercase` ? `first_uppercase` ? `capitalize` ?
|
||||
Était-ce `upper` ? `uppercase` ? `first_uppercase` ? `capitalize` ?
|
||||
|
||||
Vous essayez alors avec l'ami de toujours des programmeurs, l'autocomplétion de l'éditeur.
|
||||
Vous essayez donc d'utiliser le vieil ami du programmeur, l'auto-complétion de l'éditeur.
|
||||
|
||||
Vous tapez le premier paramètre de la fonction, `first_name`, puis un point (`.`) et appuyez sur `Ctrl+Espace` pour déclencher l'autocomplétion.
|
||||
Vous écrivez le premier paramètre, `first_name`, puis un point (`.`) et appuyez sur `Ctrl+Espace` pour déclencher l'auto-complétion.
|
||||
|
||||
Mais, malheureusement, vous n'obtenez rien d'utile :
|
||||
Mais malheureusement, rien d'utile n'en résulte :
|
||||
|
||||
<img src="/img/python-types/image01.png">
|
||||
|
||||
### Ajouter des types { #add-types }
|
||||
### Ajouter des types
|
||||
|
||||
Modifions une seule ligne de la version précédente.
|
||||
|
||||
Nous allons changer exactement ce fragment, les paramètres de la fonction, de :
|
||||
Nous allons changer seulement cet extrait, les paramètres de la fonction, de :
|
||||
|
||||
|
||||
```Python
|
||||
first_name, last_name
|
||||
@@ -76,389 +78,222 @@ Nous allons changer exactement ce fragment, les paramètres de la fonction, de :
|
||||
|
||||
C'est tout.
|
||||
|
||||
Ce sont les « annotations de type » :
|
||||
Ce sont des annotations de types :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *}
|
||||
{*../../docs_src/python_types/tutorial002.py hl[1] *}
|
||||
|
||||
Ce n'est pas la même chose que de déclarer des valeurs par défaut, ce qui serait :
|
||||
À ne pas confondre avec la déclaration de valeurs par défaut comme ici :
|
||||
|
||||
```Python
|
||||
first_name="john", last_name="doe"
|
||||
```
|
||||
|
||||
C'est différent.
|
||||
C'est une chose différente.
|
||||
|
||||
Nous utilisons des deux-points (`:`), pas des signes égal (`=`).
|
||||
On utilise un deux-points (`:`), et pas un égal (`=`).
|
||||
|
||||
Et ajouter des annotations de type ne change normalement pas ce qui se passe par rapport à ce qui se passerait sans elles.
|
||||
Et ajouter des annotations de types ne crée normalement pas de différence avec le comportement qui aurait eu lieu si elles n'étaient pas là.
|
||||
|
||||
Mais maintenant, imaginez que vous êtes à nouveau en train de créer cette fonction, mais avec des annotations de type.
|
||||
Maintenant, imaginez que vous êtes en train de créer cette fonction, mais avec des annotations de type cette fois.
|
||||
|
||||
Au même moment, vous essayez de déclencher l'autocomplétion avec `Ctrl+Espace` et vous voyez :
|
||||
Au même moment que durant l'exemple précédent, vous essayez de déclencher l'auto-complétion et vous voyez :
|
||||
|
||||
<img src="/img/python-types/image02.png">
|
||||
|
||||
Avec cela, vous pouvez faire défiler en voyant les options, jusqu'à trouver celle qui « vous dit quelque chose » :
|
||||
Vous pouvez donc dérouler les options jusqu'à trouver la méthode à laquelle vous pensiez.
|
||||
|
||||
<img src="/img/python-types/image03.png">
|
||||
|
||||
## Plus de motivation { #more-motivation }
|
||||
## Plus de motivations
|
||||
|
||||
Regardez cette fonction, elle a déjà des annotations de type :
|
||||
Cette fonction possède déjà des annotations de type :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *}
|
||||
{*../../docs_src/python_types/tutorial003.py hl[1] *}
|
||||
|
||||
Comme l'éditeur connaît les types des variables, vous n'obtenez pas seulement l'autocomplétion, vous obtenez aussi des vérifications d'erreurs :
|
||||
Comme l'éditeur connaît le type des variables, vous n'avez pas seulement l'auto-complétion, mais aussi de la détection d'erreurs :
|
||||
|
||||
<img src="/img/python-types/image04.png">
|
||||
|
||||
Vous savez maintenant qu'il faut corriger, convertir `age` en chaîne avec `str(age)` :
|
||||
Maintenant que vous avez connaissance du problème, convertissez `age` en <abbr title="string">chaîne de caractères</abbr> grâce à `str(age)` :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *}
|
||||
{*../../docs_src/python_types/tutorial004.py hl[2] *}
|
||||
|
||||
## Déclarer des types { #declaring-types }
|
||||
## Déclarer des types
|
||||
|
||||
Vous venez de voir l'endroit principal pour déclarer des annotations de type : dans les paramètres des fonctions.
|
||||
Vous venez de voir là où les types sont généralement déclarés : dans les paramètres de fonctions.
|
||||
|
||||
C'est aussi l'endroit principal où vous les utiliserez avec **FastAPI**.
|
||||
C'est aussi ici que vous les utiliseriez avec **FastAPI**.
|
||||
|
||||
### Types simples { #simple-types }
|
||||
### Types simples
|
||||
|
||||
Vous pouvez déclarer tous les types standards de Python, pas seulement `str`.
|
||||
Vous pouvez déclarer tous les types de Python, pas seulement `str`.
|
||||
|
||||
Vous pouvez utiliser, par exemple :
|
||||
Comme par exemple :
|
||||
|
||||
* `int`
|
||||
* `float`
|
||||
* `bool`
|
||||
* `bytes`
|
||||
|
||||
{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *}
|
||||
{*../../docs_src/python_types/tutorial005.py hl[1] *}
|
||||
|
||||
### Types génériques avec paramètres de type { #generic-types-with-type-parameters }
|
||||
### Types génériques avec des paramètres de types
|
||||
|
||||
Il existe certaines structures de données qui peuvent contenir d'autres valeurs, comme `dict`, `list`, `set` et `tuple`. Et les valeurs internes peuvent aussi avoir leur propre type.
|
||||
Il existe certaines structures de données qui contiennent d'autres valeurs, comme `dict`, `list`, `set` et `tuple`. Et les valeurs internes peuvent elles aussi avoir leurs propres types.
|
||||
|
||||
Ces types qui ont des types internes sont appelés types « génériques ». Et il est possible de les déclarer, même avec leurs types internes.
|
||||
Pour déclarer ces types et les types internes, on utilise le module standard de Python `typing`.
|
||||
|
||||
Pour déclarer ces types et les types internes, vous pouvez utiliser le module standard Python `typing`. Il existe spécifiquement pour prendre en charge ces annotations de type.
|
||||
Il existe spécialement pour supporter ces annotations de types.
|
||||
|
||||
#### Versions plus récentes de Python { #newer-versions-of-python }
|
||||
#### `List`
|
||||
|
||||
La syntaxe utilisant `typing` est compatible avec toutes les versions, de Python 3.6 aux plus récentes, y compris Python 3.9, Python 3.10, etc.
|
||||
Par exemple, définissons une variable comme `list` de `str`.
|
||||
|
||||
Au fur et à mesure que Python évolue, les versions plus récentes apportent un meilleur support pour ces annotations de type et dans de nombreux cas vous n'aurez même pas besoin d'importer et d'utiliser le module `typing` pour les déclarer.
|
||||
Importez `List` (avec un `L` majuscule) depuis `typing`.
|
||||
|
||||
Si vous pouvez choisir une version plus récente de Python pour votre projet, vous pourrez profiter de cette simplicité supplémentaire.
|
||||
{*../../docs_src/python_types/tutorial006.py hl[1] *}
|
||||
|
||||
Dans toute la documentation, il y a des exemples compatibles avec chaque version de Python (lorsqu'il y a une différence).
|
||||
Déclarez la variable, en utilisant la syntaxe des deux-points (`:`).
|
||||
|
||||
Par exemple « Python 3.6+ » signifie que c'est compatible avec Python 3.6 ou supérieur (y compris 3.7, 3.8, 3.9, 3.10, etc.). Et « Python 3.9+ » signifie que c'est compatible avec Python 3.9 ou supérieur (y compris 3.10, etc).
|
||||
Et comme type, mettez `List`.
|
||||
|
||||
Si vous pouvez utiliser les dernières versions de Python, utilisez les exemples pour la dernière version, ils auront la meilleure et la plus simple syntaxe, par exemple, « Python 3.10+ ».
|
||||
Les listes étant un type contenant des types internes, mettez ces derniers entre crochets (`[`, `]`) :
|
||||
|
||||
#### Liste { #list }
|
||||
{*../../docs_src/python_types/tutorial006.py hl[4] *}
|
||||
|
||||
Par exemple, définissons une variable comme une `list` de `str`.
|
||||
/// tip | Astuce
|
||||
|
||||
Déclarez la variable, en utilisant la même syntaxe avec deux-points (`:`).
|
||||
Ces types internes entre crochets sont appelés des "paramètres de type".
|
||||
|
||||
Comme type, mettez `list`.
|
||||
|
||||
Comme la liste est un type qui contient des types internes, mettez-les entre crochets :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *}
|
||||
|
||||
/// info
|
||||
|
||||
Ces types internes entre crochets sont appelés « paramètres de type ».
|
||||
|
||||
Dans ce cas, `str` est le paramètre de type passé à `list`.
|
||||
Ici, `str` est un paramètre de type passé à `List`.
|
||||
|
||||
///
|
||||
|
||||
Cela signifie : « la variable `items` est une `list`, et chacun des éléments de cette liste est un `str` ».
|
||||
Ce qui signifie : "la variable `items` est une `list`, et chacun de ses éléments a pour type `str`.
|
||||
|
||||
En faisant cela, votre éditeur peut vous fournir de l'aide même pendant le traitement des éléments de la liste :
|
||||
En faisant cela, votre éditeur pourra vous aider, même pendant que vous traitez des éléments de la liste.
|
||||
|
||||
<img src="/img/python-types/image05.png">
|
||||
|
||||
Sans types, c'est presque impossible à réaliser.
|
||||
|
||||
Remarquez que la variable `item` est l'un des éléments de la liste `items`.
|
||||
Vous remarquerez que la variable `item` n'est qu'un des éléments de la list `items`.
|
||||
|
||||
Et pourtant, l'éditeur sait que c'est un `str` et fournit le support approprié.
|
||||
Et pourtant, l'éditeur sait qu'elle est de type `str` et pourra donc vous aider à l'utiliser.
|
||||
|
||||
#### Tuple et Set { #tuple-and-set }
|
||||
#### `Tuple` et `Set`
|
||||
|
||||
Vous feriez la même chose pour déclarer des `tuple` et des `set` :
|
||||
C'est le même fonctionnement pour déclarer un `tuple` ou un `set` :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *}
|
||||
{*../../docs_src/python_types/tutorial007.py hl[1,4] *}
|
||||
|
||||
Cela signifie :
|
||||
Dans cet exemple :
|
||||
|
||||
* La variable `items_t` est un `tuple` avec 3 éléments, un `int`, un autre `int`, et un `str`.
|
||||
* La variable `items_t` est un `tuple` avec 3 éléments, un `int`, un deuxième `int`, et un `str`.
|
||||
* La variable `items_s` est un `set`, et chacun de ses éléments est de type `bytes`.
|
||||
|
||||
#### Dict { #dict }
|
||||
#### `Dict`
|
||||
|
||||
Pour définir un `dict`, vous passez 2 paramètres de type, séparés par des virgules.
|
||||
Pour définir un `dict`, il faut lui passer 2 paramètres, séparés par une virgule (`,`).
|
||||
|
||||
Le premier paramètre de type est pour les clés du `dict`.
|
||||
Le premier paramètre de type est pour les clés et le second pour les valeurs du dictionnaire (`dict`).
|
||||
|
||||
Le second paramètre de type est pour les valeurs du `dict` :
|
||||
{*../../docs_src/python_types/tutorial008.py hl[1,4] *}
|
||||
|
||||
{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *}
|
||||
Dans cet exemple :
|
||||
|
||||
Cela signifie :
|
||||
* La variable `prices` est de type `dict` :
|
||||
* Les clés de ce dictionnaire sont de type `str`.
|
||||
* Les valeurs de ce dictionnaire sont de type `float`.
|
||||
|
||||
* La variable `prices` est un `dict` :
|
||||
* Les clés de ce `dict` sont de type `str` (disons, le nom de chaque article).
|
||||
* Les valeurs de ce `dict` sont de type `float` (disons, le prix de chaque article).
|
||||
#### `Optional`
|
||||
|
||||
#### Union { #union }
|
||||
Vous pouvez aussi utiliser `Optional` pour déclarer qu'une variable a un type, comme `str` mais qu'il est "optionnel" signifiant qu'il pourrait aussi être `None`.
|
||||
|
||||
Vous pouvez déclarer qu'une variable peut être de plusieurs types, par exemple, un `int` ou un `str`.
|
||||
{*../../docs_src/python_types/tutorial009.py hl[1,4] *}
|
||||
|
||||
Dans Python 3.6 et supérieur (y compris Python 3.10), vous pouvez utiliser le type `Union` de `typing` et mettre entre crochets les types possibles à accepter.
|
||||
Utiliser `Optional[str]` plutôt que `str` permettra à l'éditeur de vous aider à détecter les erreurs où vous supposeriez qu'une valeur est toujours de type `str`, alors qu'elle pourrait aussi être `None`.
|
||||
|
||||
Dans Python 3.10, il existe aussi une nouvelle syntaxe où vous pouvez mettre les types possibles séparés par une <abbr title='aussi appelé « opérateur OU bit à bit », mais ce sens n’est pas pertinent ici'>barre verticale (`|`)</abbr>.
|
||||
#### Types génériques
|
||||
|
||||
//// tab | Python 3.10+
|
||||
Les types qui peuvent contenir des paramètres de types entre crochets, comme :
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!> ../../docs_src/python_types/tutorial008b_py310.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
{!> ../../docs_src/python_types/tutorial008b_py39.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
Dans les deux cas, cela signifie que `item` peut être un `int` ou un `str`.
|
||||
|
||||
#### Possiblement `None` { #possibly-none }
|
||||
|
||||
Vous pouvez déclarer qu'une valeur peut avoir un type, comme `str`, mais qu'elle peut aussi être `None`.
|
||||
|
||||
Dans Python 3.6 et supérieur (y compris Python 3.10), vous pouvez le déclarer en important et en utilisant `Optional` depuis le module `typing`.
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
{!../../docs_src/python_types/tutorial009_py39.py!}
|
||||
```
|
||||
|
||||
Utiliser `Optional[str]` au lieu de simplement `str` permettra à l'éditeur de vous aider à détecter des erreurs où vous supposeriez qu'une valeur est toujours un `str`, alors qu'elle pourrait en fait aussi être `None`.
|
||||
|
||||
`Optional[Something]` est en réalité un raccourci pour `Union[Something, None]`, ils sont équivalents.
|
||||
|
||||
Cela signifie aussi que dans Python 3.10, vous pouvez utiliser `Something | None` :
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!> ../../docs_src/python_types/tutorial009_py310.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
{!> ../../docs_src/python_types/tutorial009_py39.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+ alternative
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
{!> ../../docs_src/python_types/tutorial009b_py39.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
#### Utiliser `Union` ou `Optional` { #using-union-or-optional }
|
||||
|
||||
Si vous utilisez une version de Python inférieure à 3.10, voici un conseil de mon point de vue très **subjectif** :
|
||||
|
||||
* 🚨 Évitez d'utiliser `Optional[SomeType]`
|
||||
* À la place ✨ **utilisez `Union[SomeType, None]`** ✨.
|
||||
|
||||
Les deux sont équivalents et sous le capot ce sont les mêmes, mais je recommanderais `Union` plutôt que `Optional` parce que le mot « facultatif » semble impliquer que la valeur est optionnelle, alors que cela signifie en fait « elle peut être `None` », même si elle n'est pas facultative et est toujours requise.
|
||||
|
||||
Je pense que `Union[SomeType, None]` est plus explicite sur ce que cela signifie.
|
||||
|
||||
Il ne s'agit que des mots et des noms. Mais ces mots peuvent influencer la manière dont vous et vos coéquipiers pensez au code.
|
||||
|
||||
Par exemple, prenons cette fonction :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *}
|
||||
|
||||
Le paramètre `name` est défini comme `Optional[str]`, mais il n'est pas facultatif, vous ne pouvez pas appeler la fonction sans le paramètre :
|
||||
|
||||
```Python
|
||||
say_hi() # Oh non, cela lève une erreur ! 😱
|
||||
```
|
||||
|
||||
Le paramètre `name` est toujours requis (pas « optionnel ») parce qu'il n'a pas de valeur par défaut. Néanmoins, `name` accepte `None` comme valeur :
|
||||
|
||||
```Python
|
||||
say_hi(name=None) # Cela fonctionne, None est valide 🎉
|
||||
```
|
||||
|
||||
La bonne nouvelle est que, dès que vous êtes sur Python 3.10, vous n'avez plus à vous en soucier, car vous pourrez simplement utiliser `|` pour définir des unions de types :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *}
|
||||
|
||||
Et alors vous n'aurez plus à vous soucier de noms comme `Optional` et `Union`. 😎
|
||||
|
||||
#### Types génériques { #generic-types }
|
||||
|
||||
Ces types qui prennent des paramètres de type entre crochets sont appelés des **types génériques** ou **Generics**, par exemple :
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
Vous pouvez utiliser les mêmes types intégrés comme génériques (avec des crochets et des types à l'intérieur) :
|
||||
|
||||
* `list`
|
||||
* `tuple`
|
||||
* `set`
|
||||
* `dict`
|
||||
|
||||
Et, comme avec les versions précédentes de Python, depuis le module `typing` :
|
||||
|
||||
* `Union`
|
||||
* `List`
|
||||
* `Tuple`
|
||||
* `Set`
|
||||
* `Dict`
|
||||
* `Optional`
|
||||
* ... et d'autres.
|
||||
* ...et d'autres.
|
||||
|
||||
Dans Python 3.10, comme alternative à l'utilisation des génériques `Union` et `Optional`, vous pouvez utiliser la <abbr title='aussi appelé « opérateur OU bit à bit », mais ce sens n’est pas pertinent ici'>barre verticale (`|`)</abbr> pour déclarer des unions de types, c'est bien mieux et plus simple.
|
||||
sont appelés des **types génériques** ou **Generics**.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+
|
||||
|
||||
Vous pouvez utiliser les mêmes types intégrés comme génériques (avec des crochets et des types à l'intérieur) :
|
||||
|
||||
* `list`
|
||||
* `tuple`
|
||||
* `set`
|
||||
* `dict`
|
||||
|
||||
Et des génériques depuis le module `typing` :
|
||||
|
||||
* `Union`
|
||||
* `Optional`
|
||||
* ... et d'autres.
|
||||
|
||||
////
|
||||
|
||||
### Classes en tant que types { #classes-as-types }
|
||||
### Classes en tant que types
|
||||
|
||||
Vous pouvez aussi déclarer une classe comme type d'une variable.
|
||||
|
||||
Disons que vous avez une classe `Person`, avec un nom :
|
||||
Disons que vous avez une classe `Person`, avec une variable `name` :
|
||||
|
||||
{*../../docs_src/python_types/tutorial010.py hl[1:3] *}
|
||||
|
||||
{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *}
|
||||
|
||||
Vous pouvez ensuite déclarer une variable de type `Person` :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *}
|
||||
{*../../docs_src/python_types/tutorial010.py hl[6] *}
|
||||
|
||||
Et là encore, vous obtenez tout le support de l'éditeur :
|
||||
Et vous aurez accès, encore une fois, au support complet offert par l'éditeur :
|
||||
|
||||
<img src="/img/python-types/image06.png">
|
||||
|
||||
Remarquez que cela signifie « `one_person` est une instance de la classe `Person` ».
|
||||
|
||||
Cela ne signifie pas « `one_person` est la classe appelée `Person` ».
|
||||
|
||||
## Modèles Pydantic { #pydantic-models }
|
||||
## Les modèles Pydantic
|
||||
|
||||
<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> est une bibliothèque Python pour effectuer de la validation de données.
|
||||
|
||||
Vous déclarez la « forme » de la donnée sous forme de classes avec des attributs.
|
||||
Vous déclarez la forme de la donnée avec des classes et des attributs.
|
||||
|
||||
Et chaque attribut a un type.
|
||||
Chaque attribut possède un type.
|
||||
|
||||
Ensuite, vous créez une instance de cette classe avec certaines valeurs et elle validera les valeurs, les convertira dans le type approprié (le cas échéant) et vous donnera un objet avec toutes les données.
|
||||
Puis vous créez une instance de cette classe avec certaines valeurs et **Pydantic** validera les valeurs, les convertira dans le type adéquat (si c'est nécessaire et possible) et vous donnera un objet avec toute la donnée.
|
||||
|
||||
Et vous obtenez tout le support de l'éditeur avec cet objet résultant.
|
||||
Ainsi, votre éditeur vous offrira un support adapté pour l'objet résultant.
|
||||
|
||||
Un exemple tiré de la documentation officielle de Pydantic :
|
||||
Extrait de la documentation officielle de **Pydantic** :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial011_py310.py *}
|
||||
{*../../docs_src/python_types/tutorial011.py*}
|
||||
|
||||
/// info
|
||||
|
||||
Pour en savoir plus à propos de <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic, consultez sa documentation</a>.
|
||||
Pour en savoir plus à propos de <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic, allez jeter un coup d'oeil à sa documentation</a>.
|
||||
|
||||
///
|
||||
|
||||
**FastAPI** est entièrement basé sur Pydantic.
|
||||
**FastAPI** est basé entièrement sur **Pydantic**.
|
||||
|
||||
Vous verrez beaucoup plus de tout cela en pratique dans le [Tutoriel - Guide utilisateur](tutorial/index.md){.internal-link target=_blank}.
|
||||
Vous verrez bien plus d'exemples de son utilisation dans [Tutoriel - Guide utilisateur](tutorial/index.md){.internal-link target=_blank}.
|
||||
|
||||
/// tip | Astuce
|
||||
## Les annotations de type dans **FastAPI**
|
||||
|
||||
Pydantic a un comportement spécial lorsque vous utilisez `Optional` ou `Union[Something, None]` sans valeur par défaut, vous pouvez en lire davantage dans la documentation de Pydantic à propos des <a href="https://docs.pydantic.dev/2.3/usage/models/#required-fields" class="external-link" target="_blank">champs Optionals requis</a>.
|
||||
**FastAPI** utilise ces annotations pour faire différentes choses.
|
||||
|
||||
///
|
||||
Avec **FastAPI**, vous déclarez des paramètres grâce aux annotations de types et vous obtenez :
|
||||
|
||||
## Annotations de type avec métadonnées { #type-hints-with-metadata-annotations }
|
||||
* **du support de l'éditeur**
|
||||
* **de la vérification de types**
|
||||
|
||||
Python dispose également d'une fonctionnalité qui permet de mettre des **<abbr title="Données sur les données, dans ce cas, des informations sur le type, p. ex. une description.">métadonnées</abbr> supplémentaires** dans ces annotations de type en utilisant `Annotated`.
|
||||
...et **FastAPI** utilise ces mêmes déclarations pour :
|
||||
|
||||
Depuis Python 3.9, `Annotated` fait partie de la bibliothèque standard, vous pouvez donc l'importer depuis `typing`.
|
||||
|
||||
{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *}
|
||||
|
||||
Python lui-même ne fait rien avec ce `Annotated`. Et pour les éditeurs et autres outils, le type est toujours `str`.
|
||||
|
||||
Mais vous pouvez utiliser cet espace dans `Annotated` pour fournir à **FastAPI** des métadonnées supplémentaires sur la façon dont vous voulez que votre application se comporte.
|
||||
|
||||
L'important à retenir est que le premier paramètre de type que vous passez à `Annotated` est le type réel. Le reste n'est que des métadonnées pour d'autres outils.
|
||||
|
||||
Pour l'instant, vous avez juste besoin de savoir que `Annotated` existe, et que c'est du Python standard. 😎
|
||||
|
||||
Plus tard, vous verrez à quel point cela peut être puissant.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Le fait que ce soit du Python standard signifie que vous bénéficierez toujours de la meilleure expérience développeur possible dans votre éditeur, avec les outils que vous utilisez pour analyser et refactoriser votre code, etc. ✨
|
||||
|
||||
Et aussi que votre code sera très compatible avec de nombreux autres outils et bibliothèques Python. 🚀
|
||||
|
||||
///
|
||||
|
||||
## Annotations de type dans **FastAPI** { #type-hints-in-fastapi }
|
||||
|
||||
**FastAPI** tire parti de ces annotations de type pour faire plusieurs choses.
|
||||
|
||||
Avec **FastAPI**, vous déclarez des paramètres avec des annotations de type et vous obtenez :
|
||||
|
||||
* **Du support de l'éditeur**.
|
||||
* **Des vérifications de types**.
|
||||
|
||||
... et **FastAPI** utilise les mêmes déclarations pour :
|
||||
|
||||
* **Définir des prérequis** : à partir des paramètres de chemin de la requête, des paramètres de requête, des en-têtes, des corps, des dépendances, etc.
|
||||
* **Convertir des données** : de la requête vers le type requis.
|
||||
* **Valider des données** : provenant de chaque requête :
|
||||
* En générant des **erreurs automatiques** renvoyées au client lorsque la donnée est invalide.
|
||||
* **Définir les prérequis** : depuis les paramètres de chemins des requêtes, les entêtes, les corps, les dépendances, etc.
|
||||
* **Convertir des données** : depuis la requête vers les types requis.
|
||||
* **Valider des données** : venant de chaque requête :
|
||||
* Générant automatiquement des **erreurs** renvoyées au client quand la donnée est invalide.
|
||||
* **Documenter** l'API avec OpenAPI :
|
||||
* ce qui est ensuite utilisé par les interfaces utilisateur de documentation interactive automatiques.
|
||||
* ce qui ensuite utilisé par les interfaces utilisateur automatiques de documentation interactive.
|
||||
|
||||
Tout cela peut sembler abstrait. Ne vous inquiétez pas. Vous verrez tout cela en action dans le [Tutoriel - Guide utilisateur](tutorial/index.md){.internal-link target=_blank}.
|
||||
Tout cela peut paraître bien abstrait, mais ne vous inquiétez pas, vous verrez tout ça en pratique dans [Tutoriel - Guide utilisateur](tutorial/index.md){.internal-link target=_blank}.
|
||||
|
||||
L'important est qu'en utilisant les types standards de Python, en un seul endroit (au lieu d'ajouter plus de classes, de décorateurs, etc.), **FastAPI** fera une grande partie du travail pour vous.
|
||||
Ce qu'il faut retenir c'est qu'en utilisant les types standard de Python, à un seul endroit (plutôt que d'ajouter plus de classes, de décorateurs, etc.), **FastAPI** fera une grande partie du travail pour vous.
|
||||
|
||||
/// info
|
||||
|
||||
Si vous avez déjà parcouru tout le tutoriel et êtes revenu pour en voir plus sur les types, une bonne ressource est <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">l'« aide-mémoire » de `mypy`</a>.
|
||||
Si vous avez déjà lu le tutoriel et êtes revenus ici pour voir plus sur les types, une bonne ressource est la <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">"cheat sheet" de `mypy`</a>.
|
||||
|
||||
///
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Tâches d'arrière-plan { #background-tasks }
|
||||
# Tâches d'arrière-plan
|
||||
|
||||
Vous pouvez définir des tâches d'arrière-plan qui seront exécutées après avoir retourné une réponse.
|
||||
|
||||
@@ -7,19 +7,20 @@ Ceci est utile pour les opérations qui doivent avoir lieu après une requête,
|
||||
Cela comprend, par exemple :
|
||||
|
||||
* Les notifications par email envoyées après l'exécution d'une action :
|
||||
* Étant donné que se connecter à un serveur et envoyer un email a tendance à être « lent » (plusieurs secondes), vous pouvez retourner la réponse directement et envoyer la notification en arrière-plan.
|
||||
* Étant donné que se connecter à un serveur et envoyer un email a tendance à être «lent» (plusieurs secondes), vous pouvez retourner la réponse directement et envoyer la notification en arrière-plan.
|
||||
* Traiter des données :
|
||||
* Par exemple, si vous recevez un fichier qui doit passer par un traitement lent, vous pouvez retourner une réponse « Accepted » (HTTP 202) puis faire le traitement en arrière-plan.
|
||||
* Par exemple, si vous recevez un fichier qui doit passer par un traitement lent, vous pouvez retourner une réponse «Accepted» (HTTP 202) puis faire le traitement en arrière-plan.
|
||||
|
||||
## Utiliser `BackgroundTasks` { #using-backgroundtasks }
|
||||
|
||||
Pour commencer, importez `BackgroundTasks` et définissez un paramètre dans votre *fonction de chemin d'accès* avec `BackgroundTasks` comme type déclaré.
|
||||
## Utiliser `BackgroundTasks`
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *}
|
||||
Pour commencer, importez `BackgroundTasks` et définissez un paramètre dans votre *fonction de chemin* avec `BackgroundTasks` comme type déclaré.
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001.py hl[1,13] *}
|
||||
|
||||
**FastAPI** créera l'objet de type `BackgroundTasks` pour vous et le passera comme paramètre.
|
||||
|
||||
## Créer une fonction de tâche { #create-a-task-function }
|
||||
## Créer une fonction de tâche
|
||||
|
||||
Une fonction à exécuter comme tâche d'arrière-plan est juste une fonction standard qui peut recevoir des paramètres.
|
||||
|
||||
@@ -29,13 +30,14 @@ Dans cet exemple, la fonction de tâche écrira dans un fichier (afin de simuler
|
||||
|
||||
L'opération d'écriture n'utilisant ni `async` ni `await`, on définit la fonction avec un `def` normal.
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *}
|
||||
{* ../../docs_src/background_tasks/tutorial001.py hl[6:9] *}
|
||||
|
||||
## Ajouter une tâche d'arrière-plan { #add-the-background-task }
|
||||
## Ajouter une tâche d'arrière-plan
|
||||
|
||||
Dans votre *fonction de chemin d'accès*, passez votre fonction de tâche à l'objet de type `BackgroundTasks` (`background_tasks` ici) grâce à la méthode `.add_task()` :
|
||||
Dans votre *fonction de chemin*, passez votre fonction de tâche à l'objet de type `BackgroundTasks` (`background_tasks` ici) grâce à la méthode `.add_task()` :
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *}
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001.py hl[14] *}
|
||||
|
||||
`.add_task()` reçoit comme arguments :
|
||||
|
||||
@@ -43,40 +45,40 @@ Dans votre *fonction de chemin d'accès*, passez votre fonction de tâche à l'o
|
||||
* Les arguments positionnels à passer à la fonction de tâche dans l'ordre (`email`).
|
||||
* Les arguments nommés à passer à la fonction de tâche (`message="some notification"`).
|
||||
|
||||
## Injection de dépendances { #dependency-injection }
|
||||
## Injection de dépendances
|
||||
|
||||
Utiliser `BackgroundTasks` fonctionne aussi avec le système d'injection de dépendances. Vous pouvez déclarer un paramètre de type `BackgroundTasks` à différents niveaux : dans une *fonction de chemin d'accès*, dans une dépendance (dependable), dans une sous-dépendance, etc.
|
||||
Utiliser `BackgroundTasks` fonctionne aussi avec le système d'injection de dépendances. Vous pouvez déclarer un paramètre de type `BackgroundTasks` à différents niveaux : dans une *fonction de chemin*, dans une dépendance, dans une sous-dépendance...
|
||||
|
||||
**FastAPI** sait quoi faire dans chaque cas et comment réutiliser le même objet, afin que toutes les tâches d'arrière-plan soient fusionnées et que les tâches soient ensuite exécutées en arrière-plan :
|
||||
**FastAPI** sait quoi faire dans chaque cas et comment réutiliser le même objet, afin que tous les paramètres de type `BackgroundTasks` soient fusionnés et que les tâches soient exécutées en arrière-plan :
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}
|
||||
{* ../../docs_src/background_tasks/tutorial002.py hl[13,15,22,25] *}
|
||||
|
||||
Dans cet exemple, les messages seront écrits dans le fichier `log.txt` après que la réponse soit envoyée.
|
||||
|
||||
S'il y avait un paramètre de requête dans la requête, alors il sera écrit dans le journal via une tâche d'arrière-plan.
|
||||
S'il y avait une `query` (paramètre nommé `q`) dans la requête, alors elle sera écrite dans `log.txt` via une tâche d'arrière-plan.
|
||||
|
||||
Et ensuite une autre tâche d'arrière-plan (générée dans la *fonction de chemin d'accès*) écrira un message comprenant le paramètre de chemin `email`.
|
||||
Et ensuite une autre tâche d'arrière-plan (générée dans les paramètres de la *la fonction de chemin*) écrira un message dans `log.txt` comprenant le paramètre de chemin `email`.
|
||||
|
||||
## Détails techniques { #technical-details }
|
||||
## Détails techniques
|
||||
|
||||
La classe `BackgroundTasks` provient directement de <a href="https://www.starlette.dev/background/" class="external-link" target="_blank">`starlette.background`</a>.
|
||||
|
||||
Elle est importée/incluse directement dans **FastAPI** pour que vous puissiez l'importer depuis `fastapi` et éviter d'importer accidentellement `BackgroundTask` (sans `s` à la fin) depuis `starlette.background`.
|
||||
|
||||
En utilisant seulement `BackgroundTasks` (et non `BackgroundTask`), il est possible de l'utiliser en tant que paramètre de *fonction de chemin d'accès* et de laisser **FastAPI** gérer le reste pour vous, comme en utilisant l'objet `Request` directement.
|
||||
En utilisant seulement `BackgroundTasks` (et non `BackgroundTask`), il est possible de l'utiliser en tant que paramètre de *fonction de chemin* et de laisser **FastAPI** gérer le reste pour vous, comme en utilisant l'objet `Request` directement.
|
||||
|
||||
Il est tout de même possible d'utiliser `BackgroundTask` seul dans **FastAPI**, mais dans ce cas il faut créer l'objet dans le code et renvoyer une `Response` Starlette l'incluant.
|
||||
|
||||
Plus de détails sont disponibles dans <a href="https://www.starlette.dev/background/" class="external-link" target="_blank">la documentation officielle de Starlette sur les tâches d'arrière-plan</a>.
|
||||
Plus de détails sont disponibles dans <a href="https://www.starlette.dev/background/" class="external-link" target="_blank">la documentation officielle de Starlette sur les tâches d'arrière-plan</a> (via leurs classes `BackgroundTasks`et `BackgroundTask`).
|
||||
|
||||
## Avertissement { #caveat }
|
||||
## Avertissement
|
||||
|
||||
Si vous avez besoin de réaliser des traitements lourds en tâche d'arrière-plan et que vous n'avez pas besoin que ces traitements aient lieu dans le même process (par exemple, pas besoin de partager la mémoire, les variables, etc.), il peut s'avérer profitable d'utiliser des outils plus importants tels que <a href="https://docs.celeryq.dev" class="external-link" target="_blank">Celery</a>.
|
||||
|
||||
Ces outils nécessitent généralement des configurations plus complexes ainsi qu'un gestionnaire de queue de message, comme RabbitMQ ou Redis, mais ils permettent d'exécuter des tâches d'arrière-plan dans différents process, et surtout, sur plusieurs serveurs.
|
||||
Ces outils nécessitent généralement des configurations plus complexes ainsi qu'un gestionnaire de queue de message, comme RabbitMQ ou Redis, mais ils permettent d'exécuter des tâches d'arrière-plan dans différents process, et potentiellement, sur plusieurs serveurs.
|
||||
|
||||
Mais si vous avez besoin d'accéder aux variables et objets de la même application **FastAPI**, ou si vous avez besoin d'effectuer de petites tâches d'arrière-plan (comme envoyer des notifications par email), vous pouvez simplement vous contenter d'utiliser `BackgroundTasks`.
|
||||
|
||||
## Résumé { #recap }
|
||||
## Résumé
|
||||
|
||||
Importez et utilisez `BackgroundTasks` grâce aux paramètres de *fonction de chemin d'accès* et les dépendances pour ajouter des tâches d'arrière-plan.
|
||||
Importez et utilisez `BackgroundTasks` grâce aux paramètres de *fonction de chemin* et les dépendances pour ajouter des tâches d'arrière-plan.
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
# Body - Paramètres multiples { #body-multiple-parameters }
|
||||
# Body - Paramètres multiples
|
||||
|
||||
Maintenant que nous avons vu comment utiliser `Path` et `Query`, voyons des usages plus avancés des déclarations de paramètres du corps de la requête.
|
||||
Maintenant que nous avons vu comment manipuler `Path` et `Query`, voyons comment faire pour le corps d'une requête, communément désigné par le terme anglais "body".
|
||||
|
||||
## Mélanger les paramètres `Path`, `Query` et body { #mix-path-query-and-body-parameters }
|
||||
## Mélanger les paramètres `Path`, `Query` et body
|
||||
|
||||
Tout d'abord, sachez que vous pouvez mélanger librement les déclarations des paramètres `Path`, `Query` et du body, **FastAPI** saura quoi faire.
|
||||
Tout d'abord, sachez que vous pouvez mélanger les déclarations des paramètres `Path`, `Query` et body, **FastAPI** saura quoi faire.
|
||||
|
||||
Et vous pouvez également déclarer des paramètres du body comme étant optionnels, en leur assignant une valeur par défaut à `None` :
|
||||
Vous pouvez également déclarer des paramètres body comme étant optionnels, en leur assignant une valeur par défaut à `None` :
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}
|
||||
|
||||
/// note | Remarque
|
||||
/// note
|
||||
|
||||
Notez que, dans ce cas, l'élément `item` récupéré depuis le body est optionnel. Comme sa valeur par défaut est `None`.
|
||||
Notez que, dans ce cas, le paramètre `item` provenant du `Body` est optionnel (sa valeur par défaut est `None`).
|
||||
|
||||
///
|
||||
|
||||
## Paramètres multiples du body { #multiple-body-parameters }
|
||||
## Paramètres multiples du body
|
||||
|
||||
Dans l'exemple précédent, les chemins d'accès attendraient un body JSON avec les attributs d'un `Item`, par exemple :
|
||||
Dans l'exemple précédent, les opérations de routage attendaient un body JSON avec les attributs d'un `Item`, par exemple :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -29,13 +29,13 @@ Dans l'exemple précédent, les chemins d'accès attendraient un body JSON avec
|
||||
}
|
||||
```
|
||||
|
||||
Mais vous pouvez également déclarer plusieurs paramètres provenant du body, par exemple `item` et `user` :
|
||||
Mais vous pouvez également déclarer plusieurs paramètres provenant de body, par exemple `item` et `user` simultanément :
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}
|
||||
|
||||
Dans ce cas, **FastAPI** détectera qu'il y a plus d'un paramètre du body dans la fonction (il y a deux paramètres qui sont des modèles Pydantic).
|
||||
Dans ce cas, **FastAPI** détectera qu'il y a plus d'un paramètre dans le body (chacun correspondant à un modèle Pydantic).
|
||||
|
||||
Il utilisera alors les noms des paramètres comme clés (noms de champs) dans le body, et s'attendra à recevoir un body semblable à :
|
||||
Il utilisera alors les noms des paramètres comme clés, et s'attendra à recevoir quelque chose de semblable à :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -52,25 +52,25 @@ Il utilisera alors les noms des paramètres comme clés (noms de champs) dans le
|
||||
}
|
||||
```
|
||||
|
||||
/// note | Remarque
|
||||
/// note
|
||||
|
||||
Notez que, bien que `item` ait été déclaré de la même manière qu'auparavant, il est désormais attendu à l'intérieur du body sous la clé `item`.
|
||||
"Notez que, bien que nous ayons déclaré le paramètre `item` de la même manière que précédemment, il est maintenant associé à la clé `item` dans le corps de la requête."`.
|
||||
|
||||
///
|
||||
|
||||
**FastAPI** effectuera la conversion automatique depuis la requête, de sorte que le paramètre `item` reçoive son contenu spécifique, et de même pour `user`.
|
||||
**FastAPI** effectue la conversion de la requête de façon transparente, de sorte que les objets `item` et `user` se trouvent correctement définis.
|
||||
|
||||
Il effectuera la validation des données composées, et les documentera ainsi pour le schéma OpenAPI et la documentation automatique.
|
||||
Il effectue également la validation des données (même imbriquées les unes dans les autres), et permet de les documenter correctement (schéma OpenAPI et documentation auto-générée).
|
||||
|
||||
## Valeurs singulières dans le body { #singular-values-in-body }
|
||||
## Valeurs scalaires dans le body
|
||||
|
||||
De la même façon qu'il existe `Query` et `Path` pour définir des données supplémentaires pour les paramètres de requête et de chemin, **FastAPI** fournit un équivalent `Body`.
|
||||
De la même façon qu'il existe `Query` et `Path` pour définir des données supplémentaires pour les paramètres query et path, **FastAPI** fournit un équivalent `Body`.
|
||||
|
||||
Par exemple, en étendant le modèle précédent, vous pourriez décider d'avoir une autre clé `importance` dans le même body, en plus de `item` et `user`.
|
||||
Par exemple, en étendant le modèle précédent, vous pouvez vouloir ajouter un paramètre `importance` dans le même body, en plus des paramètres `item` et `user`.
|
||||
|
||||
Si vous le déclarez tel quel, comme c'est une valeur singulière, **FastAPI** supposera qu'il s'agit d'un paramètre de requête.
|
||||
Si vous le déclarez tel quel, comme c'est une valeur [scalaire](https://docs.github.com/fr/graphql/reference/scalars), **FastAPI** supposera qu'il s'agit d'un paramètre de requête (`Query`).
|
||||
|
||||
Mais vous pouvez indiquer à **FastAPI** de la traiter comme une autre clé du body en utilisant `Body` :
|
||||
Mais vous pouvez indiquer à **FastAPI** de la traiter comme une variable de body en utilisant `Body` :
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}
|
||||
|
||||
@@ -92,51 +92,51 @@ Dans ce cas, **FastAPI** s'attendra à un body semblable à :
|
||||
}
|
||||
```
|
||||
|
||||
Encore une fois, il convertira les types de données, validera, documentera, etc.
|
||||
Encore une fois, cela convertira les types de données, les validera, permettra de générer la documentation, etc...
|
||||
|
||||
## Paramètres multiples du body et paramètres de requête { #multiple-body-params-and-query }
|
||||
## Paramètres multiples body et query
|
||||
|
||||
Bien entendu, vous pouvez également déclarer des paramètres de requête supplémentaires quand vous en avez besoin, en plus de tout paramètre du body.
|
||||
Bien entendu, vous pouvez déclarer autant de paramètres que vous le souhaitez, en plus des paramètres body déjà déclarés.
|
||||
|
||||
Comme, par défaut, les valeurs singulières sont interprétées comme des paramètres de requête, vous n'avez pas besoin d'ajouter explicitement `Query`, vous pouvez simplement écrire :
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
Ou en Python 3.9 :
|
||||
Par défaut, les valeurs [scalaires](https://docs.github.com/fr/graphql/reference/scalars) sont interprétées comme des paramètres query, donc inutile d'ajouter explicitement `Query`. Vous pouvez juste écrire :
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
Ou bien, en Python 3.10 et supérieur :
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
Par exemple :
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
|
||||
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[27] *}
|
||||
|
||||
/// info
|
||||
|
||||
`Body` possède également les mêmes paramètres supplémentaires de validation et de métadonnées que `Query`, `Path` et d'autres que vous verrez plus tard.
|
||||
`Body` possède les mêmes paramètres de validation additionnels et de gestion des métadonnées que `Query` et `Path`, ainsi que d'autres que nous verrons plus tard.
|
||||
|
||||
///
|
||||
|
||||
## Intégrer un seul paramètre du body { #embed-a-single-body-parameter }
|
||||
## Inclure un paramètre imbriqué dans le body
|
||||
|
||||
Supposons que vous n'ayez qu'un seul paramètre `item` dans le body, provenant d'un modèle Pydantic `Item`.
|
||||
Disons que vous avez seulement un paramètre `item` dans le body, correspondant à un modèle Pydantic `Item`.
|
||||
|
||||
Par défaut, **FastAPI** attendra alors son contenu directement.
|
||||
Par défaut, **FastAPI** attendra sa déclaration directement dans le body.
|
||||
|
||||
Mais si vous voulez qu'il attende un JSON avec une clé `item` contenant le contenu du modèle, comme lorsqu'on déclare des paramètres supplémentaires du body, vous pouvez utiliser le paramètre spécial `embed` de `Body` :
|
||||
Cependant, si vous souhaitez qu'il interprête correctement un JSON avec une clé `item` associée au contenu du modèle, comme cela serait le cas si vous déclariez des paramètres body additionnels, vous pouvez utiliser le paramètre spécial `embed` de `Body` :
|
||||
|
||||
```Python
|
||||
item: Item = Body(embed=True)
|
||||
```
|
||||
|
||||
comme dans :
|
||||
Voici un exemple complet :
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}
|
||||
|
||||
Dans ce cas **FastAPI** s'attendra à un body semblable à :
|
||||
Dans ce cas **FastAPI** attendra un body semblable à :
|
||||
|
||||
```JSON hl_lines="2"
|
||||
{
|
||||
@@ -160,12 +160,12 @@ au lieu de :
|
||||
}
|
||||
```
|
||||
|
||||
## Récapitulatif { #recap }
|
||||
## Pour résumer
|
||||
|
||||
Vous pouvez ajouter plusieurs paramètres du body à votre fonction de chemin d'accès, même si une requête ne peut avoir qu'un seul body.
|
||||
Vous pouvez ajouter plusieurs paramètres body dans votre fonction de routage, même si une requête ne peut avoir qu'un seul body.
|
||||
|
||||
Mais **FastAPI** s'en chargera, vous fournira les bonnes données dans votre fonction, et validera et documentera le schéma correct dans le chemin d'accès.
|
||||
Cependant, **FastAPI** se chargera de faire opérer sa magie, afin de toujours fournir à votre fonction des données correctes, les validera et documentera le schéma associé.
|
||||
|
||||
Vous pouvez également déclarer des valeurs singulières à recevoir dans le body.
|
||||
Vous pouvez également déclarer des valeurs [scalaires](https://docs.github.com/fr/graphql/reference/scalars) à recevoir dans le body.
|
||||
|
||||
Et vous pouvez indiquer à **FastAPI** d'intégrer le body sous une clé même lorsqu'un seul paramètre est déclaré.
|
||||
Et vous pouvez indiquer à **FastAPI** d'inclure le body dans une autre variable, même lorsqu'un seul paramètre est déclaré.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Corps de la requête { #request-body }
|
||||
# Corps de la requête
|
||||
|
||||
Quand vous avez besoin d'envoyer de la donnée depuis un client (comme un navigateur) vers votre API, vous l'envoyez en tant que **corps de requête**.
|
||||
|
||||
Le corps d'une **requête** est de la donnée envoyée par le client à votre API. Le corps d'une **réponse** est la donnée envoyée par votre API au client.
|
||||
|
||||
Votre API aura presque toujours à envoyer un corps de **réponse**. Mais un client n'a pas toujours à envoyer un **corps de requête** : parfois il demande seulement un chemin, peut-être avec quelques paramètres de requête, mais n'envoie pas de corps.
|
||||
Votre API aura presque toujours à envoyer un corps de **réponse**. Mais un client n'a pas toujours à envoyer un corps de **requête**.
|
||||
|
||||
Pour déclarer un corps de **requête**, on utilise les modèles de <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> en profitant de tous leurs avantages et fonctionnalités.
|
||||
|
||||
@@ -18,23 +18,23 @@ Ceci étant découragé, la documentation interactive générée par Swagger UI
|
||||
|
||||
///
|
||||
|
||||
## Importer le `BaseModel` de Pydantic { #import-pydantics-basemodel }
|
||||
## Importez le `BaseModel` de Pydantic
|
||||
|
||||
Commencez par importer la classe `BaseModel` du module `pydantic` :
|
||||
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[2] *}
|
||||
{* ../../docs_src/body/tutorial001.py hl[4] *}
|
||||
|
||||
## Créer votre modèle de données { #create-your-data-model }
|
||||
## Créez votre modèle de données
|
||||
|
||||
Déclarez ensuite votre modèle de données en tant que classe qui hérite de `BaseModel`.
|
||||
|
||||
Utilisez les types Python standard pour tous les attributs :
|
||||
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
|
||||
{* ../../docs_src/body/tutorial001.py hl[7:11] *}
|
||||
|
||||
Tout comme pour la déclaration de paramètres de requête, quand un attribut de modèle a une valeur par défaut, il n'est pas nécessaire. Sinon, cet attribut doit être renseigné dans le corps de la requête. Utilisez `None` pour le rendre simplement optionnel.
|
||||
Tout comme pour la déclaration de paramètres de requête, quand un attribut de modèle a une valeur par défaut, il n'est pas nécessaire. Sinon, cet attribut doit être renseigné dans le corps de la requête. Pour rendre ce champ optionnel simplement, utilisez `None` comme valeur par défaut.
|
||||
|
||||
Par exemple, le modèle ci-dessus déclare un JSON « `object` » (ou `dict` Python) tel que :
|
||||
Par exemple, le modèle ci-dessus déclare un "objet" JSON (ou `dict` Python) tel que :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -45,7 +45,7 @@ Par exemple, le modèle ci-dessus déclare un JSON « `object` » (ou `dict` P
|
||||
}
|
||||
```
|
||||
|
||||
... `description` et `tax` étant des attributs optionnels (avec `None` comme valeur par défaut), ce JSON « `object` » serait aussi valide :
|
||||
...`description` et `tax` étant des attributs optionnels (avec `None` comme valeur par défaut), cet "objet" JSON serait aussi valide :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -54,28 +54,28 @@ Par exemple, le modèle ci-dessus déclare un JSON « `object` » (ou `dict` P
|
||||
}
|
||||
```
|
||||
|
||||
## Le déclarer comme paramètre { #declare-it-as-a-parameter }
|
||||
## Déclarez-le comme paramètre
|
||||
|
||||
Pour l'ajouter à votre *opération de chemin*, déclarez-le comme vous déclareriez des paramètres de chemin ou de requête :
|
||||
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[16] *}
|
||||
{* ../../docs_src/body/tutorial001.py hl[18] *}
|
||||
|
||||
... et déclarez que son type est le modèle que vous avez créé : `Item`.
|
||||
...et déclarez que son type est le modèle que vous avez créé : `Item`.
|
||||
|
||||
## Résultats { #results }
|
||||
## Résultats
|
||||
|
||||
En utilisant uniquement les déclarations de type Python, **FastAPI** réussit à :
|
||||
|
||||
* Lire le contenu de la requête en tant que JSON.
|
||||
* Convertir les types correspondants (si nécessaire).
|
||||
* Valider la donnée.
|
||||
* Si la donnée est invalide, une erreur propre et claire sera renvoyée, indiquant exactement où et quelle était la donnée incorrecte.
|
||||
* Si la donnée est invalide, une erreur propre et claire sera renvoyée, indiquant exactement où était la donnée incorrecte.
|
||||
* Passer la donnée reçue dans le paramètre `item`.
|
||||
* Ce paramètre ayant été déclaré dans la fonction comme étant de type `Item`, vous aurez aussi tout le support offert par l'éditeur (autocomplétion, etc.) pour tous les attributs de ce paramètre et les types de ces attributs.
|
||||
* Générer des définitions <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a> pour votre modèle ; vous pouvez également les utiliser partout ailleurs si cela a du sens pour votre projet.
|
||||
* Ces schémas participeront à la constitution du schéma généré OpenAPI, et seront utilisés par les documentations automatiques <abbr title="User Interfaces - Interfaces utilisateur">UIs</abbr>.
|
||||
* Ce paramètre ayant été déclaré dans la fonction comme étant de type `Item`, vous aurez aussi tout le support offert par l'éditeur (auto-complétion, etc.) pour tous les attributs de ce paramètre et les types de ces attributs.
|
||||
* Générer des définitions <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a> pour votre modèle, qui peuvent être utilisées où vous en avez besoin dans votre projet ensuite.
|
||||
* Ces schémas participeront à la constitution du schéma généré OpenAPI, et seront donc utilisés par les documentations automatiquement générées.
|
||||
|
||||
## Documentation automatique { #automatic-docs }
|
||||
## Documentation automatique
|
||||
|
||||
Les schémas JSON de vos modèles seront intégrés au schéma OpenAPI global de votre application, et seront donc affichés dans la documentation interactive de l'API :
|
||||
|
||||
@@ -85,63 +85,63 @@ Et seront aussi utilisés dans chaque *opération de chemin* de la documentation
|
||||
|
||||
<img src="/img/tutorial/body/image02.png">
|
||||
|
||||
## Support de l'éditeur { #editor-support }
|
||||
## Support de l'éditeur
|
||||
|
||||
Dans votre éditeur, vous aurez des annotations de type et de l'autocomplétion partout dans votre fonction (ce qui n'aurait pas été le cas si vous aviez reçu un `dict` plutôt qu'un modèle Pydantic) :
|
||||
Dans votre éditeur, vous aurez des annotations de types et de l'auto-complétion partout dans votre fonction (ce qui n'aurait pas été le cas si vous aviez utilisé un classique `dict` plutôt qu'un modèle Pydantic) :
|
||||
|
||||
<img src="/img/tutorial/body/image03.png">
|
||||
|
||||
Et vous obtenez aussi des vérifications d'erreurs pour les opérations de types incorrectes :
|
||||
Et vous obtenez aussi de la vérification d'erreur pour les opérations incorrectes de types :
|
||||
|
||||
<img src="/img/tutorial/body/image04.png">
|
||||
|
||||
Ce n'est pas un hasard, ce framework entier a été bâti avec ce design comme objectif.
|
||||
|
||||
Et cela a été rigoureusement testé durant la phase de design, avant toute implémentation, pour vous assurer que cela fonctionnerait avec tous les éditeurs.
|
||||
Et cela a été rigoureusement testé durant la phase de design, avant toute implémentation, pour s'assurer que cela fonctionnerait avec tous les éditeurs.
|
||||
|
||||
Des changements sur Pydantic ont même été faits pour supporter cela.
|
||||
|
||||
Les captures d'écran précédentes ont été prises sur <a href="https://code.visualstudio.com" class="external-link" target="_blank">Visual Studio Code</a>.
|
||||
Les captures d'écrans précédentes ont été prises sur <a href="https://code.visualstudio.com" class="external-link" target="_blank">Visual Studio Code</a>.
|
||||
|
||||
Mais vous auriez le même support de l'éditeur avec <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> et la majorité des autres éditeurs de code Python :
|
||||
Mais vous auriez le même support de l'éditeur avec <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> et la majorité des autres éditeurs de code Python.
|
||||
|
||||
<img src="/img/tutorial/body/image05.png">
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Si vous utilisez <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> comme éditeur, vous pouvez utiliser le plug-in <a href="https://github.com/koxudaxi/pydantic-pycharm-plugin/" class="external-link" target="_blank">Pydantic PyCharm Plugin</a>.
|
||||
Si vous utilisez <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> comme éditeur, vous pouvez utiliser le Plugin <a href="https://github.com/koxudaxi/pydantic-pycharm-plugin/" class="external-link" target="_blank">Pydantic PyCharm Plugin</a>.
|
||||
|
||||
Ce qui améliore le support pour les modèles Pydantic avec :
|
||||
|
||||
* de l'autocomplétion
|
||||
* de l'auto-complétion
|
||||
* des vérifications de type
|
||||
* du « refactoring » (ou remaniement de code)
|
||||
* du "refactoring" (ou remaniement de code)
|
||||
* de la recherche
|
||||
* des inspections
|
||||
* de l'inspection
|
||||
|
||||
///
|
||||
|
||||
## Utiliser le modèle { #use-the-model }
|
||||
## Utilisez le modèle
|
||||
|
||||
Dans la fonction, vous pouvez accéder à tous les attributs de l'objet du modèle directement :
|
||||
|
||||
{* ../../docs_src/body/tutorial002_py310.py *}
|
||||
{* ../../docs_src/body/tutorial002.py hl[21] *}
|
||||
|
||||
## Corps de la requête + paramètres de chemin { #request-body-path-parameters }
|
||||
## Corps de la requête + paramètres de chemin
|
||||
|
||||
Vous pouvez déclarer des paramètres de chemin et un corps de requête pour la même *opération de chemin*.
|
||||
|
||||
**FastAPI** est capable de reconnaître que les paramètres de la fonction qui correspondent aux paramètres de chemin doivent être **récupérés depuis le chemin**, et que les paramètres de fonctions déclarés comme modèles Pydantic devraient être **récupérés depuis le corps de la requête**.
|
||||
|
||||
{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
|
||||
{* ../../docs_src/body/tutorial003.py hl[17:18] *}
|
||||
|
||||
## Corps de la requête + paramètres de chemin et de requête { #request-body-path-query-parameters }
|
||||
## Corps de la requête + paramètres de chemin et de requête
|
||||
|
||||
Vous pouvez aussi déclarer un **corps**, et des paramètres de **chemin** et de **requête** dans la même *opération de chemin*.
|
||||
|
||||
**FastAPI** saura reconnaître chacun d'entre eux et récupérer la bonne donnée au bon endroit.
|
||||
|
||||
{* ../../docs_src/body/tutorial004_py310.py hl[16] *}
|
||||
{* ../../docs_src/body/tutorial004.py hl[18] *}
|
||||
|
||||
Les paramètres de la fonction seront reconnus comme tel :
|
||||
|
||||
@@ -149,16 +149,14 @@ Les paramètres de la fonction seront reconnus comme tel :
|
||||
* Si le paramètre est d'un **type singulier** (comme `int`, `float`, `str`, `bool`, etc.), il sera interprété comme un paramètre de **requête**.
|
||||
* Si le paramètre est déclaré comme ayant pour type un **modèle Pydantic**, il sera interprété comme faisant partie du **corps** de la requête.
|
||||
|
||||
/// note | Remarque
|
||||
/// note
|
||||
|
||||
**FastAPI** saura que la valeur de `q` n'est pas requise grâce à la valeur par défaut `= None`.
|
||||
**FastAPI** saura que la valeur de `q` n'est pas requise grâce à la valeur par défaut `=None`.
|
||||
|
||||
L'annotation de type `str | None` (Python 3.10+) ou `Union` dans `Union[str, None]` (Python 3.9+) n'est pas utilisée par **FastAPI** pour déterminer que la valeur n'est pas requise, il le saura parce qu'elle a une valeur par défaut `= None`.
|
||||
|
||||
Mais ajouter ces annotations de type permettra à votre éditeur de vous offrir un meilleur support et de détecter des erreurs.
|
||||
Le type `Optional` dans `Optional[str]` n'est pas utilisé par **FastAPI**, mais sera utile à votre éditeur pour améliorer le support offert par ce dernier et détecter plus facilement des erreurs de type.
|
||||
|
||||
///
|
||||
|
||||
## Sans Pydantic { #without-pydantic }
|
||||
## Sans Pydantic
|
||||
|
||||
Si vous ne voulez pas utiliser des modèles Pydantic, vous pouvez aussi utiliser des paramètres de **Body**. Pour cela, allez voir la documentation sur [Corps de la requête - Paramètres multiples : Valeurs singulières dans le corps](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.
|
||||
Si vous ne voulez pas utiliser des modèles Pydantic, vous pouvez aussi utiliser des paramètres de **Corps**. Pour cela, allez voir la partie de la documentation sur [Corps de la requête - Paramètres multiples](body-multiple-params.md){.internal-link target=_blank}.
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# <abbr title="En anglais: Debugging">Débogage</abbr> { #debugging }
|
||||
# <abbr title="En anglais: Debugging">Débogage</abbr>
|
||||
|
||||
Vous pouvez connecter le <abbr title="En anglais: debugger">débogueur</abbr> dans votre éditeur, par exemple avec Visual Studio Code ou PyCharm.
|
||||
|
||||
## Appeler `uvicorn` { #call-uvicorn }
|
||||
## Faites appel à `uvicorn`
|
||||
|
||||
Dans votre application FastAPI, importez et exécutez directement `uvicorn` :
|
||||
|
||||
{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *}
|
||||
{* ../../docs_src/debugging/tutorial001.py hl[1,15] *}
|
||||
|
||||
### À propos de `__name__ == "__main__"` { #about-name-main }
|
||||
### À propos de `__name__ == "__main__"`
|
||||
|
||||
Le but principal de `__name__ == "__main__"` est d'avoir du code qui est exécuté lorsque votre fichier est appelé avec :
|
||||
|
||||
@@ -26,7 +26,7 @@ mais qui n'est pas appelé lorsqu'un autre fichier l'importe, comme dans :
|
||||
from myapp import app
|
||||
```
|
||||
|
||||
#### Pour davantage de détails { #more-details }
|
||||
#### Pour davantage de détails
|
||||
|
||||
Imaginons que votre fichier s'appelle `myapp.py`.
|
||||
|
||||
@@ -78,7 +78,7 @@ Pour plus d'informations, consultez <a href="https://docs.python.org/3/library/_
|
||||
|
||||
///
|
||||
|
||||
## Exécuter votre code avec votre <abbr title="En anglais: debugger">débogueur</abbr> { #run-your-code-with-your-debugger }
|
||||
## Exécutez votre code avec votre <abbr title="En anglais: debugger">débogueur</abbr>
|
||||
|
||||
Parce que vous exécutez le serveur Uvicorn directement depuis votre code, vous pouvez appeler votre programme Python (votre application FastAPI) directement depuis le <abbr title="En anglais: debugger">débogueur</abbr>.
|
||||
|
||||
@@ -86,10 +86,10 @@ Parce que vous exécutez le serveur Uvicorn directement depuis votre code, vous
|
||||
|
||||
Par exemple, dans Visual Studio Code, vous pouvez :
|
||||
|
||||
- Allez dans le panneau « Debug ».
|
||||
- « Add configuration... ».
|
||||
- Sélectionnez « Python ».
|
||||
- Lancez le <abbr title="En anglais: debugger">débogueur</abbr> avec l'option « Python: Current File (Integrated Terminal) ».
|
||||
- Cliquer sur l'onglet "Debug" de la barre d'activités de Visual Studio Code.
|
||||
- "Add configuration...".
|
||||
- Sélectionnez "Python".
|
||||
- Lancez le <abbr title="En anglais: debugger">débogueur</abbr> avec l'option "`Python: Current File (Integrated Terminal)`".
|
||||
|
||||
Il démarrera alors le serveur avec votre code **FastAPI**, s'arrêtera à vos points d'arrêt, etc.
|
||||
|
||||
@@ -101,8 +101,8 @@ Voici à quoi cela pourrait ressembler :
|
||||
|
||||
Si vous utilisez Pycharm, vous pouvez :
|
||||
|
||||
- Ouvrez le menu « Run ».
|
||||
- Sélectionnez l'option « Debug... ».
|
||||
- Ouvrir le menu "Run".
|
||||
- Sélectionnez l'option "Debug...".
|
||||
- Un menu contextuel s'affiche alors.
|
||||
- Sélectionnez le fichier à déboguer (dans ce cas, `main.py`).
|
||||
|
||||
|
||||
@@ -1,122 +1,107 @@
|
||||
# Démarrage { #first-steps }
|
||||
# Démarrage
|
||||
|
||||
Le fichier **FastAPI** le plus simple possible pourrait ressembler à ceci :
|
||||
Le fichier **FastAPI** le plus simple possible pourrait ressembler à cela :
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py *}
|
||||
{* ../../docs_src/first_steps/tutorial001.py *}
|
||||
|
||||
Copiez cela dans un fichier `main.py`.
|
||||
Copiez ce code dans un fichier nommé `main.py`.
|
||||
|
||||
Démarrez le serveur en direct :
|
||||
Démarrez le serveur :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting development server 🚀
|
||||
|
||||
Searching for package file structure from directories
|
||||
with <font color="#3465A4">__init__.py</font> files
|
||||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with
|
||||
the following code:
|
||||
|
||||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000/docs</u></font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> tip </font></span> Running in development mode, for production use:
|
||||
<b>fastapi run</b>
|
||||
|
||||
Logs:
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Will watch for changes in these directories:
|
||||
<b>[</b><font color="#4E9A06">'/home/user/code/awesomeapp'</font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C
|
||||
to quit<b>)</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started reloader process <b>[</b><font color="#34E2E2"><b>383138</b></font><b>]</b> using WatchFiles
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>383153</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
<span style="color: green;">INFO</span>: Started reloader process [28720]
|
||||
<span style="color: green;">INFO</span>: Started server process [28722]
|
||||
<span style="color: green;">INFO</span>: Waiting for application startup.
|
||||
<span style="color: green;">INFO</span>: Application startup complete.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Dans la sortie, il y a une ligne semblable à :
|
||||
/// note
|
||||
|
||||
La commande `uvicorn main:app` fait référence à :
|
||||
|
||||
* `main` : le fichier `main.py` (le module Python).
|
||||
* `app` : l'objet créé dans `main.py` via la ligne `app = FastAPI()`.
|
||||
* `--reload` : l'option disant à uvicorn de redémarrer le serveur à chaque changement du code. À ne pas utiliser en production !
|
||||
|
||||
///
|
||||
|
||||
Vous devriez voir dans la console, une ligne semblable à la suivante :
|
||||
|
||||
```hl_lines="4"
|
||||
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
Cette ligne montre l’URL où votre application est servie, sur votre machine locale.
|
||||
Cette ligne montre l'URL par laquelle l'app est actuellement accessible, sur votre machine locale.
|
||||
|
||||
### Vérifiez { #check-it }
|
||||
### Allez voir le résultat
|
||||
|
||||
Ouvrez votre navigateur à l’adresse <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>.
|
||||
Ouvrez votre navigateur à l'adresse <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>.
|
||||
|
||||
Vous verrez la réponse JSON suivante :
|
||||
Vous obtiendrez cette réponse JSON :
|
||||
|
||||
```JSON
|
||||
{"message": "Hello World"}
|
||||
```
|
||||
|
||||
### Documentation interactive de l’API { #interactive-api-docs }
|
||||
### Documentation interactive de l'API
|
||||
|
||||
Allez maintenant sur <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
Rendez-vous sur <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
Vous verrez la documentation interactive de l’API générée automatiquement (fournie par <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>) :
|
||||
Vous verrez la documentation interactive de l'API générée automatiquement (via <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>) :
|
||||
|
||||

|
||||
|
||||
### Documentation alternative de l’API { #alternative-api-docs }
|
||||
### Documentation alternative
|
||||
|
||||
Et maintenant, allez sur <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
|
||||
Ensuite, rendez-vous sur <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
|
||||
|
||||
Vous verrez la documentation automatique alternative (fournie par <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>) :
|
||||
Vous y verrez la documentation alternative (via <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>) :
|
||||
|
||||

|
||||
|
||||
### OpenAPI { #openapi }
|
||||
### OpenAPI
|
||||
|
||||
**FastAPI** génère un « schéma » contenant toute votre API en utilisant le standard **OpenAPI** pour définir des API.
|
||||
**FastAPI** génère un "schéma" contenant toute votre API dans le standard de définition d'API **OpenAPI**.
|
||||
|
||||
#### « Schéma » { #schema }
|
||||
#### "Schéma"
|
||||
|
||||
Un « schéma » est une définition ou une description de quelque chose. Pas le code qui l’implémente, mais uniquement une description abstraite.
|
||||
Un "schéma" est une définition ou une description de quelque chose. Pas le code qui l'implémente, uniquement une description abstraite.
|
||||
|
||||
#### « Schéma » d’API { #api-schema }
|
||||
#### "Schéma" d'API
|
||||
|
||||
Ici, <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> est une spécification qui dicte comment définir le schéma de votre API.
|
||||
|
||||
Cette définition de schéma inclut les chemins de votre API, les paramètres possibles qu’ils prennent, etc.
|
||||
Le schéma inclut les chemins de votre API, les paramètres potentiels de chaque chemin, etc.
|
||||
|
||||
#### « Schéma » de données { #data-schema }
|
||||
#### "Schéma" de données
|
||||
|
||||
Le terme « schéma » peut également faire référence à la forme d’une donnée, comme un contenu JSON.
|
||||
Le terme "schéma" peut aussi faire référence à la forme de la donnée, comme un contenu JSON.
|
||||
|
||||
Dans ce cas, cela désignerait les attributs JSON, ainsi que leurs types, etc.
|
||||
Dans ce cas, cela signifierait les attributs JSON, ainsi que les types de ces attributs, etc.
|
||||
|
||||
#### OpenAPI et JSON Schema { #openapi-and-json-schema }
|
||||
#### OpenAPI et JSON Schema
|
||||
|
||||
OpenAPI définit un schéma d’API pour votre API. Et ce schéma inclut des définitions (ou « schémas ») des données envoyées et reçues par votre API en utilisant **JSON Schema**, le standard pour les schémas de données JSON.
|
||||
**OpenAPI** définit un schéma d'API pour votre API. Il inclut des définitions (ou "schémas") de la donnée envoyée et reçue par votre API en utilisant **JSON Schema**, le standard des schémas de données JSON.
|
||||
|
||||
#### Voir le `openapi.json` { #check-the-openapi-json }
|
||||
#### Allez voir `openapi.json`
|
||||
|
||||
Si vous êtes curieux de voir à quoi ressemble le schéma OpenAPI brut, FastAPI génère automatiquement un JSON (schéma) avec les descriptions de toute votre API.
|
||||
Si vous êtes curieux d'à quoi ressemble le schéma brut **OpenAPI**, **FastAPI** génère automatiquement un (schéma) JSON avec les descriptions de toute votre API.
|
||||
|
||||
Vous pouvez le voir directement à l’adresse : <a href="http://127.0.0.1:8000/openapi.json" class="external-link" target="_blank">http://127.0.0.1:8000/openapi.json</a>.
|
||||
Vous pouvez le voir directement à cette adresse : <a href="http://127.0.0.1:8000/openapi.json" class="external-link" target="_blank">http://127.0.0.1:8000/openapi.json</a>.
|
||||
|
||||
Le schéma devrait ressembler à ceci :
|
||||
|
||||
Il affichera un JSON commençant par quelque chose comme :
|
||||
|
||||
```JSON
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"openapi": "3.0.2",
|
||||
"info": {
|
||||
"title": "FastAPI",
|
||||
"version": "0.1.0"
|
||||
@@ -135,87 +120,79 @@ Il affichera un JSON commençant par quelque chose comme :
|
||||
...
|
||||
```
|
||||
|
||||
#### À quoi sert OpenAPI { #what-is-openapi-for }
|
||||
#### À quoi sert OpenAPI
|
||||
|
||||
Le schéma OpenAPI est ce qui alimente les deux systèmes de documentation interactive inclus.
|
||||
Le schéma **OpenAPI** est ce qui alimente les deux systèmes de documentation interactive.
|
||||
|
||||
Et il existe des dizaines d’alternatives, toutes basées sur OpenAPI. Vous pourriez facilement ajouter n’importe laquelle de ces alternatives à votre application construite avec **FastAPI**.
|
||||
Et il existe des dizaines d'alternatives, toutes basées sur **OpenAPI**. Vous pourriez facilement ajouter n'importe laquelle de ces alternatives à votre application **FastAPI**.
|
||||
|
||||
Vous pourriez également l’utiliser pour générer du code automatiquement, pour les clients qui communiquent avec votre API. Par exemple, des applications frontend, mobiles ou IoT.
|
||||
Vous pourriez aussi l'utiliser pour générer du code automatiquement, pour les clients qui communiquent avec votre API. Comme par exemple, des applications frontend, mobiles ou IOT.
|
||||
|
||||
### Déployer votre application (optionnel) { #deploy-your-app-optional }
|
||||
## Récapitulatif, étape par étape
|
||||
|
||||
Vous pouvez, si vous le souhaitez, déployer votre application FastAPI sur <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>, allez rejoindre la liste d’attente si ce n’est pas déjà fait. 🚀
|
||||
### Étape 1 : import `FastAPI`
|
||||
|
||||
Si vous avez déjà un compte **FastAPI Cloud** (nous vous avons invité depuis la liste d’attente 😉), vous pouvez déployer votre application avec une seule commande.
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[1] *}
|
||||
|
||||
Avant de déployer, vous devez vous assurer que vous êtes connecté :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi login
|
||||
|
||||
You are logged in to FastAPI Cloud 🚀
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Puis déployez votre application :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi deploy
|
||||
|
||||
Deploying to FastAPI Cloud...
|
||||
|
||||
✅ Deployment successful!
|
||||
|
||||
🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
C’est tout ! Vous pouvez maintenant accéder à votre application à cette URL. ✨
|
||||
|
||||
## Récapitulatif, étape par étape { #recap-step-by-step }
|
||||
|
||||
### Étape 1 : importer `FastAPI` { #step-1-import-fastapi }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[1] *}
|
||||
|
||||
`FastAPI` est une classe Python qui fournit toutes les fonctionnalités nécessaires à votre API.
|
||||
`FastAPI` est une classe Python qui fournit toutes les fonctionnalités nécessaires au lancement de votre API.
|
||||
|
||||
/// note | Détails techniques
|
||||
|
||||
`FastAPI` est une classe qui hérite directement de `Starlette`.
|
||||
`FastAPI` est une classe héritant directement de `Starlette`.
|
||||
|
||||
Vous pouvez donc aussi utiliser toutes les fonctionnalités de <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a> avec `FastAPI`.
|
||||
Vous pouvez donc aussi utiliser toutes les fonctionnalités de <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a> depuis `FastAPI`.
|
||||
|
||||
///
|
||||
|
||||
### Étape 2 : créer une « instance » `FastAPI` { #step-2-create-a-fastapi-instance }
|
||||
### Étape 2 : créer une "instance" `FastAPI`
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[3] *}
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[3] *}
|
||||
|
||||
Ici, la variable `app` sera une « instance » de la classe `FastAPI`.
|
||||
Ici la variable `app` sera une "instance" de la classe `FastAPI`.
|
||||
|
||||
Ce sera le point principal d’interaction pour créer toute votre API.
|
||||
Ce sera le point principal d'interaction pour créer toute votre API.
|
||||
|
||||
### Étape 3 : créer un « chemin d’accès » { #step-3-create-a-path-operation }
|
||||
Cette `app` est la même que celle à laquelle fait référence `uvicorn` dans la commande :
|
||||
|
||||
#### Chemin { #path }
|
||||
<div class="termy">
|
||||
|
||||
« Chemin » fait ici référence à la dernière partie de l’URL à partir du premier `/`.
|
||||
```console
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
Donc, dans une URL telle que :
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Si vous créez votre app avec :
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial002.py hl[3] *}
|
||||
|
||||
Et la mettez dans un fichier `main.py`, alors vous appelleriez `uvicorn` avec :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:my_awesome_api --reload
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### Étape 3: créer une *opération de chemin*
|
||||
|
||||
#### Chemin
|
||||
|
||||
Chemin, ou "path" fait référence ici à la dernière partie de l'URL démarrant au premier `/`.
|
||||
|
||||
Donc, dans un URL tel que :
|
||||
|
||||
```
|
||||
https://example.com/items/foo
|
||||
```
|
||||
|
||||
... le chemin serait :
|
||||
...le "path" serait :
|
||||
|
||||
```
|
||||
/items/foo
|
||||
@@ -223,67 +200,66 @@ https://example.com/items/foo
|
||||
|
||||
/// info
|
||||
|
||||
Un « chemin » est aussi couramment appelé « endpoint » ou « route ».
|
||||
Un chemin, ou "path" est aussi souvent appelé route ou "endpoint".
|
||||
|
||||
///
|
||||
|
||||
Lors de la création d’une API, le « chemin » est la manière principale de séparer les « préoccupations » et les « ressources ».
|
||||
#### Opération
|
||||
|
||||
#### Opération { #operation }
|
||||
"Opération" fait référence à une des "méthodes" HTTP.
|
||||
|
||||
« Opération » fait ici référence à l’une des « méthodes » HTTP.
|
||||
|
||||
L’une de :
|
||||
Une de :
|
||||
|
||||
* `POST`
|
||||
* `GET`
|
||||
* `PUT`
|
||||
* `DELETE`
|
||||
|
||||
... et les plus exotiques :
|
||||
...ou une des plus exotiques :
|
||||
|
||||
* `OPTIONS`
|
||||
* `HEAD`
|
||||
* `PATCH`
|
||||
* `TRACE`
|
||||
|
||||
Dans le protocole HTTP, vous pouvez communiquer avec chaque chemin en utilisant une (ou plusieurs) de ces « méthodes ».
|
||||
Dans le protocol HTTP, vous pouvez communiquer avec chaque chemin en utilisant une (ou plus) de ces "méthodes".
|
||||
|
||||
---
|
||||
|
||||
En construisant des APIs, vous utilisez normalement ces méthodes HTTP spécifiques pour effectuer une action précise.
|
||||
En construisant des APIs, vous utilisez généralement ces méthodes HTTP spécifiques pour effectuer une action précise.
|
||||
|
||||
En général, vous utilisez :
|
||||
Généralement vous utilisez :
|
||||
|
||||
* `POST` : pour créer des données.
|
||||
* `GET` : pour lire des données.
|
||||
* `PUT` : pour mettre à jour des données.
|
||||
* `DELETE` : pour supprimer des données.
|
||||
* `POST` : pour créer de la donnée.
|
||||
* `GET` : pour lire de la donnée.
|
||||
* `PUT` : pour mettre à jour de la donnée.
|
||||
* `DELETE` : pour supprimer de la donnée.
|
||||
|
||||
Donc, dans OpenAPI, chacune des méthodes HTTP est appelée une « opération ».
|
||||
Donc, dans **OpenAPI**, chaque méthode HTTP est appelée une "opération".
|
||||
|
||||
Nous allons donc aussi les appeler « opérations ».
|
||||
Nous allons donc aussi appeler ces dernières des "**opérations**".
|
||||
|
||||
#### Définir un « décorateur de chemin d’accès » { #define-a-path-operation-decorator }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[6] *}
|
||||
#### Définir un *décorateur d'opération de chemin*
|
||||
|
||||
Le `@app.get("/")` indique à **FastAPI** que la fonction juste en dessous est chargée de gérer les requêtes qui vont vers :
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[6] *}
|
||||
|
||||
Le `@app.get("/")` dit à **FastAPI** que la fonction en dessous est chargée de gérer les requêtes qui vont sur :
|
||||
|
||||
* le chemin `/`
|
||||
* en utilisant une <abbr title="une méthode HTTP GET"><code>get</code> opération</abbr>
|
||||
* en utilisant une <abbr title="une méthode GET HTTP">opération <code>get</code></abbr>
|
||||
|
||||
/// info | `@décorateur` Info
|
||||
|
||||
Cette syntaxe `@something` en Python est appelée un « décorateur ».
|
||||
Cette syntaxe `@something` en Python est appelée un "décorateur".
|
||||
|
||||
Vous la mettez au-dessus d’une fonction. Comme un joli chapeau décoratif (j’imagine que c’est de là que vient le terme 🤷🏻♂).
|
||||
Vous la mettez au dessus d'une fonction. Comme un joli chapeau décoratif (j'imagine que ce terme vient de là 🤷🏻♂).
|
||||
|
||||
Un « décorateur » prend la fonction en dessous et fait quelque chose avec.
|
||||
Un "décorateur" prend la fonction en dessous et en fait quelque chose.
|
||||
|
||||
Dans notre cas, ce décorateur indique à **FastAPI** que la fonction en dessous correspond au **chemin** `/` avec une **opération** `get`.
|
||||
Dans notre cas, ce décorateur dit à **FastAPI** que la fonction en dessous correspond au **chemin** `/` avec l'**opération** `get`.
|
||||
|
||||
C’est le « décorateur de chemin d’accès ».
|
||||
C'est le "**décorateur d'opération de chemin**".
|
||||
|
||||
///
|
||||
|
||||
@@ -293,7 +269,7 @@ Vous pouvez aussi utiliser les autres opérations :
|
||||
* `@app.put()`
|
||||
* `@app.delete()`
|
||||
|
||||
Ainsi que les plus exotiques :
|
||||
Tout comme celles les plus exotiques :
|
||||
|
||||
* `@app.options()`
|
||||
* `@app.head()`
|
||||
@@ -302,79 +278,58 @@ Ainsi que les plus exotiques :
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Vous êtes libre d’utiliser chaque opération (méthode HTTP) comme vous le souhaitez.
|
||||
Vous êtes libres d'utiliser chaque opération (méthode HTTP) comme vous le désirez.
|
||||
|
||||
**FastAPI** n’impose aucune signification spécifique.
|
||||
**FastAPI** n'impose pas de sens spécifique à chacune d'elle.
|
||||
|
||||
Les informations ici sont présentées comme des lignes directrices, pas comme une obligation.
|
||||
Les informations qui sont présentées ici forment une directive générale, pas des obligations.
|
||||
|
||||
Par exemple, lorsque vous utilisez GraphQL, vous effectuez normalement toutes les actions en utilisant uniquement des opérations `POST`.
|
||||
Par exemple, quand l'on utilise **GraphQL**, toutes les actions sont effectuées en utilisant uniquement des opérations `POST`.
|
||||
|
||||
///
|
||||
|
||||
### Étape 4 : définir la **fonction de chemin d’accès** { #step-4-define-the-path-operation-function }
|
||||
### Étape 4 : définir la **fonction de chemin**.
|
||||
|
||||
Voici notre « fonction de chemin d’accès » :
|
||||
Voici notre "**fonction de chemin**" (ou fonction d'opération de chemin) :
|
||||
|
||||
* **chemin** : `/`.
|
||||
* **opération** : `get`.
|
||||
* **fonction** : la fonction sous le « décorateur » (sous `@app.get("/")`).
|
||||
* **fonction** : la fonction sous le "décorateur" (sous `@app.get("/")`).
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[7] *}
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[7] *}
|
||||
|
||||
C’est une fonction Python.
|
||||
C'est une fonction Python.
|
||||
|
||||
Elle sera appelée par **FastAPI** chaque fois qu’il recevra une requête vers l’URL « / » en utilisant une opération `GET`.
|
||||
Elle sera appelée par **FastAPI** quand une requête sur l'URL `/` sera reçue via une opération `GET`.
|
||||
|
||||
Dans ce cas, c’est une fonction `async`.
|
||||
Ici, c'est une fonction asynchrone (définie avec `async def`).
|
||||
|
||||
---
|
||||
|
||||
Vous pouvez aussi la définir comme une fonction normale au lieu de `async def` :
|
||||
Vous pourriez aussi la définir comme une fonction classique plutôt qu'avec `async def` :
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *}
|
||||
{* ../../docs_src/first_steps/tutorial003.py hl[7] *}
|
||||
|
||||
/// note
|
||||
|
||||
Si vous ne connaissez pas la différence, consultez [Asynchrone : « Pressé ? »](../async.md#in-a-hurry){.internal-link target=_blank}.
|
||||
Si vous ne connaissez pas la différence, allez voir la section [Concurrence : *"Vous êtes pressés ?"*](../async.md#vous-etes-presses){.internal-link target=_blank}.
|
||||
|
||||
///
|
||||
|
||||
### Étape 5 : retourner le contenu { #step-5-return-the-content }
|
||||
### Étape 5 : retourner le contenu
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *}
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[8] *}
|
||||
|
||||
Vous pouvez retourner un `dict`, une `list`, des valeurs uniques comme `str`, `int`, etc.
|
||||
Vous pouvez retourner un dictionnaire (`dict`), une liste (`list`), des valeurs seules comme des chaines de caractères (`str`) et des entiers (`int`), etc.
|
||||
|
||||
Vous pouvez également retourner des modèles Pydantic (vous en verrez plus à ce sujet plus tard).
|
||||
Vous pouvez aussi retourner des models **Pydantic** (qui seront détaillés plus tard).
|
||||
|
||||
Il existe de nombreux autres objets et modèles qui seront automatiquement convertis en JSON (y compris des ORM, etc.). Essayez d’utiliser vos favoris, il est fort probable qu’ils soient déjà pris en charge.
|
||||
Il y a de nombreux autres objets et modèles qui seront automatiquement convertis en JSON. Essayez d'utiliser vos favoris, il est fort probable qu'ils soient déjà supportés.
|
||||
|
||||
### Étape 6 : le déployer { #step-6-deploy-it }
|
||||
|
||||
Déployez votre application sur **<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>** avec une seule commande : `fastapi deploy`. 🎉
|
||||
|
||||
#### À propos de FastAPI Cloud { #about-fastapi-cloud }
|
||||
|
||||
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>** est construit par le même auteur et l’équipe derrière **FastAPI**.
|
||||
|
||||
Il simplifie le processus de **construction**, de **déploiement** et d’**accès** à une API avec un minimum d’effort.
|
||||
|
||||
Il apporte la même **expérience développeur** de création d’applications avec FastAPI au **déploiement** dans le cloud. 🎉
|
||||
|
||||
FastAPI Cloud est le sponsor principal et le financeur des projets open source *FastAPI and friends*. ✨
|
||||
|
||||
#### Déployer sur d’autres fournisseurs cloud { #deploy-to-other-cloud-providers }
|
||||
|
||||
FastAPI est open source et basé sur des standards. Vous pouvez déployer des applications FastAPI chez n’importe quel fournisseur cloud de votre choix.
|
||||
|
||||
Suivez les guides de votre fournisseur cloud pour y déployer des applications FastAPI. 🤓
|
||||
|
||||
## Récapitulatif { #recap }
|
||||
## Récapitulatif
|
||||
|
||||
* Importez `FastAPI`.
|
||||
* Créez une instance `app`.
|
||||
* Écrivez un **décorateur de chemin d’accès** avec des décorateurs comme `@app.get("/")`.
|
||||
* Définissez une **fonction de chemin d’accès** ; par exemple, `def root(): ...`.
|
||||
* Exécutez le serveur de développement avec la commande `fastapi dev`.
|
||||
* Déployez éventuellement votre application avec `fastapi deploy`.
|
||||
* Créez une instance d'`app`.
|
||||
* Ajoutez une **décorateur d'opération de chemin** (tel que `@app.get("/")`).
|
||||
* Ajoutez une **fonction de chemin** (telle que `def root(): ...` comme ci-dessus).
|
||||
* Lancez le serveur de développement (avec `uvicorn main:app --reload`).
|
||||
|
||||
@@ -1,53 +1,29 @@
|
||||
# Tutoriel - Guide utilisateur { #tutorial-user-guide }
|
||||
# Tutoriel - Guide utilisateur - Introduction
|
||||
|
||||
Ce tutoriel vous montre comment utiliser **FastAPI** avec la plupart de ses fonctionnalités, étape par étape.
|
||||
|
||||
Chaque section s'appuie progressivement sur les précédentes, mais elle est structurée de manière à séparer les sujets, afin que vous puissiez aller directement à l'un d'entre eux pour répondre à vos besoins spécifiques d'API.
|
||||
Chaque section s'appuie progressivement sur les précédentes, mais elle est structurée de manière à séparer les sujets, afin que vous puissiez aller directement à l'un d'entre eux pour résoudre vos besoins spécifiques en matière d'API.
|
||||
|
||||
Il est également conçu pour servir de référence ultérieure, afin que vous puissiez revenir voir exactement ce dont vous avez besoin.
|
||||
Il est également conçu pour fonctionner comme une référence future.
|
||||
|
||||
## Exécuter le code { #run-the-code }
|
||||
Vous pouvez donc revenir et voir exactement ce dont vous avez besoin.
|
||||
|
||||
## Exécuter le code
|
||||
|
||||
Tous les blocs de code peuvent être copiés et utilisés directement (il s'agit en fait de fichiers Python testés).
|
||||
|
||||
Pour exécuter l'un de ces exemples, copiez le code dans un fichier `main.py`, et démarrez `fastapi dev` avec :
|
||||
Pour exécuter l'un de ces exemples, copiez le code dans un fichier `main.py`, et commencez `uvicorn` avec :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting development server 🚀
|
||||
|
||||
Searching for package file structure from directories
|
||||
with <font color="#3465A4">__init__.py</font> files
|
||||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with
|
||||
the following code:
|
||||
|
||||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000/docs</u></font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> tip </font></span> Running in development mode, for production use:
|
||||
<b>fastapi run</b>
|
||||
|
||||
Logs:
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Will watch for changes in these directories:
|
||||
<b>[</b><font color="#4E9A06">'/home/user/code/awesomeapp'</font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C
|
||||
to quit<b>)</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started reloader process <b>[</b><font color="#34E2E2"><b>383138</b></font><b>]</b> using WatchFiles
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>383153</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
<span style="color: green;">INFO</span>: Started reloader process [28720]
|
||||
<span style="color: green;">INFO</span>: Started server process [28722]
|
||||
<span style="color: green;">INFO</span>: Waiting for application startup.
|
||||
<span style="color: green;">INFO</span>: Application startup complete.
|
||||
```
|
||||
|
||||
</div>
|
||||
@@ -58,33 +34,45 @@ L'utiliser dans votre éditeur est ce qui vous montre vraiment les avantages de
|
||||
|
||||
---
|
||||
|
||||
## Installer FastAPI { #install-fastapi }
|
||||
## Installer FastAPI
|
||||
|
||||
La première étape consiste à installer FastAPI.
|
||||
|
||||
Assurez-vous de créer un [environnement virtuel](../virtual-environments.md){.internal-link target=_blank}, de l'activer, puis **d'installer FastAPI** :
|
||||
Pour le tutoriel, vous voudrez peut-être l'installer avec toutes les dépendances et fonctionnalités optionnelles :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install "fastapi[standard]"
|
||||
$ pip install fastapi[all]
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
/// note | Remarque
|
||||
... qui comprend également `uvicorn`, que vous pouvez utiliser comme serveur pour exécuter votre code.
|
||||
|
||||
Lorsque vous installez avec `pip install "fastapi[standard]"` cela inclut des dépendances standard optionnelles par défaut, y compris `fastapi-cloud-cli`, qui vous permet de déployer sur <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>.
|
||||
/// note
|
||||
|
||||
Si vous ne souhaitez pas avoir ces dépendances optionnelles, vous pouvez à la place installer `pip install fastapi`.
|
||||
Vous pouvez également l'installer pièce par pièce.
|
||||
|
||||
Si vous souhaitez installer les dépendances standard mais sans `fastapi-cloud-cli`, vous pouvez installer avec `pip install "fastapi[standard-no-fastapi-cloud-cli]"`.
|
||||
C'est ce que vous feriez probablement une fois que vous voudrez déployer votre application en production :
|
||||
|
||||
```
|
||||
pip install fastapi
|
||||
```
|
||||
|
||||
Installez également `uvicorn` pour qu'il fonctionne comme serveur :
|
||||
|
||||
```
|
||||
pip install uvicorn
|
||||
```
|
||||
|
||||
Et la même chose pour chacune des dépendances facultatives que vous voulez utiliser.
|
||||
|
||||
///
|
||||
|
||||
## Guide d'utilisation avancé { #advanced-user-guide }
|
||||
## Guide utilisateur avancé
|
||||
|
||||
Il existe également un **Guide d'utilisation avancé** que vous pouvez lire plus tard après ce **Tutoriel - Guide d'utilisation**.
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Paramètres de chemin et validations numériques { #path-parameters-and-numeric-validations }
|
||||
# Paramètres de chemin et validations numériques
|
||||
|
||||
De la même façon que vous pouvez déclarer plus de validations et de métadonnées pour les paramètres de requête avec `Query`, vous pouvez déclarer le même type de validations et de métadonnées pour les paramètres de chemin avec `Path`.
|
||||
|
||||
## Importer `Path` { #import-path }
|
||||
## Importer Path
|
||||
|
||||
Tout d'abord, importez `Path` de `fastapi`, et importez `Annotated` :
|
||||
|
||||
@@ -14,11 +14,11 @@ FastAPI a ajouté le support pour `Annotated` (et a commencé à le recommander)
|
||||
|
||||
Si vous avez une version plus ancienne, vous obtiendrez des erreurs en essayant d'utiliser `Annotated`.
|
||||
|
||||
Assurez-vous de [Mettre à niveau la version de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} à la version 0.95.1 à minima avant d'utiliser `Annotated`.
|
||||
Assurez-vous de [Mettre à jour la version de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} à la version 0.95.1 à minima avant d'utiliser `Annotated`.
|
||||
|
||||
///
|
||||
|
||||
## Déclarer des métadonnées { #declare-metadata }
|
||||
## Déclarer des métadonnées
|
||||
|
||||
Vous pouvez déclarer les mêmes paramètres que pour `Query`.
|
||||
|
||||
@@ -26,15 +26,15 @@ Par exemple, pour déclarer une valeur de métadonnée `title` pour le paramètr
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}
|
||||
|
||||
/// note | Remarque
|
||||
/// note
|
||||
|
||||
Un paramètre de chemin est toujours requis car il doit faire partie du chemin. Même si vous l'avez déclaré avec `None` ou défini une valeur par défaut, cela ne changerait rien, il serait toujours requis.
|
||||
|
||||
///
|
||||
|
||||
## Ordonner les paramètres comme vous le souhaitez { #order-the-parameters-as-you-need }
|
||||
## Ordonnez les paramètres comme vous le souhaitez
|
||||
|
||||
/// tip | Astuce
|
||||
/// tip
|
||||
|
||||
Ce n'est probablement pas aussi important ou nécessaire si vous utilisez `Annotated`.
|
||||
|
||||
@@ -46,7 +46,7 @@ Et vous n'avez pas besoin de déclarer autre chose pour ce paramètre, donc vous
|
||||
|
||||
Mais vous avez toujours besoin d'utiliser `Path` pour le paramètre de chemin `item_id`. Et vous ne voulez pas utiliser `Annotated` pour une raison quelconque.
|
||||
|
||||
Python se plaindra si vous mettez une valeur avec une « valeur par défaut » avant une valeur qui n'a pas de « valeur par défaut ».
|
||||
Python se plaindra si vous mettez une valeur avec une "défaut" avant une valeur qui n'a pas de "défaut".
|
||||
|
||||
Mais vous pouvez les réorganiser, et avoir la valeur sans défaut (le paramètre de requête `q`) en premier.
|
||||
|
||||
@@ -54,15 +54,15 @@ Cela n'a pas d'importance pour **FastAPI**. Il détectera les paramètres par le
|
||||
|
||||
Ainsi, vous pouvez déclarer votre fonction comme suit :
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *}
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial002.py hl[7] *}
|
||||
|
||||
Mais gardez à l'esprit que si vous utilisez `Annotated`, vous n'aurez pas ce problème, cela n'aura pas d'importance car vous n'utilisez pas les valeurs par défaut des paramètres de fonction pour `Query()` ou `Path()`.
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py *}
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py hl[10] *}
|
||||
|
||||
## Ordonner les paramètres comme vous le souhaitez, astuces { #order-the-parameters-as-you-need-tricks }
|
||||
## Ordonnez les paramètres comme vous le souhaitez (astuces)
|
||||
|
||||
/// tip | Astuce
|
||||
/// tip
|
||||
|
||||
Ce n'est probablement pas aussi important ou nécessaire si vous utilisez `Annotated`.
|
||||
|
||||
@@ -77,29 +77,38 @@ Si vous voulez :
|
||||
* les avoir dans un ordre différent
|
||||
* ne pas utiliser `Annotated`
|
||||
|
||||
... Python a une petite syntaxe spéciale pour cela.
|
||||
...Python a une petite syntaxe spéciale pour cela.
|
||||
|
||||
Passez `*`, comme premier paramètre de la fonction.
|
||||
|
||||
Python ne fera rien avec ce `*`, mais il saura que tous les paramètres suivants doivent être appelés comme arguments "mots-clés" (paires clé-valeur), également connus sous le nom de <abbr title="De : K-ey W-ord Arg-uments"><code>kwargs</code></abbr>. Même s'ils n'ont pas de valeur par défaut.
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *}
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial003.py hl[7] *}
|
||||
|
||||
### Mieux avec `Annotated` { #better-with-annotated }
|
||||
# Avec `Annotated`
|
||||
|
||||
Gardez à l'esprit que si vous utilisez `Annotated`, comme vous n'utilisez pas les valeurs par défaut des paramètres de fonction, vous n'aurez pas ce problème, et vous n'aurez probablement pas besoin d'utiliser `*`.
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *}
|
||||
|
||||
## Validations numériques : supérieur ou égal { #number-validations-greater-than-or-equal }
|
||||
## Validations numériques : supérieur ou égal
|
||||
|
||||
Avec `Query` et `Path` (et d'autres que vous verrez plus tard) vous pouvez déclarer des contraintes numériques.
|
||||
|
||||
Ici, avec `ge=1`, `item_id` devra être un nombre entier « `g`reater than or `e`qual » à `1`.
|
||||
Ici, avec `ge=1`, `item_id` devra être un nombre entier "`g`reater than or `e`qual" à `1`.
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *}
|
||||
|
||||
## Validations numériques : supérieur et inférieur ou égal { #number-validations-greater-than-and-less-than-or-equal }
|
||||
## Validations numériques : supérieur ou égal et inférieur ou égal
|
||||
|
||||
La même chose s'applique pour :
|
||||
|
||||
* `gt` : `g`reater `t`han
|
||||
* `le` : `l`ess than or `e`qual
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *}
|
||||
|
||||
## Validations numériques : supérieur et inférieur ou égal
|
||||
|
||||
La même chose s'applique pour :
|
||||
|
||||
@@ -108,7 +117,7 @@ La même chose s'applique pour :
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py hl[10] *}
|
||||
|
||||
## Validations numériques : flottants, supérieur et inférieur { #number-validations-floats-greater-than-and-less-than }
|
||||
## Validations numériques : flottants, supérieur et inférieur
|
||||
|
||||
Les validations numériques fonctionnent également pour les valeurs `float`.
|
||||
|
||||
@@ -120,7 +129,7 @@ Et la même chose pour <abbr title="less than"><code>lt</code></abbr>.
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *}
|
||||
|
||||
## Pour résumer { #recap }
|
||||
## Pour résumer
|
||||
|
||||
Avec `Query`, `Path` (et d'autres que vous verrez plus tard) vous pouvez déclarer des métadonnées et des validations de chaînes de la même manière qu'avec les [Paramètres de requête et validations de chaînes](query-params-str-validations.md){.internal-link target=_blank}.
|
||||
|
||||
|
||||
@@ -1,196 +1,205 @@
|
||||
# Paramètres de chemin { #path-parameters }
|
||||
# Paramètres de chemin
|
||||
|
||||
Vous pouvez déclarer des « paramètres » ou « variables » de chemin avec la même syntaxe utilisée par les chaînes de format Python :
|
||||
Vous pouvez déclarer des "paramètres" ou "variables" de chemin avec la même syntaxe que celle utilisée par le
|
||||
<a href="https://docs.python.org/fr/3/library/string.html#format-string-syntax" class="external-link" target="_blank">formatage de chaîne Python</a> :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *}
|
||||
|
||||
La valeur du paramètre de chemin `item_id` sera transmise à votre fonction dans l'argument `item_id`.
|
||||
{* ../../docs_src/path_params/tutorial001.py hl[6:7] *}
|
||||
|
||||
Donc, si vous exécutez cet exemple et allez sur <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a>, vous verrez comme réponse :
|
||||
La valeur du paramètre `item_id` sera transmise à la fonction dans l'argument `item_id`.
|
||||
|
||||
Donc, si vous exécutez cet exemple et allez sur <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a>,
|
||||
vous verrez comme réponse :
|
||||
|
||||
```JSON
|
||||
{"item_id":"foo"}
|
||||
```
|
||||
|
||||
## Paramètres de chemin typés { #path-parameters-with-types }
|
||||
## Paramètres de chemin typés
|
||||
|
||||
Vous pouvez déclarer le type d'un paramètre de chemin dans la fonction, en utilisant les annotations de type Python standard :
|
||||
Vous pouvez déclarer le type d'un paramètre de chemin dans la fonction, en utilisant les annotations de type Python :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial002_py39.py hl[7] *}
|
||||
|
||||
{* ../../docs_src/path_params/tutorial002.py hl[7] *}
|
||||
|
||||
Ici, `item_id` est déclaré comme `int`.
|
||||
|
||||
/// check | Vérifications
|
||||
/// check | vérifier
|
||||
|
||||
Cela vous apporte la prise en charge par l'éditeur dans votre fonction, avec vérifications d'erreurs, autocomplétion, etc.
|
||||
Ceci vous permettra d'obtenir des fonctionnalités de l'éditeur dans votre fonction, telles
|
||||
que des vérifications d'erreur, de l'auto-complétion, etc.
|
||||
|
||||
///
|
||||
|
||||
## <abbr title="également appelé : sérialisation, parsing, marshalling">Conversion</abbr> de données { #data-conversion }
|
||||
## <abbr title="aussi appelé sérialisation, ou parfois parsing ou marshalling en anglais">Conversion</abbr> de données
|
||||
|
||||
Si vous exécutez cet exemple et ouvrez votre navigateur sur <a href="http://127.0.0.1:8000/items/3" class="external-link" target="_blank">http://127.0.0.1:8000/items/3</a>, vous verrez comme réponse :
|
||||
Si vous exécutez cet exemple et allez sur <a href="http://127.0.0.1:8000/items/3" class="external-link" target="_blank">http://127.0.0.1:8000/items/3</a>, vous aurez comme réponse :
|
||||
|
||||
```JSON
|
||||
{"item_id":3}
|
||||
```
|
||||
|
||||
/// check | Vérifications
|
||||
/// check | vérifier
|
||||
|
||||
Remarquez que la valeur reçue par votre fonction (et renvoyée) est `3`, en tant qu'entier (`int`) Python, pas la chaîne de caractères « 3 ».
|
||||
Comme vous l'avez remarqué, la valeur reçue par la fonction (et renvoyée ensuite) est `3`,
|
||||
en tant qu'entier (`int`) Python, pas la chaîne de caractères (`string`) `"3"`.
|
||||
|
||||
Ainsi, avec cette déclaration de type, **FastAPI** vous fournit automatiquement le <abbr title="conversion de la chaîne de caractères provenant d'une requête HTTP en données Python">« parsing »</abbr> de la requête.
|
||||
Grâce aux déclarations de types, **FastAPI** fournit du
|
||||
<abbr title="conversion de la chaîne de caractères venant de la requête HTTP en données Python">"parsing"</abbr> automatique.
|
||||
|
||||
///
|
||||
|
||||
## Validation de données { #data-validation }
|
||||
## Validation de données
|
||||
|
||||
Mais si vous allez dans le navigateur sur <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a>, vous verrez une belle erreur HTTP :
|
||||
Si vous allez sur <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a>, vous aurez une belle erreur HTTP :
|
||||
|
||||
```JSON
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
"type": "int_parsing",
|
||||
"loc": [
|
||||
"path",
|
||||
"item_id"
|
||||
],
|
||||
"msg": "Input should be a valid integer, unable to parse string as an integer",
|
||||
"input": "foo"
|
||||
}
|
||||
]
|
||||
"detail": [
|
||||
{
|
||||
"loc": [
|
||||
"path",
|
||||
"item_id"
|
||||
],
|
||||
"msg": "value is not a valid integer",
|
||||
"type": "type_error.integer"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
car le paramètre de chemin `item_id` a pour valeur « foo », qui n'est pas un `int`.
|
||||
car le paramètre de chemin `item_id` possède comme valeur `"foo"`, qui ne peut pas être convertie en entier (`int`).
|
||||
|
||||
La même erreur apparaîtrait si vous fournissiez un `float` au lieu d'un `int`, comme ici : <a href="http://127.0.0.1:8000/items/4.2" class="external-link" target="_blank">http://127.0.0.1:8000/items/4.2</a>
|
||||
La même erreur se produira si vous passez un nombre flottant (`float`) et non un entier, comme ici
|
||||
<a href="http://127.0.0.1:8000/items/4.2" class="external-link" target="_blank">http://127.0.0.1:8000/items/4.2</a>.
|
||||
|
||||
/// check | Vérifications
|
||||
|
||||
Ainsi, avec la même déclaration de type Python, **FastAPI** vous fournit la validation de données.
|
||||
/// check | vérifier
|
||||
|
||||
Remarquez que l'erreur indique clairement l'endroit exact où la validation n'a pas réussi.
|
||||
Donc, avec ces mêmes déclarations de type Python, **FastAPI** vous fournit de la validation de données.
|
||||
|
||||
C'est incroyablement utile lors du développement et du débogage du code qui interagit avec votre API.
|
||||
Notez que l'erreur mentionne le point exact où la validation n'a pas réussi.
|
||||
|
||||
Ce qui est incroyablement utile au moment de développer et débugger du code qui interagit avec votre API.
|
||||
|
||||
///
|
||||
|
||||
## Documentation { #documentation }
|
||||
## Documentation
|
||||
|
||||
Et lorsque vous ouvrez votre navigateur sur <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, vous verrez une documentation d'API automatique et interactive comme :
|
||||
Et quand vous vous rendez sur <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, vous verrez la
|
||||
documentation générée automatiquement et interactive :
|
||||
|
||||
<img src="/img/tutorial/path-params/image01.png">
|
||||
|
||||
/// check | Vérifications
|
||||
/// info
|
||||
|
||||
À nouveau, simplement avec cette même déclaration de type Python, **FastAPI** vous fournit une documentation interactive automatique (intégrant Swagger UI).
|
||||
À nouveau, en utilisant uniquement les déclarations de type Python, **FastAPI** vous fournit automatiquement une documentation interactive (via Swagger UI).
|
||||
|
||||
Remarquez que le paramètre de chemin est déclaré comme entier.
|
||||
On voit bien dans la documentation que `item_id` est déclaré comme entier.
|
||||
|
||||
///
|
||||
|
||||
## Les avantages d'une norme, documentation alternative { #standards-based-benefits-alternative-documentation }
|
||||
## Les avantages d'avoir une documentation basée sur une norme, et la documentation alternative.
|
||||
|
||||
Et comme le schéma généré suit la norme <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md" class="external-link" target="_blank">OpenAPI</a>, il existe de nombreux outils compatibles.
|
||||
Le schéma généré suivant la norme <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md" class="external-link" target="_blank">OpenAPI</a>,
|
||||
il existe de nombreux outils compatibles.
|
||||
|
||||
Grâce à cela, **FastAPI** fournit lui-même une documentation d'API alternative (utilisant ReDoc), accessible sur <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> :
|
||||
Grâce à cela, **FastAPI** lui-même fournit une documentation alternative (utilisant ReDoc), qui peut être lue
|
||||
sur <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> :
|
||||
|
||||
<img src="/img/tutorial/path-params/image02.png">
|
||||
|
||||
De la même façon, il existe de nombreux outils compatibles, y compris des outils de génération de code pour de nombreux langages.
|
||||
De la même façon, il existe bien d'autres outils compatibles, y compris des outils de génération de code
|
||||
pour de nombreux langages.
|
||||
|
||||
## Pydantic { #pydantic }
|
||||
## Pydantic
|
||||
|
||||
Toute la validation de données est effectuée sous le capot par <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>, vous en bénéficiez donc pleinement. Vous savez ainsi que vous êtes entre de bonnes mains.
|
||||
Toute la validation de données est effectué en arrière-plan avec <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>,
|
||||
dont vous bénéficierez de tous les avantages. Vous savez donc que vous êtes entre de bonnes mains.
|
||||
|
||||
Vous pouvez utiliser les mêmes déclarations de type avec `str`, `float`, `bool` et de nombreux autres types de données complexes.
|
||||
## L'ordre importe
|
||||
|
||||
Plusieurs d'entre eux sont explorés dans les prochains chapitres du tutoriel.
|
||||
Quand vous créez des *fonctions de chemins*, vous pouvez vous retrouver dans une situation où vous avez un chemin fixe.
|
||||
|
||||
## L'ordre importe { #order-matters }
|
||||
Tel que `/users/me`, disons pour récupérer les données sur l'utilisateur actuel.
|
||||
|
||||
Quand vous créez des *chemins d'accès*, vous pouvez vous retrouver dans une situation avec un chemin fixe.
|
||||
Et vous avez un second chemin : `/users/{user_id}` pour récupérer de la donnée sur un utilisateur spécifique grâce à son identifiant d'utilisateur
|
||||
|
||||
Par exemple `/users/me`, disons pour récupérer les données de l'utilisateur actuel.
|
||||
Les *fonctions de chemin* étant évaluées dans l'ordre, il faut s'assurer que la fonction correspondant à `/users/me` est déclarée avant celle de `/users/{user_id}` :
|
||||
|
||||
Et vous pouvez aussi avoir un chemin `/users/{user_id}` pour récupérer des données sur un utilisateur spécifique grâce à un identifiant d'utilisateur.
|
||||
{* ../../docs_src/path_params/tutorial003.py hl[6,11] *}
|
||||
|
||||
Comme les *chemins d'accès* sont évalués dans l'ordre, vous devez vous assurer que le chemin `/users/me` est déclaré avant celui de `/users/{user_id}` :
|
||||
Sinon, le chemin `/users/{user_id}` correspondrait aussi à `/users/me`, la fonction "croyant" qu'elle a reçu un paramètre `user_id` avec pour valeur `"me"`.
|
||||
|
||||
{* ../../docs_src/path_params/tutorial003_py39.py hl[6,11] *}
|
||||
## Valeurs prédéfinies
|
||||
|
||||
Sinon, le chemin `/users/{user_id}` correspondrait aussi à `/users/me`, « pensant » qu'il reçoit un paramètre `user_id` avec la valeur « me ».
|
||||
Si vous avez une *fonction de chemin* qui reçoit un *paramètre de chemin*, mais que vous voulez que les valeurs possibles des paramètres soient prédéfinies, vous pouvez utiliser les <abbr title="Enumeration">`Enum`</abbr> de Python.
|
||||
|
||||
De même, vous ne pouvez pas redéfinir un chemin d'accès :
|
||||
### Création d'un `Enum`
|
||||
|
||||
{* ../../docs_src/path_params/tutorial003b_py39.py hl[6,11] *}
|
||||
Importez `Enum` et créez une sous-classe qui hérite de `str` et `Enum`.
|
||||
|
||||
Le premier sera toujours utilisé puisque le chemin correspond en premier.
|
||||
En héritant de `str` la documentation sera capable de savoir que les valeurs doivent être de type `string` et pourra donc afficher cette `Enum` correctement.
|
||||
|
||||
## Valeurs prédéfinies { #predefined-values }
|
||||
Créez ensuite des attributs de classe avec des valeurs fixes, qui seront les valeurs autorisées pour cette énumération.
|
||||
|
||||
Si vous avez un *chemin d'accès* qui reçoit un *paramètre de chemin*, mais que vous voulez que les valeurs possibles de ce *paramètre de chemin* soient prédéfinies, vous pouvez utiliser une <abbr title="Enumeration">`Enum`</abbr> Python standard.
|
||||
{* ../../docs_src/path_params/tutorial005.py hl[1,6:9] *}
|
||||
|
||||
### Créer une classe `Enum` { #create-an-enum-class }
|
||||
/// info
|
||||
|
||||
Importez `Enum` et créez une sous-classe qui hérite de `str` et de `Enum`.
|
||||
|
||||
En héritant de `str`, la documentation de l'API saura que les valeurs doivent être de type `string` et pourra donc s'afficher correctement.
|
||||
|
||||
Créez ensuite des attributs de classe avec des valeurs fixes, qui seront les valeurs valides disponibles :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005_py39.py hl[1,6:9] *}
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Si vous vous demandez, « AlexNet », « ResNet » et « LeNet » sont juste des noms de <abbr title="Techniquement, architectures de modèles de Deep Learning">modèles</abbr> de Machine Learning.
|
||||
<a href="https://docs.python.org/3/library/enum.html" class="external-link" target="_blank">Les énumérations (ou enums) sont disponibles en Python</a> depuis la version 3.4.
|
||||
|
||||
///
|
||||
|
||||
### Déclarer un paramètre de chemin { #declare-a-path-parameter }
|
||||
/// tip | Astuce
|
||||
|
||||
Créez ensuite un *paramètre de chemin* avec une annotation de type utilisant la classe d'énumération que vous avez créée (`ModelName`) :
|
||||
Pour ceux qui se demandent, "AlexNet", "ResNet", et "LeNet" sont juste des noms de <abbr title="Techniquement, des architectures de modèles">modèles</abbr> de Machine Learning.
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005_py39.py hl[16] *}
|
||||
///
|
||||
|
||||
### Consulter la documentation { #check-the-docs }
|
||||
### Déclarer un paramètre de chemin
|
||||
|
||||
Comme les valeurs disponibles pour le *paramètre de chemin* sont prédéfinies, la documentation interactive peut les afficher clairement :
|
||||
Créez ensuite un *paramètre de chemin* avec une annotation de type désignant l'énumération créée précédemment (`ModelName`) :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005.py hl[16] *}
|
||||
|
||||
### Documentation
|
||||
|
||||
Les valeurs disponibles pour le *paramètre de chemin* sont bien prédéfinies, la documentation les affiche correctement :
|
||||
|
||||
<img src="/img/tutorial/path-params/image03.png">
|
||||
|
||||
### Travailler avec les *énumérations* Python { #working-with-python-enumerations }
|
||||
### Manipuler les *énumérations* Python
|
||||
|
||||
La valeur du *paramètre de chemin* sera un *membre d'énumération*.
|
||||
La valeur du *paramètre de chemin* sera un des "membres" de l'énumération.
|
||||
|
||||
#### Comparer des *membres d'énumération* { #compare-enumeration-members }
|
||||
#### Comparer les *membres d'énumération*
|
||||
|
||||
Vous pouvez le comparer avec le *membre d'énumération* dans votre enum `ModelName` :
|
||||
Vous pouvez comparer ce paramètre avec les membres de votre énumération `ModelName` :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005_py39.py hl[17] *}
|
||||
{* ../../docs_src/path_params/tutorial005.py hl[17] *}
|
||||
|
||||
#### Obtenir la *valeur de l'énumération* { #get-the-enumeration-value }
|
||||
#### Récupérer la *valeur de l'énumération*
|
||||
|
||||
Vous pouvez obtenir la valeur réelle (une `str` dans ce cas) avec `model_name.value`, ou en général, `votre_membre_d_enum.value` :
|
||||
Vous pouvez obtenir la valeur réel d'un membre (une chaîne de caractères ici), avec `model_name.value`, ou en général, `votre_membre_d'enum.value` :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005_py39.py hl[20] *}
|
||||
{* ../../docs_src/path_params/tutorial005.py hl[20] *}
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Vous pouvez aussi accéder à la valeur « lenet » avec `ModelName.lenet.value`.
|
||||
Vous pouvez aussi accéder la valeur `"lenet"` avec `ModelName.lenet.value`.
|
||||
|
||||
///
|
||||
|
||||
#### Retourner des *membres d'énumération* { #return-enumeration-members }
|
||||
#### Retourner des *membres d'énumération*
|
||||
|
||||
Vous pouvez retourner des *membres d'énumération* depuis votre *chemin d'accès*, même imbriqués dans un corps JSON (par ex. un `dict`).
|
||||
Vous pouvez retourner des *membres d'énumération* dans vos *fonctions de chemin*, même imbriquée dans un JSON (e.g. un `dict`).
|
||||
|
||||
Ils seront convertis vers leurs valeurs correspondantes (des chaînes de caractères ici) avant d'être renvoyés au client :
|
||||
Ils seront convertis vers leurs valeurs correspondantes (chaînes de caractères ici) avant d'être transmis au client :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005_py39.py hl[18,21,23] *}
|
||||
{* ../../docs_src/path_params/tutorial005.py hl[18,21,23] *}
|
||||
|
||||
Dans votre client, vous recevrez une réponse JSON comme :
|
||||
Le client recevra une réponse JSON comme celle-ci :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -199,53 +208,53 @@ Dans votre client, vous recevrez une réponse JSON comme :
|
||||
}
|
||||
```
|
||||
|
||||
## Paramètres de chemin contenant des chemins { #path-parameters-containing-paths }
|
||||
## Paramètres de chemin contenant des chemins
|
||||
|
||||
Disons que vous avez un *chemin d'accès* avec un chemin `/files/{file_path}`.
|
||||
Disons que vous avez une *fonction de chemin* liée au chemin `/files/{file_path}`.
|
||||
|
||||
Mais vous avez besoin que `file_path` lui-même contienne un *chemin*, comme `home/johndoe/myfile.txt`.
|
||||
Mais que `file_path` lui-même doit contenir un *chemin*, comme `home/johndoe/myfile.txt` par exemple.
|
||||
|
||||
Ainsi, l'URL pour ce fichier serait : `/files/home/johndoe/myfile.txt`.
|
||||
Donc, l'URL pour ce fichier pourrait être : `/files/home/johndoe/myfile.txt`.
|
||||
|
||||
### Support d'OpenAPI { #openapi-support }
|
||||
### Support d'OpenAPI
|
||||
|
||||
OpenAPI ne prend pas en charge une manière de déclarer un *paramètre de chemin* contenant un *chemin* à l'intérieur, car cela peut conduire à des scénarios difficiles à tester et à définir.
|
||||
OpenAPI ne supporte pas de manière de déclarer un paramètre de chemin contenant un *chemin*, cela pouvant causer des scénarios difficiles à tester et définir.
|
||||
|
||||
Néanmoins, vous pouvez toujours le faire dans **FastAPI**, en utilisant l'un des outils internes de Starlette.
|
||||
Néanmoins, cela reste faisable dans **FastAPI**, via les outils internes de Starlette.
|
||||
|
||||
Et la documentation fonctionnera quand même, même si aucune indication supplémentaire ne sera ajoutée pour dire que le paramètre doit contenir un chemin.
|
||||
Et la documentation fonctionne quand même, bien qu'aucune section ne soit ajoutée pour dire que la paramètre devrait contenir un *chemin*.
|
||||
|
||||
### Convertisseur de chemin { #path-convertor }
|
||||
### Convertisseur de *chemin*
|
||||
|
||||
En utilisant une option directement depuis Starlette, vous pouvez déclarer un *paramètre de chemin* contenant un *chemin* avec une URL comme :
|
||||
En utilisant une option de Starlette directement, vous pouvez déclarer un *paramètre de chemin* contenant un *chemin* avec une URL comme :
|
||||
|
||||
```
|
||||
/files/{file_path:path}
|
||||
```
|
||||
|
||||
Dans ce cas, le nom du paramètre est `file_path`, et la dernière partie, `:path`, indique que le paramètre doit correspondre à n'importe quel *chemin*.
|
||||
Dans ce cas, le nom du paramètre est `file_path`, et la dernière partie, `:path`, indique à Starlette que le paramètre devrait correspondre à un *chemin*.
|
||||
|
||||
Vous pouvez donc l'utiliser ainsi :
|
||||
Vous pouvez donc l'utilisez comme tel :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial004_py39.py hl[6] *}
|
||||
{* ../../docs_src/path_params/tutorial004.py hl[6] *}
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Vous pourriez avoir besoin que le paramètre contienne `/home/johndoe/myfile.txt`, avec un slash initial (`/`).
|
||||
Vous pourriez avoir besoin que le paramètre contienne `/home/johndoe/myfile.txt`, avec un slash au début (`/`).
|
||||
|
||||
Dans ce cas, l'URL serait : `/files//home/johndoe/myfile.txt`, avec un double slash (`//`) entre `files` et `home`.
|
||||
|
||||
///
|
||||
|
||||
## Récapitulatif { #recap }
|
||||
## Récapitulatif
|
||||
|
||||
Avec **FastAPI**, en utilisant des déclarations de type Python courtes, intuitives et standard, vous obtenez :
|
||||
Avec **FastAPI**, en utilisant les déclarations de type rapides, intuitives et standards de Python, vous bénéficiez de :
|
||||
|
||||
* Support de l'éditeur : vérifications d'erreurs, autocomplétion, etc.
|
||||
* Données « <abbr title="conversion de la chaîne de caractères provenant d'une requête HTTP en données Python">parsing</abbr> »
|
||||
* Validation de données
|
||||
* Annotations d'API et documentation automatique
|
||||
* Support de l'éditeur : vérification d'erreurs, auto-complétion, etc.
|
||||
* <abbr title="conversion de la chaîne de caractères venant de la requête HTTP en données Python">"Parsing"</abbr> de données.
|
||||
* Validation de données.
|
||||
* Annotations d'API et documentation automatique.
|
||||
|
||||
Et vous n'avez besoin de les déclarer qu'une seule fois.
|
||||
Et vous n'avez besoin de le déclarer qu'une fois.
|
||||
|
||||
C'est probablement l'avantage visible principal de **FastAPI** comparé aux autres frameworks (outre les performances pures).
|
||||
C'est probablement l'avantage visible principal de **FastAPI** comparé aux autres *frameworks* (outre les performances pures).
|
||||
|
||||
@@ -1,273 +1,166 @@
|
||||
# Paramètres de requête et validations de chaînes de caractères { #query-parameters-and-string-validations }
|
||||
# Paramètres de requête et validations de chaînes de caractères
|
||||
|
||||
**FastAPI** vous permet de déclarer des informations et des validations supplémentaires pour vos paramètres.
|
||||
**FastAPI** vous permet de déclarer des informations et des validateurs additionnels pour vos paramètres de requêtes.
|
||||
|
||||
Prenons cette application comme exemple :
|
||||
Commençons avec cette application pour exemple :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial001.py hl[9] *}
|
||||
|
||||
Le paramètre de requête `q` est de type `str | None`, cela signifie qu’il est de type `str` mais peut aussi être `None`, et en effet, la valeur par défaut est `None`, donc FastAPI saura qu’il n’est pas requis.
|
||||
Le paramètre de requête `q` a pour type `Union[str, None]` (ou `str | None` en Python 3.10), signifiant qu'il est de type `str` mais pourrait aussi être égal à `None`, et bien sûr, la valeur par défaut est `None`, donc **FastAPI** saura qu'il n'est pas requis.
|
||||
|
||||
/// note | Remarque
|
||||
/// note
|
||||
|
||||
FastAPI saura que la valeur de `q` n’est pas requise grâce à la valeur par défaut `= None`.
|
||||
**FastAPI** saura que la valeur de `q` n'est pas requise grâce à la valeur par défaut `= None`.
|
||||
|
||||
Avoir `str | None` permettra à votre éditeur de vous offrir un meilleur support et de détecter les erreurs.
|
||||
Le `Union` dans `Union[str, None]` permettra à votre éditeur de vous offrir un meilleur support et de détecter les erreurs.
|
||||
|
||||
///
|
||||
|
||||
## Validation additionnelle { #additional-validation }
|
||||
## Validation additionnelle
|
||||
|
||||
Nous allons imposer que, même si `q` est optionnel, dès qu’il est fourni, **sa longueur n’excède pas 50 caractères**.
|
||||
Nous allons imposer que bien que `q` soit un paramètre optionnel, dès qu'il est fourni, **sa longueur n'excède pas 50 caractères**.
|
||||
|
||||
### Importer `Query` et `Annotated` { #import-query-and-annotated }
|
||||
## Importer `Query`
|
||||
|
||||
Pour ce faire, importez d’abord :
|
||||
Pour cela, importez d'abord `Query` depuis `fastapi` :
|
||||
|
||||
- `Query` depuis `fastapi`
|
||||
- `Annotated` depuis `typing`
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002.py hl[3] *}
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}
|
||||
## Utiliser `Query` comme valeur par défaut
|
||||
|
||||
/// info
|
||||
Construisez ensuite la valeur par défaut de votre paramètre avec `Query`, en choisissant 50 comme `max_length` :
|
||||
|
||||
FastAPI a ajouté la prise en charge de `Annotated` (et a commencé à le recommander) dans la version 0.95.0.
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002.py hl[9] *}
|
||||
|
||||
Si vous avez une version plus ancienne, vous obtiendrez des erreurs en essayant d’utiliser `Annotated`.
|
||||
Comme nous devons remplacer la valeur par défaut `None` dans la fonction par `Query()`, nous pouvons maintenant définir la valeur par défaut avec le paramètre `Query(default=None)`, il sert le même objectif qui est de définir cette valeur par défaut.
|
||||
|
||||
Assurez-vous de [mettre à niveau la version de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} vers au moins 0.95.1 avant d’utiliser `Annotated`.
|
||||
|
||||
///
|
||||
|
||||
## Utiliser `Annotated` dans le type pour le paramètre `q` { #use-annotated-in-the-type-for-the-q-parameter }
|
||||
|
||||
Vous vous souvenez que je vous ai dit plus tôt que `Annotated` peut être utilisé pour ajouter des métadonnées à vos paramètres dans l’[Introduction aux types Python](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank} ?
|
||||
|
||||
C’est le moment de l’utiliser avec FastAPI. 🚀
|
||||
|
||||
Nous avions cette annotation de type :
|
||||
|
||||
//// tab | Python 3.10+
|
||||
Donc :
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
q: Union[str, None] = Query(default=None)
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+
|
||||
... rend le paramètre optionnel, et est donc équivalent à :
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
////
|
||||
Mais déclare explicitement `q` comme étant un paramètre de requête.
|
||||
|
||||
Ce que nous allons faire, c’est l’englober avec `Annotated`, de sorte que cela devienne :
|
||||
/// info
|
||||
|
||||
//// tab | Python 3.10+
|
||||
Gardez à l'esprit que la partie la plus importante pour rendre un paramètre optionnel est :
|
||||
|
||||
```Python
|
||||
q: Annotated[str | None] = None
|
||||
= None
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+
|
||||
ou :
|
||||
|
||||
```Python
|
||||
q: Annotated[Union[str, None]] = None
|
||||
= Query(None)
|
||||
```
|
||||
|
||||
////
|
||||
et utilisera ce `None` pour détecter que ce paramètre de requête **n'est pas requis**.
|
||||
|
||||
Les deux versions signifient la même chose, `q` est un paramètre qui peut être une `str` ou `None`, et par défaut, c’est `None`.
|
||||
|
||||
Passons maintenant aux choses amusantes. 🎉
|
||||
|
||||
## Ajouter `Query` à `Annotated` dans le paramètre `q` { #add-query-to-annotated-in-the-q-parameter }
|
||||
|
||||
Maintenant que nous avons cet `Annotated` dans lequel nous pouvons mettre plus d’informations (dans ce cas une validation supplémentaire), ajoutez `Query` à l’intérieur de `Annotated`, et définissez le paramètre `max_length` à `50` :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}
|
||||
|
||||
Remarquez que la valeur par défaut est toujours `None`, donc le paramètre est toujours optionnel.
|
||||
|
||||
Mais maintenant, avec `Query(max_length=50)` à l’intérieur de `Annotated`, nous indiquons à FastAPI que nous voulons **une validation supplémentaire** pour cette valeur, nous voulons qu’elle ait au maximum 50 caractères. 😎
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Ici nous utilisons `Query()` parce qu’il s’agit d’un **paramètre de requête**. Plus tard nous verrons d’autres comme `Path()`, `Body()`, `Header()` et `Cookie()`, qui acceptent également les mêmes arguments que `Query()`.
|
||||
Le `Union[str, None]` est uniquement là pour permettre à votre éditeur un meilleur support.
|
||||
|
||||
///
|
||||
|
||||
FastAPI va maintenant :
|
||||
Ensuite, nous pouvons passer d'autres paramètres à `Query`. Dans cet exemple, le paramètre `max_length` qui s'applique aux chaînes de caractères :
|
||||
|
||||
- **Valider** les données en s’assurant que la longueur maximale est de 50 caractères
|
||||
- Afficher une **erreur claire** au client quand les données ne sont pas valides
|
||||
- **Documenter** le paramètre dans la *chemin d'accès* du schéma OpenAPI (il apparaîtra donc dans l’**interface de documentation automatique**)
|
||||
```Python
|
||||
q: Union[str, None] = Query(default=None, max_length=50)
|
||||
```
|
||||
|
||||
## Alternative (ancienne) : `Query` comme valeur par défaut { #alternative-old-query-as-the-default-value }
|
||||
Cela va valider les données, montrer une erreur claire si ces dernières ne sont pas valides, et documenter le paramètre dans le schéma `OpenAPI` de cette *path operation*.
|
||||
|
||||
Les versions précédentes de FastAPI (avant <abbr title="avant 2023-03">0.95.0</abbr>) exigeaient d’utiliser `Query` comme valeur par défaut de votre paramètre, au lieu de le mettre dans `Annotated`. Il y a de fortes chances que vous voyiez du code qui l’utilise encore, je vais donc vous l’expliquer.
|
||||
## Rajouter plus de validation
|
||||
|
||||
/// tip | Astuce
|
||||
Vous pouvez aussi rajouter un second paramètre `min_length` :
|
||||
|
||||
Pour du nouveau code et dès que possible, utilisez `Annotated` comme expliqué ci-dessus. Il y a de multiples avantages (expliqués ci-dessous) et aucun inconvénient. 🍰
|
||||
{* ../../docs_src/query_params_str_validations/tutorial003.py hl[9] *}
|
||||
|
||||
## Ajouter des validations par expressions régulières
|
||||
|
||||
On peut définir une <abbr title="Une expression régulière, regex ou regexp est une suite de caractères qui définit un pattern de correspondance pour les chaînes de caractères.">expression régulière</abbr> à laquelle le paramètre doit correspondre :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial004.py hl[10] *}
|
||||
|
||||
Cette expression régulière vérifie que la valeur passée comme paramètre :
|
||||
|
||||
* `^` : commence avec les caractères qui suivent, avec aucun caractère avant ceux-là.
|
||||
* `fixedquery` : a pour valeur exacte `fixedquery`.
|
||||
* `$` : se termine directement ensuite, n'a pas d'autres caractères après `fixedquery`.
|
||||
|
||||
Si vous vous sentez perdu avec le concept d'**expression régulière**, pas d'inquiétudes. Il s'agit d'une notion difficile pour beaucoup, et l'on peut déjà réussir à faire beaucoup sans jamais avoir à les manipuler.
|
||||
|
||||
Mais si vous décidez d'apprendre à les utiliser, sachez qu'ensuite vous pouvez les utiliser directement dans **FastAPI**.
|
||||
|
||||
## Valeurs par défaut
|
||||
|
||||
De la même façon que vous pouvez passer `None` comme premier argument pour l'utiliser comme valeur par défaut, vous pouvez passer d'autres valeurs.
|
||||
|
||||
Disons que vous déclarez le paramètre `q` comme ayant une longueur minimale de `3`, et une valeur par défaut étant `"fixedquery"` :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial005.py hl[7] *}
|
||||
|
||||
/// note | Rappel
|
||||
|
||||
Avoir une valeur par défaut rend le paramètre optionnel.
|
||||
|
||||
///
|
||||
|
||||
Voici comment vous utiliseriez `Query()` comme valeur par défaut du paramètre de votre fonction, en définissant le paramètre `max_length` à 50 :
|
||||
## Rendre ce paramètre requis
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}
|
||||
|
||||
Comme, dans ce cas (sans utiliser `Annotated`), nous devons remplacer la valeur par défaut `None` dans la fonction par `Query()`, nous devons maintenant définir la valeur par défaut avec le paramètre `Query(default=None)`, cela sert le même objectif de définir cette valeur par défaut (au moins pour FastAPI).
|
||||
|
||||
Donc :
|
||||
|
||||
```Python
|
||||
q: str | None = Query(default=None)
|
||||
```
|
||||
|
||||
... rend le paramètre optionnel, avec une valeur par défaut de `None`, comme :
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
Mais la version avec `Query` le déclare explicitement comme étant un paramètre de requête.
|
||||
|
||||
Ensuite, nous pouvons passer plus de paramètres à `Query`. Dans ce cas, le paramètre `max_length` qui s’applique aux chaînes de caractères :
|
||||
|
||||
```Python
|
||||
q: str | None = Query(default=None, max_length=50)
|
||||
```
|
||||
|
||||
Cela validera les données, affichera une erreur claire lorsque les données ne sont pas valides et documentera le paramètre dans la *chemin d'accès* du schéma OpenAPI.
|
||||
|
||||
### `Query` comme valeur par défaut ou dans `Annotated` { #query-as-the-default-value-or-in-annotated }
|
||||
|
||||
Gardez à l’esprit qu’en utilisant `Query` à l’intérieur de `Annotated`, vous ne pouvez pas utiliser le paramètre `default` de `Query`.
|
||||
|
||||
Utilisez à la place la valeur par défaut réelle du paramètre de fonction. Sinon, ce serait incohérent.
|
||||
|
||||
Par exemple, ceci n’est pas autorisé :
|
||||
|
||||
```Python
|
||||
q: Annotated[str, Query(default="rick")] = "morty"
|
||||
```
|
||||
|
||||
... parce qu’il n’est pas clair si la valeur par défaut doit être « rick » ou « morty ».
|
||||
|
||||
Donc, vous utiliseriez (de préférence) :
|
||||
|
||||
```Python
|
||||
q: Annotated[str, Query()] = "rick"
|
||||
```
|
||||
|
||||
... ou dans des bases de code plus anciennes, vous trouverez :
|
||||
|
||||
```Python
|
||||
q: str = Query(default="rick")
|
||||
```
|
||||
|
||||
### Avantages de `Annotated` { #advantages-of-annotated }
|
||||
|
||||
**L’utilisation de `Annotated` est recommandée** plutôt que la valeur par défaut dans les paramètres de fonction, c’est **mieux** pour plusieurs raisons. 🤓
|
||||
|
||||
La valeur **par défaut** du **paramètre de fonction** est la **vraie valeur par défaut**, c’est plus intuitif en Python en général. 😌
|
||||
|
||||
Vous pouvez **appeler** cette même fonction dans **d’autres endroits** sans FastAPI, et elle **fonctionnera comme prévu**. S’il y a un paramètre **requis** (sans valeur par défaut), votre **éditeur** vous le signalera avec une erreur, **Python** se plaindra aussi si vous l’exécutez sans passer le paramètre requis.
|
||||
|
||||
Quand vous n’utilisez pas `Annotated` et utilisez à la place l’**ancienne** méthode avec la **valeur par défaut**, si vous appelez cette fonction sans FastAPI dans **d’autres endroits**, vous devez **penser** à passer les arguments à la fonction pour qu’elle fonctionne correctement, sinon les valeurs seront différentes de ce que vous attendez (par ex. `QueryInfo` ou quelque chose de similaire au lieu d’une `str`). Et votre éditeur ne se plaindra pas, et Python ne se plaindra pas en exécutant cette fonction, seulement quand les opérations internes échoueront.
|
||||
|
||||
Comme `Annotated` peut avoir plus d’une annotation de métadonnées, vous pouvez maintenant même utiliser la même fonction avec d’autres outils, comme <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">Typer</a>. 🚀
|
||||
|
||||
## Ajouter plus de validations { #add-more-validations }
|
||||
|
||||
Vous pouvez également ajouter un paramètre `min_length` :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}
|
||||
|
||||
## Ajouter des expressions régulières { #add-regular-expressions }
|
||||
|
||||
Vous pouvez définir un `pattern` d’<abbr title="Une expression régulière, regex ou regexp, est une suite de caractères qui définit un motif de recherche pour les chaînes de caractères.">expression régulière</abbr> auquel le paramètre doit correspondre :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
|
||||
|
||||
Ce pattern d’expression régulière spécifique vérifie que la valeur reçue pour le paramètre :
|
||||
|
||||
- `^` : commence avec les caractères qui suivent, n’a pas de caractères avant.
|
||||
- `fixedquery` : a exactement la valeur `fixedquery`.
|
||||
- `$` : se termine là, n’a pas d’autres caractères après `fixedquery`.
|
||||
|
||||
Si vous vous sentez perdu avec toutes ces idées d’**« expression régulière »**, pas d’inquiétude. C’est un sujet difficile pour beaucoup. Vous pouvez déjà faire beaucoup de choses sans avoir besoin d’expressions régulières.
|
||||
|
||||
Désormais, vous savez que, lorsque vous en aurez besoin, vous pourrez les utiliser dans **FastAPI**.
|
||||
|
||||
## Valeurs par défaut { #default-values }
|
||||
|
||||
Vous pouvez, bien sûr, utiliser des valeurs par défaut autres que `None`.
|
||||
|
||||
Disons que vous voulez déclarer le paramètre de requête `q` avec un `min_length` de `3`, et avec une valeur par défaut de « fixedquery » :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Avoir une valeur par défaut de n’importe quel type, y compris `None`, rend le paramètre optionnel (non requis).
|
||||
|
||||
///
|
||||
|
||||
## Paramètres requis { #required-parameters }
|
||||
|
||||
Quand nous n’avons pas besoin de déclarer plus de validations ou de métadonnées, nous pouvons rendre le paramètre de requête `q` requis en n’indiquant simplement pas de valeur par défaut, comme :
|
||||
Quand on ne déclare ni validation, ni métadonnée, on peut rendre le paramètre `q` requis en ne lui déclarant juste aucune valeur par défaut :
|
||||
|
||||
```Python
|
||||
q: str
|
||||
```
|
||||
|
||||
au lieu de :
|
||||
à la place de :
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
Mais maintenant nous le déclarons avec `Query`, par exemple ainsi :
|
||||
Mais maintenant, on déclare `q` avec `Query`, comme ceci :
|
||||
|
||||
```Python
|
||||
q: Annotated[str | None, Query(min_length=3)] = None
|
||||
q: Union[str, None] = Query(default=None, min_length=3)
|
||||
```
|
||||
|
||||
Donc, lorsque vous avez besoin de déclarer une valeur comme requise tout en utilisant `Query`, vous pouvez simplement ne pas déclarer de valeur par défaut :
|
||||
Donc pour déclarer une valeur comme requise tout en utilisant `Query`, il faut utiliser `...` comme premier argument :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial006.py hl[7] *}
|
||||
|
||||
### Requis, peut valoir `None` { #required-can-be-none }
|
||||
/// info
|
||||
|
||||
Vous pouvez déclarer qu’un paramètre accepte `None`, mais qu’il est tout de même requis. Cela obligerait les clients à envoyer une valeur, même si la valeur est `None`.
|
||||
Si vous n'avez jamais vu ce `...` auparavant : c'est une des constantes natives de Python <a href="https://docs.python.org/fr/3/library/constants.html#Ellipsis" class="external-link" target="_blank">appelée "Ellipsis"</a>.
|
||||
|
||||
Pour ce faire, vous pouvez déclarer que `None` est un type valide tout en ne déclarant pas de valeur par défaut :
|
||||
///
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}
|
||||
Cela indiquera à **FastAPI** que la présence de ce paramètre est obligatoire.
|
||||
|
||||
## Liste de paramètres de requête / valeurs multiples { #query-parameter-list-multiple-values }
|
||||
## Liste de paramètres / valeurs multiples via Query
|
||||
|
||||
Quand vous définissez un paramètre de requête explicitement avec `Query`, vous pouvez aussi déclarer qu’il reçoit une liste de valeurs, autrement dit, qu’il reçoit des valeurs multiples.
|
||||
Quand on définit un paramètre de requête explicitement avec `Query` on peut aussi déclarer qu'il reçoit une liste de valeur, ou des "valeurs multiples".
|
||||
|
||||
Par exemple, pour déclarer un paramètre de requête `q` qui peut apparaître plusieurs fois dans l’URL, vous pouvez écrire :
|
||||
Par exemple, pour déclarer un paramètre de requête `q` qui peut apparaître plusieurs fois dans une URL, on écrit :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial011.py hl[9] *}
|
||||
|
||||
Ensuite, avec une URL comme :
|
||||
Ce qui fait qu'avec une URL comme :
|
||||
|
||||
```
|
||||
http://localhost:8000/items/?q=foo&q=bar
|
||||
```
|
||||
|
||||
vous recevriez les valeurs des multiples paramètres de requête `q` (`foo` et `bar`) dans une `list` Python à l’intérieur de votre fonction de *chemin d'accès*, dans le *paramètre de fonction* `q`.
|
||||
vous recevriez les valeurs des multiples paramètres de requête `q` (`foo` et `bar`) dans une `list` Python au sein de votre fonction de **path operation**, dans le paramètre de fonction `q`.
|
||||
|
||||
Donc, la réponse pour cette URL serait :
|
||||
Donc la réponse de cette URL serait :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -280,19 +173,19 @@ Donc, la réponse pour cette URL serait :
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Pour déclarer un paramètre de requête avec un type `list`, comme dans l’exemple ci-dessus, vous devez explicitement utiliser `Query`, sinon il serait interprété comme faisant partie du corps de la requête.
|
||||
Pour déclarer un paramètre de requête de type `list`, comme dans l'exemple ci-dessus, il faut explicitement utiliser `Query`, sinon cela sera interprété comme faisant partie du corps de la requête.
|
||||
|
||||
///
|
||||
|
||||
L’interface de documentation interactive de l’API sera mise à jour en conséquence, pour autoriser plusieurs valeurs :
|
||||
La documentation sera donc mise à jour automatiquement pour autoriser plusieurs valeurs :
|
||||
|
||||
<img src="/img/tutorial/query-params-str-validations/image02.png">
|
||||
|
||||
### Liste de paramètres de requête / valeurs multiples avec valeurs par défaut { #query-parameter-list-multiple-values-with-defaults }
|
||||
### Combiner liste de paramètres et valeurs par défaut
|
||||
|
||||
Vous pouvez également définir une `list` de valeurs par défaut si aucune n’est fournie :
|
||||
Et l'on peut aussi définir une liste de valeurs par défaut si aucune n'est fournie :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial012.py hl[9] *}
|
||||
|
||||
Si vous allez à :
|
||||
|
||||
@@ -300,7 +193,9 @@ Si vous allez à :
|
||||
http://localhost:8000/items/
|
||||
```
|
||||
|
||||
la valeur par défaut de `q` sera : `["foo", "bar"]` et votre réponse sera :
|
||||
la valeur par défaut de `q` sera : `["foo", "bar"]`
|
||||
|
||||
et la réponse sera :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -311,163 +206,93 @@ la valeur par défaut de `q` sera : `["foo", "bar"]` et votre réponse sera :
|
||||
}
|
||||
```
|
||||
|
||||
#### Utiliser simplement `list` { #using-just-list }
|
||||
#### Utiliser `list`
|
||||
|
||||
Vous pouvez aussi utiliser `list` directement au lieu de `list[str]` :
|
||||
Il est aussi possible d'utiliser directement `list` plutôt que `List[str]` :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial013.py hl[7] *}
|
||||
|
||||
/// note | Remarque
|
||||
/// note
|
||||
|
||||
Gardez à l’esprit que dans ce cas, FastAPI ne vérifiera pas le contenu de la liste.
|
||||
Dans ce cas-là, **FastAPI** ne vérifiera pas le contenu de la liste.
|
||||
|
||||
Par exemple, `list[int]` vérifierait (et documenterait) que le contenu de la liste est composé d’entiers. Mais un simple `list` ne le ferait pas.
|
||||
Par exemple, `List[int]` vérifiera (et documentera) que la liste est bien entièrement composée d'entiers. Alors qu'un simple `list` ne ferait pas cette vérification.
|
||||
|
||||
///
|
||||
|
||||
## Déclarer plus de métadonnées { #declare-more-metadata }
|
||||
## Déclarer des métadonnées supplémentaires
|
||||
|
||||
Vous pouvez ajouter plus d’informations à propos du paramètre.
|
||||
On peut aussi ajouter plus d'informations sur le paramètre.
|
||||
|
||||
Ces informations seront incluses dans l’OpenAPI généré et utilisées par les interfaces de documentation et les outils externes.
|
||||
Ces informations seront incluses dans le schéma `OpenAPI` généré et utilisées par la documentation interactive ou les outils externes utilisés.
|
||||
|
||||
/// note | Remarque
|
||||
/// note
|
||||
|
||||
Gardez à l’esprit que différents outils peuvent avoir des niveaux de prise en charge d’OpenAPI différents.
|
||||
Gardez en tête que les outils externes utilisés ne supportent pas forcément tous parfaitement OpenAPI.
|
||||
|
||||
Certains d’entre eux pourraient ne pas encore afficher toutes les informations supplémentaires déclarées, bien que, dans la plupart des cas, la fonctionnalité manquante soit déjà prévue au développement.
|
||||
Il se peut donc que certains d'entre eux n'utilisent pas toutes les métadonnées que vous avez déclarées pour le moment, bien que dans la plupart des cas, les fonctionnalités manquantes ont prévu d'être implémentées.
|
||||
|
||||
///
|
||||
|
||||
Vous pouvez ajouter un `title` :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial007.py hl[10] *}
|
||||
|
||||
Et une `description` :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial008.py hl[13] *}
|
||||
|
||||
## Paramètres avec alias { #alias-parameters }
|
||||
## Alias de paramètres
|
||||
|
||||
Imaginez que vous vouliez que le paramètre soit `item-query`.
|
||||
Imaginez que vous vouliez que votre paramètre se nomme `item-query`.
|
||||
|
||||
Comme dans :
|
||||
Comme dans la requête :
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?item-query=foobaritems
|
||||
```
|
||||
|
||||
Mais `item-query` n’est pas un nom de variable Python valide.
|
||||
Mais `item-query` n'est pas un nom de variable valide en Python.
|
||||
|
||||
Le plus proche serait `item_query`.
|
||||
Le nom le plus proche serait `item_query`.
|
||||
|
||||
Mais vous avez quand même besoin que ce soit exactement `item-query` ...
|
||||
Mais vous avez vraiment envie que ce soit exactement `item-query`...
|
||||
|
||||
Vous pouvez alors déclarer un `alias`, et cet alias sera utilisé pour trouver la valeur du paramètre :
|
||||
Pour cela vous pouvez déclarer un `alias`, et cet alias est ce qui sera utilisé pour trouver la valeur du paramètre :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial009.py hl[9] *}
|
||||
|
||||
## Déprécier des paramètres { #deprecating-parameters }
|
||||
## Déprécier des paramètres
|
||||
|
||||
Disons que vous n’aimez plus ce paramètre.
|
||||
Disons que vous ne vouliez plus utiliser ce paramètre désormais.
|
||||
|
||||
Vous devez le laisser là quelque temps car des clients l’utilisent, mais vous voulez que les documents l’affichent clairement comme <abbr title="obsolète, recommandé de ne pas l’utiliser">déprécié</abbr>.
|
||||
Il faut qu'il continue à exister pendant un certain temps car vos clients l'utilisent, mais vous voulez que la documentation mentionne clairement que ce paramètre est <abbr title="obsolète, recommandé de ne pas l'utiliser">déprécié</abbr>.
|
||||
|
||||
Passez alors le paramètre `deprecated=True` à `Query` :
|
||||
On utilise alors l'argument `deprecated=True` de `Query` :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial010.py hl[18] *}
|
||||
|
||||
Les documents l’afficheront ainsi :
|
||||
La documentation le présentera comme il suit :
|
||||
|
||||
<img src="/img/tutorial/query-params-str-validations/image01.png">
|
||||
|
||||
## Exclure des paramètres d’OpenAPI { #exclude-parameters-from-openapi }
|
||||
## Pour résumer
|
||||
|
||||
Pour exclure un paramètre de requête du schéma OpenAPI généré (et donc, des systèmes de documentation automatiques), définissez le paramètre `include_in_schema` de `Query` à `False` :
|
||||
Il est possible d'ajouter des validateurs et métadonnées pour vos paramètres.
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}
|
||||
Validateurs et métadonnées génériques:
|
||||
|
||||
## Validation personnalisée { #custom-validation }
|
||||
* `alias`
|
||||
* `title`
|
||||
* `description`
|
||||
* `deprecated`
|
||||
|
||||
Il peut y avoir des cas où vous devez faire une **validation personnalisée** qui ne peut pas être réalisée avec les paramètres montrés ci-dessus.
|
||||
Validateurs spécifiques aux chaînes de caractères :
|
||||
|
||||
Dans ces cas, vous pouvez utiliser une **fonction de validation personnalisée** qui est appliquée après la validation normale (par ex. après avoir validé que la valeur est une `str`).
|
||||
* `min_length`
|
||||
* `max_length`
|
||||
* `regex`
|
||||
|
||||
Vous pouvez y parvenir en utilisant <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator" class="external-link" target="_blank">`AfterValidator` de Pydantic</a> à l’intérieur de `Annotated`.
|
||||
Parmi ces exemples, vous avez pu voir comment déclarer des validateurs pour les chaînes de caractères.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Pydantic a aussi <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator" class="external-link" target="_blank">`BeforeValidator`</a> et d’autres. 🤓
|
||||
|
||||
///
|
||||
|
||||
Par exemple, ce validateur personnalisé vérifie que l’ID d’item commence par `isbn-` pour un numéro de livre <abbr title="International Standard Book Number - Numéro international normalisé du livre">ISBN</abbr> ou par `imdb-` pour un ID d’URL de film <abbr title="IMDB (Internet Movie Database) est un site web contenant des informations sur les films">IMDB</abbr> :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
|
||||
|
||||
/// info
|
||||
|
||||
C’est disponible avec Pydantic version 2 ou supérieure. 😎
|
||||
|
||||
///
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Si vous devez faire un type de validation qui nécessite de communiquer avec un **composant externe**, comme une base de données ou une autre API, vous devez plutôt utiliser les **Dépendances de FastAPI**, vous en apprendrez davantage plus tard.
|
||||
|
||||
Ces validateurs personnalisés sont destinés aux éléments qui peuvent être vérifiés **uniquement** avec les **mêmes données** fournies dans la requête.
|
||||
|
||||
///
|
||||
|
||||
### Comprendre ce code { #understand-that-code }
|
||||
|
||||
Le point important est simplement d’utiliser **`AfterValidator` avec une fonction à l’intérieur de `Annotated`**. N’hésitez pas à passer cette partie. 🤸
|
||||
|
||||
---
|
||||
|
||||
Mais si vous êtes curieux de cet exemple de code spécifique et que vous êtes toujours partant, voici quelques détails supplémentaires.
|
||||
|
||||
#### Chaîne avec `value.startswith()` { #string-with-value-startswith }
|
||||
|
||||
Avez-vous remarqué ? Une chaîne utilisant `value.startswith()` peut prendre un tuple, et elle vérifiera chaque valeur du tuple :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}
|
||||
|
||||
#### Un élément aléatoire { #a-random-item }
|
||||
|
||||
Avec `data.items()` nous obtenons un <abbr title="Quelque chose que l’on peut itérer avec une boucle for, comme une liste, un set, etc.">objet itérable</abbr> avec des tuples contenant la clé et la valeur pour chaque élément du dictionnaire.
|
||||
|
||||
Nous convertissons cet objet itérable en une `list` propre avec `list(data.items())`.
|
||||
|
||||
Ensuite, avec `random.choice()` nous pouvons obtenir une **valeur aléatoire** depuis la liste, nous obtenons donc un tuple `(id, name)`. Ce sera quelque chose comme `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
|
||||
|
||||
Puis nous **affectons ces deux valeurs** du tuple aux variables `id` et `name`.
|
||||
|
||||
Ainsi, si l’utilisateur n’a pas fourni d’ID d’item, il recevra quand même une suggestion aléatoire.
|
||||
|
||||
... nous faisons tout cela en **une seule ligne simple**. 🤯 Vous n’adorez pas Python ? 🐍
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}
|
||||
|
||||
## Récapitulatif { #recap }
|
||||
|
||||
Vous pouvez déclarer des validations et des métadonnées supplémentaires pour vos paramètres.
|
||||
|
||||
Validations et métadonnées génériques :
|
||||
|
||||
- `alias`
|
||||
- `title`
|
||||
- `description`
|
||||
- `deprecated`
|
||||
|
||||
Validations spécifiques aux chaînes :
|
||||
|
||||
- `min_length`
|
||||
- `max_length`
|
||||
- `pattern`
|
||||
|
||||
Validations personnalisées avec `AfterValidator`.
|
||||
|
||||
Dans ces exemples, vous avez vu comment déclarer des validations pour des valeurs `str`.
|
||||
|
||||
Voyez les prochains chapitres pour apprendre à déclarer des validations pour d’autres types, comme les nombres.
|
||||
Dans les prochains chapitres, vous verrez comment déclarer des validateurs pour d'autres types, comme les nombres.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Paramètres de requête { #query-parameters }
|
||||
# Paramètres de requête
|
||||
|
||||
Quand vous déclarez d'autres paramètres de fonction qui ne font pas partie des paramètres de chemin, ils sont automatiquement interprétés comme des paramètres de « query ».
|
||||
Quand vous déclarez des paramètres dans votre fonction de chemin qui ne font pas partie des paramètres indiqués dans le chemin associé, ces paramètres sont automatiquement considérés comme des paramètres de "requête".
|
||||
|
||||
{* ../../docs_src/query_params/tutorial001_py39.py hl[9] *}
|
||||
{* ../../docs_src/query_params/tutorial001.py hl[9] *}
|
||||
|
||||
La query est l'ensemble des paires clé-valeur placées après le `?` dans une URL, séparées par des caractères `&`.
|
||||
La partie appelée requête (ou **query**) dans une URL est l'ensemble des paires clés-valeurs placées après le `?` , séparées par des `&`.
|
||||
|
||||
Par exemple, dans l'URL :
|
||||
|
||||
@@ -12,27 +12,27 @@ Par exemple, dans l'URL :
|
||||
http://127.0.0.1:8000/items/?skip=0&limit=10
|
||||
```
|
||||
|
||||
... les paramètres de requête sont :
|
||||
...les paramètres de requête sont :
|
||||
|
||||
* `skip` : avec une valeur de `0`
|
||||
* `skip` : avec une valeur de`0`
|
||||
* `limit` : avec une valeur de `10`
|
||||
|
||||
Comme ils font partie de l'URL, ce sont « naturellement » des chaînes de caractères.
|
||||
Faisant partie de l'URL, ces valeurs sont des chaînes de caractères (`str`).
|
||||
|
||||
Mais lorsque vous les déclarez avec des types Python (dans l'exemple ci-dessus, en tant que `int`), ils sont convertis vers ce type et validés par rapport à celui-ci.
|
||||
Mais quand on les déclare avec des types Python (dans l'exemple précédent, en tant qu'`int`), elles sont converties dans les types renseignés.
|
||||
|
||||
Tous les mêmes processus qui s'appliquaient aux paramètres de chemin s'appliquent aussi aux paramètres de requête :
|
||||
Toutes les fonctionnalités qui s'appliquent aux paramètres de chemin s'appliquent aussi aux paramètres de requête :
|
||||
|
||||
* Prise en charge de l'éditeur (évidemment)
|
||||
* <abbr title="conversion de la chaîne provenant d'une requête HTTP en données Python">« parsing »</abbr> des données
|
||||
* Validation des données
|
||||
* Documentation automatique
|
||||
* Support de l'éditeur : vérification d'erreurs, auto-complétion, etc.
|
||||
* <abbr title="conversion de la chaîne de caractères venant de la requête HTTP en données Python">"Parsing"</abbr> de données.
|
||||
* Validation de données.
|
||||
* Annotations d'API et documentation automatique.
|
||||
|
||||
## Valeurs par défaut { #defaults }
|
||||
## Valeurs par défaut
|
||||
|
||||
Comme les paramètres de requête ne sont pas une partie fixe d'un chemin, ils peuvent être optionnels et avoir des valeurs par défaut.
|
||||
Les paramètres de requête ne sont pas une partie fixe d'un chemin, ils peuvent être optionnels et avoir des valeurs par défaut.
|
||||
|
||||
Dans l'exemple ci-dessus, ils ont des valeurs par défaut `skip=0` et `limit=10`.
|
||||
Dans l'exemple ci-dessus, ils ont des valeurs par défaut qui sont `skip=0` et `limit=10`.
|
||||
|
||||
Donc, accéder à l'URL :
|
||||
|
||||
@@ -40,44 +40,52 @@ Donc, accéder à l'URL :
|
||||
http://127.0.0.1:8000/items/
|
||||
```
|
||||
|
||||
serait équivalent à accéder à :
|
||||
serait équivalent à accéder à l'URL :
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?skip=0&limit=10
|
||||
```
|
||||
|
||||
Mais si vous accédez, par exemple, à :
|
||||
Mais si vous accédez à, par exemple :
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?skip=20
|
||||
```
|
||||
|
||||
Les valeurs des paramètres dans votre fonction seront :
|
||||
Les valeurs des paramètres de votre fonction seront :
|
||||
|
||||
* `skip=20` : car vous l'avez défini dans l'URL
|
||||
* `limit=10` : car c'était la valeur par défaut
|
||||
* `skip=20` : car c'est la valeur déclarée dans l'URL.
|
||||
* `limit=10` : car `limit` n'a pas été déclaré dans l'URL, et que la valeur par défaut était `10`.
|
||||
|
||||
## Paramètres optionnels { #optional-parameters }
|
||||
## Paramètres optionnels
|
||||
|
||||
De la même façon, vous pouvez déclarer des paramètres de requête optionnels, en définissant leur valeur par défaut à `None` :
|
||||
De la même façon, vous pouvez définir des paramètres de requête comme optionnels, en leur donnant comme valeur par défaut `None` :
|
||||
|
||||
{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}
|
||||
{* ../../docs_src/query_params/tutorial002.py hl[9] *}
|
||||
|
||||
Dans ce cas, le paramètre de fonction `q` sera optionnel et vaudra `None` par défaut.
|
||||
Ici, le paramètre `q` sera optionnel, et aura `None` comme valeur par défaut.
|
||||
|
||||
/// check | Vérifications
|
||||
/// check | Remarque
|
||||
|
||||
Notez également que FastAPI est suffisamment intelligent pour remarquer que le paramètre de chemin `item_id` est un paramètre de chemin et que `q` ne l'est pas, c'est donc un paramètre de requête.
|
||||
On peut voir que **FastAPI** est capable de détecter que le paramètre de chemin `item_id` est un paramètre de chemin et que `q` n'en est pas un, c'est donc un paramètre de requête.
|
||||
|
||||
///
|
||||
|
||||
## Conversion des types des paramètres de requête { #query-parameter-type-conversion }
|
||||
/// note
|
||||
|
||||
Vous pouvez aussi déclarer des types `bool`, ils seront convertis :
|
||||
**FastAPI** saura que `q` est optionnel grâce au `=None`.
|
||||
|
||||
{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}
|
||||
Le `Optional` dans `Optional[str]` n'est pas utilisé par **FastAPI** (**FastAPI** n'en utilisera que la partie `str`), mais il servira tout de même à votre éditeur de texte pour détecter des erreurs dans votre code.
|
||||
|
||||
Dans ce cas, si vous allez sur :
|
||||
///
|
||||
|
||||
## Conversion des types des paramètres de requête
|
||||
|
||||
Vous pouvez aussi déclarer des paramètres de requête comme booléens (`bool`), **FastAPI** les convertira :
|
||||
|
||||
{* ../../docs_src/query_params/tutorial003.py hl[9] *}
|
||||
|
||||
Avec ce code, en allant sur :
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/foo?short=1
|
||||
@@ -107,61 +115,60 @@ ou
|
||||
http://127.0.0.1:8000/items/foo?short=yes
|
||||
```
|
||||
|
||||
ou n'importe quelle autre variation de casse (tout en majuscules, uniquement la première lettre en majuscule, etc.), votre fonction verra le paramètre `short` avec une valeur `bool` à `True`. Sinon la valeur sera à `False`.
|
||||
ou n'importe quelle autre variation de casse (tout en majuscules, uniquement la première lettre en majuscule, etc.), votre fonction considérera le paramètre `short` comme ayant une valeur booléenne à `True`. Sinon la valeur sera à `False`.
|
||||
|
||||
## Multiples paramètres de chemin et de requête { #multiple-path-and-query-parameters }
|
||||
## Multiples paramètres de chemin et de requête
|
||||
|
||||
Vous pouvez déclarer plusieurs paramètres de chemin et paramètres de requête en même temps, FastAPI sait lequel est lequel.
|
||||
Vous pouvez déclarer plusieurs paramètres de chemin et paramètres de requête dans la même fonction, **FastAPI** saura comment les gérer.
|
||||
|
||||
Et vous n'avez pas besoin de les déclarer dans un ordre spécifique.
|
||||
|
||||
Ils seront détectés par leur nom :
|
||||
Ils seront détectés par leurs noms :
|
||||
|
||||
{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}
|
||||
{* ../../docs_src/query_params/tutorial004.py hl[8,10] *}
|
||||
|
||||
## Paramètres de requête requis { #required-query-parameters }
|
||||
## Paramètres de requête requis
|
||||
|
||||
Quand vous déclarez une valeur par défaut pour des paramètres qui ne sont pas des paramètres de chemin (pour l'instant, nous n'avons vu que les paramètres de requête), alors ils ne sont pas requis.
|
||||
Quand vous déclarez une valeur par défaut pour un paramètre qui n'est pas un paramètre de chemin (actuellement, nous n'avons vu que les paramètres de requête), alors ce paramètre n'est pas requis.
|
||||
|
||||
Si vous ne voulez pas leur donner de valeur spécifique mais simplement les rendre optionnels, définissez la valeur par défaut à `None`.
|
||||
Si vous ne voulez pas leur donner de valeur par défaut mais juste les rendre optionnels, utilisez `None` comme valeur par défaut.
|
||||
|
||||
Mais si vous voulez rendre un paramètre de requête obligatoire, vous pouvez simplement ne déclarer aucune valeur par défaut :
|
||||
Mais si vous voulez rendre un paramètre de requête obligatoire, vous pouvez juste ne pas y affecter de valeur par défaut :
|
||||
|
||||
{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *}
|
||||
{* ../../docs_src/query_params/tutorial005.py hl[6:7] *}
|
||||
|
||||
Ici, le paramètre de requête `needy` est un paramètre de requête requis de type `str`.
|
||||
Ici le paramètre `needy` est un paramètre requis (ou obligatoire) de type `str`.
|
||||
|
||||
Si vous ouvrez dans votre navigateur une URL comme :
|
||||
Si vous ouvrez une URL comme :
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/foo-item
|
||||
```
|
||||
|
||||
... sans ajouter le paramètre requis `needy`, vous verrez une erreur comme :
|
||||
...sans ajouter le paramètre requis `needy`, vous aurez une erreur :
|
||||
|
||||
```JSON
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
"type": "missing",
|
||||
"loc": [
|
||||
"query",
|
||||
"needy"
|
||||
],
|
||||
"msg": "Field required",
|
||||
"input": null
|
||||
}
|
||||
]
|
||||
"detail": [
|
||||
{
|
||||
"loc": [
|
||||
"query",
|
||||
"needy"
|
||||
],
|
||||
"msg": "field required",
|
||||
"type": "value_error.missing"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Comme `needy` est un paramètre requis, vous devez le définir dans l'URL :
|
||||
La présence de `needy` étant nécessaire, vous auriez besoin de l'insérer dans l'URL :
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
|
||||
```
|
||||
|
||||
... cela fonctionnerait :
|
||||
...ce qui fonctionnerait :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -170,18 +177,18 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
|
||||
}
|
||||
```
|
||||
|
||||
Et bien sûr, vous pouvez définir certains paramètres comme requis, certains avec une valeur par défaut et certains entièrement optionnels :
|
||||
Et bien sur, vous pouvez définir certains paramètres comme requis, certains avec des valeurs par défaut et certains entièrement optionnels :
|
||||
|
||||
{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}
|
||||
{* ../../docs_src/query_params/tutorial006.py hl[10] *}
|
||||
|
||||
Dans ce cas, il y a 3 paramètres de requête :
|
||||
Ici, on a donc 3 paramètres de requête :
|
||||
|
||||
* `needy`, un `str` requis.
|
||||
* `skip`, un `int` avec une valeur par défaut de `0`.
|
||||
* `needy`, requis et de type `str`.
|
||||
* `skip`, un `int` avec comme valeur par défaut `0`.
|
||||
* `limit`, un `int` optionnel.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Vous pourriez aussi utiliser des `Enum`s de la même façon qu'avec les [Paramètres de chemin](path-params.md#predefined-values){.internal-link target=_blank}.
|
||||
Vous pouvez utiliser les `Enum`s de la même façon qu'avec les [Paramètres de chemin](path-params.md#valeurs-predefinies){.internal-link target=_blank}.
|
||||
|
||||
///
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
# 追加のステータスコード { #additional-status-codes }
|
||||
# 追加のステータスコード
|
||||
|
||||
デフォルトでは、 **FastAPI** は `JSONResponse` を使ってレスポンスを返し、*path operation* から返した内容をその `JSONResponse` の中に入れます。
|
||||
デフォルトでは、 **FastAPI** は `JSONResponse` を使ってレスポンスを返します。その `JSONResponse` の中には、 *path operation* が返した内容が入ります。
|
||||
|
||||
デフォルトのステータスコード、または *path operation* で設定したステータスコードが使用されます。
|
||||
それは、デフォルトのステータスコードか、 *path operation* でセットしたものを利用します。
|
||||
|
||||
## 追加のステータスコード { #additional-status-codes_1 }
|
||||
## 追加のステータスコード
|
||||
|
||||
メインのステータスコードとは別に追加のステータスコードを返したい場合は、`JSONResponse` のような `Response` を直接返し、追加のステータスコードを直接設定できます。
|
||||
メインのステータスコードとは別に、他のステータスコードを返したい場合は、`Response` (`JSONResponse` など) に追加のステータスコードを設定して直接返します。
|
||||
|
||||
たとえば、item を更新でき、成功時に HTTP ステータスコード 200 "OK" を返す *path operation* を作りたいとします。
|
||||
例えば、itemを更新し、成功した場合は200 "OK"のHTTPステータスコードを返す *path operation* を作りたいとします。
|
||||
|
||||
しかし、新しい item も受け付けたいとします。そして、item が以前存在しなかった場合には作成し、HTTP ステータスコード 201「Created」を返します。
|
||||
しかし、新しいitemも許可したいです。itemが存在しない場合は、それらを作成して201 "Created"を返します。
|
||||
|
||||
これを実現するには、`JSONResponse` をインポートし、望む `status_code` を設定して、そこで内容を直接返します。
|
||||
これを達成するには、 `JSONResponse` をインポートし、 `status_code` を設定して直接内容を返します。
|
||||
|
||||
{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}
|
||||
{* ../../docs_src/additional_status_codes/tutorial001.py hl[4,25] *}
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
上の例のように `Response` を直接返すと、それはそのまま返されます。
|
||||
上記の例のように `Response` を明示的に返す場合、それは直接返されます。
|
||||
|
||||
モデルなどによってシリアライズされません。
|
||||
モデルなどはシリアライズされません。
|
||||
|
||||
必要なデータが含まれていること、そして(`JSONResponse` を使用している場合)値が有効な JSON であることを確認してください。
|
||||
必要なデータが含まれていることや、値が有効なJSONであること (`JSONResponse` を使う場合) を確認してください。
|
||||
|
||||
///
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
`from starlette.responses import JSONResponse` を使うこともできます。
|
||||
`from starlette.responses import JSONResponse` を利用することもできます。
|
||||
|
||||
**FastAPI** は開発者の利便性のために、`fastapi.responses` と同じ `starlette.responses` を提供しています。しかし、利用可能なレスポンスのほとんどは Starlette から直接提供されています。`status` も同様です。
|
||||
**FastAPI** は `fastapi.responses` と同じ `starlette.responses` を、開発者の利便性のために提供しています。しかし有効なレスポンスはほとんどStarletteから来ています。 `status` についても同じです。
|
||||
|
||||
///
|
||||
|
||||
## OpenAPI と API ドキュメント { #openapi-and-api-docs }
|
||||
## OpenAPIとAPIドキュメント
|
||||
|
||||
追加のステータスコードとレスポンスを直接返す場合、それらは OpenAPI スキーマ(API ドキュメント)には含まれません。FastAPI には、事前に何が返されるかを知る方法がないからです。
|
||||
ステータスコードとレスポンスを直接返す場合、それらはOpenAPIスキーマ (APIドキュメント) には含まれません。なぜなら、FastAPIは何が返されるのか事前に知ることができないからです。
|
||||
|
||||
しかし、[Additional Responses](additional-responses.md){.internal-link target=_blank} を使ってコード内にドキュメント化できます。
|
||||
しかし、 [Additional Responses](additional-responses.md){.internal-link target=_blank} を使ってコードの中にドキュメントを書くことができます。
|
||||
|
||||
@@ -1,40 +1,34 @@
|
||||
# カスタムレスポンス - HTML、ストリーム、ファイル、その他のレスポンス { #custom-response-html-stream-file-others }
|
||||
# カスタムレスポンス - HTML、ストリーム、ファイル、その他のレスポンス
|
||||
|
||||
デフォルトでは、**FastAPI** は `JSONResponse` を使ってレスポンスを返します。
|
||||
|
||||
[レスポンスを直接返す](response-directly.md){.internal-link target=_blank}で見たように、 `Response` を直接返すことでこの挙動をオーバーライドできます。
|
||||
|
||||
しかし、`Response` を直接返すと(または `JSONResponse` のような任意のサブクラスを返すと)、データは自動的に変換されず(`response_model` を宣言していても)、ドキュメントも自動生成されません(例えば、生成されるOpenAPIの一部としてHTTPヘッダー `Content-Type` に特定の「メディアタイプ」を含めるなど)。
|
||||
しかし、`Response` を直接返すと、データは自動的に変換されず、ドキュメントも自動生成されません (例えば、生成されるOpenAPIの一部としてHTTPヘッダー `Content-Type` に特定の「メディアタイプ」を含めるなど) 。
|
||||
|
||||
`response_class` パラメータを使用して、*path operation デコレータ* で使用したい `Response`(任意の `Response` サブクラス)を宣言することもできます。
|
||||
しかし、*path operationデコレータ* に、使いたい `Response` を宣言することもできます。
|
||||
|
||||
*path operation 関数* から返されるコンテンツは、その `Response` に含まれます。
|
||||
*path operation関数* から返されるコンテンツは、その `Response` に含まれます。
|
||||
|
||||
そしてその `Response` が、`JSONResponse` や `UJSONResponse` の場合のようにJSONメディアタイプ(`application/json`)なら、関数の返り値は *path operationデコレータ* に宣言した任意のPydantic `response_model` により自動的に変換(およびフィルタ)されます。
|
||||
そしてもし、`Response` が、`JSONResponse` や `UJSONResponse` の場合のようにJSONメディアタイプ (`application/json`) ならば、データは *path operationデコレータ* に宣言したPydantic `response_model` により自動的に変換 (もしくはフィルタ) されます。
|
||||
|
||||
/// note | 備考
|
||||
|
||||
メディアタイプを指定せずにレスポンスクラスを利用すると、FastAPIはレスポンスにコンテンツがないことを期待します。そのため、生成されるOpenAPIドキュメントにレスポンスフォーマットが記載されません。
|
||||
メディアタイプを指定せずにレスポンスクラスを利用すると、FastAPIは何もコンテンツがないことを期待します。そのため、生成されるOpenAPIドキュメントにレスポンスフォーマットが記載されません。
|
||||
|
||||
///
|
||||
|
||||
## `ORJSONResponse` を使う { #use-orjsonresponse }
|
||||
## `ORJSONResponse` を使う
|
||||
|
||||
例えば、パフォーマンスを絞り出したい場合は、<a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>をインストールし、レスポンスとして `ORJSONResponse` をセットできます。
|
||||
例えば、パフォーマンスを出したい場合は、<a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>をインストールし、`ORJSONResponse`をレスポンスとしてセットすることができます。
|
||||
|
||||
使いたい `Response` クラス(サブクラス)をインポートし、*path operationデコレータ* に宣言します。
|
||||
使いたい `Response` クラス (サブクラス) をインポートし、 *path operationデコレータ* に宣言します。
|
||||
|
||||
大きなレスポンスの場合、`Response` を直接返すほうが、辞書を返すよりもはるかに高速です。
|
||||
|
||||
これは、デフォルトではFastAPIがチュートリアルで説明した同じ[JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank}を使って、内部の各アイテムを検査し、JSONとしてシリアライズ可能であることを確認するためです。これにより、例えばデータベースモデルのような**任意のオブジェクト**を返せます。
|
||||
|
||||
しかし、返そうとしているコンテンツが **JSONでシリアライズ可能**であることが確実なら、それを直接レスポンスクラスに渡して、FastAPIがレスポンスクラスへ渡す前に返却コンテンツを `jsonable_encoder` に通すことで発生する追加のオーバーヘッドを回避できます。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial001b_py39.py hl[2,7] *}
|
||||
{* ../../docs_src/custom_response/tutorial001b.py hl[2,7] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
パラメータ `response_class` は、レスポンスの「メディアタイプ」を定義するためにも利用されます。
|
||||
パラメータ `response_class` は、レスポンスの「メディアタイプ」を定義するために利用することもできます。
|
||||
|
||||
この場合、HTTPヘッダー `Content-Type` には `application/json` がセットされます。
|
||||
|
||||
@@ -44,70 +38,70 @@
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`ORJSONResponse` はFastAPIでのみ利用可能で、Starletteでは利用できません。
|
||||
`ORJSONResponse` は、現在はFastAPIのみで利用可能で、Starletteでは利用できません。
|
||||
|
||||
///
|
||||
|
||||
## HTMLレスポンス { #html-response }
|
||||
## HTMLレスポンス
|
||||
|
||||
**FastAPI** からHTMLを直接返す場合は、`HTMLResponse` を使います。
|
||||
|
||||
* `HTMLResponse` をインポートする。
|
||||
* *path operation デコレータ* のパラメータ `response_class` に `HTMLResponse` を渡す。
|
||||
* *path operation* のパラメータ `content_type` に `HTMLResponse` を渡す。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial002_py39.py hl[2,7] *}
|
||||
{* ../../docs_src/custom_response/tutorial002.py hl[2,7] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
パラメータ `response_class` は、レスポンスの「メディアタイプ」を定義するためにも利用されます。
|
||||
パラメータ `response_class` は、レスポンスの「メディアタイプ」を定義するために利用されます。
|
||||
|
||||
この場合、HTTPヘッダー `Content-Type` には `text/html` がセットされます。
|
||||
|
||||
そして、OpenAPIにはそのようにドキュメントされます。
|
||||
そして、OpenAPIにはそのようにドキュメント化されます。
|
||||
|
||||
///
|
||||
|
||||
### `Response` を返す { #return-a-response }
|
||||
### `Response` を返す
|
||||
|
||||
[レスポンスを直接返す](response-directly.md){.internal-link target=_blank}で見たように、レスポンスを返すことで、*path operation* の中でレスポンスを直接オーバーライドすることもできます。
|
||||
[レスポンスを直接返す](response-directly.md){.internal-link target=_blank}で見たように、レスポンスを直接返すことで、*path operation* の中でレスポンスをオーバーライドできます。
|
||||
|
||||
上記と同じ例において、 `HTMLResponse` を返すと、このようになります:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *}
|
||||
{* ../../docs_src/custom_response/tutorial003.py hl[2,7,19] *}
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
*path operation関数* から直接返される `Response` は、OpenAPIにドキュメントされず(例えば、`Content-Type` がドキュメントされない)、自動的な対話的ドキュメントでも表示されません。
|
||||
*path operation関数* から直接返される `Response` は、OpenAPIにドキュメントされず (例えば、 `Content-Type` がドキュメントされない) 、自動的な対話的ドキュメントからも閲覧できません。
|
||||
|
||||
///
|
||||
|
||||
/// info | 情報
|
||||
|
||||
もちろん、実際の `Content-Type` ヘッダーやステータスコードなどは、返された `Response` オブジェクトに由来します。
|
||||
もちろん、実際の `Content-Type` ヘッダーやステータスコードなどは、返された `Response` オブジェクトに由来しています。
|
||||
|
||||
///
|
||||
|
||||
### OpenAPIドキュメントと `Response` のオーバーライド { #document-in-openapi-and-override-response }
|
||||
### OpenAPIドキュメントと `Response` のオーバーライド
|
||||
|
||||
関数の中でレスポンスをオーバーライドしつつも、OpenAPI に「メディアタイプ」をドキュメント化したいなら、`response_class` パラメータを使用し、かつ `Response` オブジェクトを返します。
|
||||
関数の中でレスポンスをオーバーライドしつつも、OpenAPI に「メディアタイプ」をドキュメント化したいなら、 `response_class` パラメータを使い、 `Response` オブジェクトを返します。
|
||||
|
||||
`response_class` はOpenAPIの*path operation*のドキュメント化のためにのみ使用され、`Response` はそのまま使用されます。
|
||||
`response_class` はOpenAPIの *path operation* ドキュメントにのみ使用されますが、 `Response` はそのまま使用されます。
|
||||
|
||||
#### `HTMLResponse` を直接返す { #return-an-htmlresponse-directly }
|
||||
#### `HTMLResponse` を直接返す
|
||||
|
||||
例えば、このようになります:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial004_py39.py hl[7,21,23] *}
|
||||
{* ../../docs_src/custom_response/tutorial004.py hl[7,21,23] *}
|
||||
|
||||
この例では、関数 `generate_html_response()` は、`str` のHTMLを返すのではなく、`Response` を生成して返しています。
|
||||
この例では、関数 `generate_html_response()` は、`str` のHTMLを返すのではなく `Response` を生成して返しています。
|
||||
|
||||
`generate_html_response()` を呼び出した結果を返すことにより、デフォルトの **FastAPI** の挙動をオーバーライドする `Response` をすでに返しています。
|
||||
`generate_html_response()` を呼び出した結果を返すことにより、**FastAPI** の振る舞いを上書きする `Response` が既に返されています。
|
||||
|
||||
しかし、`response_class` にも `HTMLResponse` を渡しているため、**FastAPI** はOpenAPIと対話的ドキュメントで、`text/html` のHTMLとしてどのようにドキュメント化すればよいかを理解できます:
|
||||
しかし、一方では `response_class` に `HTMLResponse` を渡しているため、 **FastAPI** はOpenAPIや対話的ドキュメントでHTMLとして `text/html` でドキュメント化する方法を知っています。
|
||||
|
||||
<img src="/img/tutorial/custom-response/image01.png">
|
||||
|
||||
## 利用可能なレスポンス { #available-responses }
|
||||
## 利用可能なレスポンス
|
||||
|
||||
以下が利用可能なレスポンスの一部です。
|
||||
|
||||
@@ -117,11 +111,11 @@
|
||||
|
||||
`from starlette.responses import HTMLResponse` も利用できます。
|
||||
|
||||
**FastAPI** は開発者の利便性のために、`starlette.responses` と同じものを `fastapi.responses` として提供しています。しかし、利用可能なレスポンスのほとんどはStarletteから直接提供されます。
|
||||
**FastAPI** は開発者の利便性のために `fastapi.responses` として `starlette.responses` と同じものを提供しています。しかし、利用可能なレスポンスのほとんどはStarletteから直接提供されます。
|
||||
|
||||
///
|
||||
|
||||
### `Response` { #response }
|
||||
### `Response`
|
||||
|
||||
メインの `Response` クラスで、他の全てのレスポンスはこれを継承しています。
|
||||
|
||||
@@ -134,53 +128,41 @@
|
||||
* `headers` - 文字列の `dict` 。
|
||||
* `media_type` - メディアタイプを示す `str` 。例えば `"text/html"` 。
|
||||
|
||||
FastAPI(実際にはStarlette)は自動的にContent-Lengthヘッダーを含みます。また、`media_type` に基づいたContent-Typeヘッダーを含み、テキストタイプのためにcharsetを追加します。
|
||||
FastAPI (実際にはStarlette) は自動的にContent-Lengthヘッダーを含みます。また、media_typeに基づいたContent-Typeヘッダーを含み、テキストタイプのためにcharsetを追加します。
|
||||
|
||||
{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
|
||||
{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *}
|
||||
|
||||
### `HTMLResponse` { #htmlresponse }
|
||||
### `HTMLResponse`
|
||||
|
||||
上で読んだように、テキストやバイトを受け取り、HTMLレスポンスを返します。
|
||||
|
||||
### `PlainTextResponse` { #plaintextresponse }
|
||||
### `PlainTextResponse`
|
||||
|
||||
テキストやバイトを受け取り、プレーンテキストのレスポンスを返します。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial005_py39.py hl[2,7,9] *}
|
||||
{* ../../docs_src/custom_response/tutorial005.py hl[2,7,9] *}
|
||||
|
||||
### `JSONResponse` { #jsonresponse }
|
||||
### `JSONResponse`
|
||||
|
||||
データを受け取り、`application/json` としてエンコードされたレスポンスを返します。
|
||||
データを受け取り、 `application/json` としてエンコードされたレスポンスを返します。
|
||||
|
||||
上で読んだように、**FastAPI** のデフォルトのレスポンスとして利用されます。
|
||||
|
||||
### `ORJSONResponse` { #orjsonresponse }
|
||||
### `ORJSONResponse`
|
||||
|
||||
上で読んだように、<a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>を使った、高速な代替のJSONレスポンスです。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
これは、例えば `pip install orjson` で `orjson` をインストールする必要があります。
|
||||
|
||||
///
|
||||
|
||||
### `UJSONResponse` { #ujsonresponse }
|
||||
### `UJSONResponse`
|
||||
|
||||
<a href="https://github.com/ultrajson/ultrajson" class="external-link" target="_blank">`ujson`</a>を使った、代替のJSONレスポンスです。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
これは、例えば `pip install ujson` で `ujson` をインストールする必要があります。
|
||||
|
||||
///
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
`ujson` は、いくつかのエッジケースの取り扱いについて、Pythonにビルトインされた実装ほど注意深くありません。
|
||||
`ujson` は、いくつかのエッジケースの取り扱いについて、Pythonにビルトインされた実装よりも作りこまれていません。
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial001_py39.py hl[2,7] *}
|
||||
{* ../../docs_src/custom_response/tutorial001.py hl[2,7] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
@@ -188,61 +170,33 @@ FastAPI(実際にはStarlette)は自動的にContent-Lengthヘッダーを
|
||||
|
||||
///
|
||||
|
||||
### `RedirectResponse` { #redirectresponse }
|
||||
### `RedirectResponse`
|
||||
|
||||
HTTPリダイレクトを返します。デフォルトでは307ステータスコード(Temporary Redirect)となります。
|
||||
HTTPリダイレクトを返します。デフォルトでは307ステータスコード (Temporary Redirect) となります。
|
||||
|
||||
`RedirectResponse` を直接返せます:
|
||||
{* ../../docs_src/custom_response/tutorial006.py hl[2,9] *}
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial006_py39.py hl[2,9] *}
|
||||
### `StreamingResponse`
|
||||
|
||||
---
|
||||
非同期なジェネレータか通常のジェネレータ・イテレータを受け取り、レスポンスボディをストリームします。
|
||||
|
||||
または、`response_class` パラメータで使用できます:
|
||||
{* ../../docs_src/custom_response/tutorial007.py hl[2,14] *}
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial006b_py39.py hl[2,7,9] *}
|
||||
#### `StreamingResponse` をファイルライクなオブジェクトとともに使う
|
||||
|
||||
その場合、*path operation*関数からURLを直接返せます。
|
||||
ファイルライクなオブジェクト (例えば、 `open()` で返されたオブジェクト) がある場合、 `StreamingResponse` に含めて返すことができます。
|
||||
|
||||
この場合に使用される `status_code` は `RedirectResponse` のデフォルトである `307` になります。
|
||||
これにはクラウドストレージとの連携や映像処理など、多くのライブラリが含まれています。
|
||||
|
||||
---
|
||||
|
||||
また、`status_code` パラメータを `response_class` パラメータと組み合わせて使うこともできます:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial006c_py39.py hl[2,7,9] *}
|
||||
|
||||
### `StreamingResponse` { #streamingresponse }
|
||||
|
||||
非同期ジェネレータ、または通常のジェネレータ/イテレータを受け取り、レスポンスボディをストリームします。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial007_py39.py hl[2,14] *}
|
||||
|
||||
#### ファイルライクオブジェクトで `StreamingResponse` を使う { #using-streamingresponse-with-file-like-objects }
|
||||
|
||||
<a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> オブジェクト(例: `open()` で返されるオブジェクト)がある場合、そのfile-likeオブジェクトを反復処理するジェネレータ関数を作れます。
|
||||
|
||||
そうすれば、最初にすべてをメモリへ読み込む必要はなく、そのジェネレータ関数を `StreamingResponse` に渡して返せます。
|
||||
|
||||
これにはクラウドストレージとの連携、映像処理など、多くのライブラリが含まれます。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial008_py39.py hl[2,10:12,14] *}
|
||||
|
||||
1. これはジェネレータ関数です。内部に `yield` 文を含むため「ジェネレータ関数」です。
|
||||
2. `with` ブロックを使うことで、ジェネレータ関数が終わった後(つまりレスポンスの送信が完了した後)にfile-likeオブジェクトが確実にクローズされるようにします。
|
||||
3. この `yield from` は、`file_like` という名前のものを反復処理するように関数へ指示します。そして反復された各パートについて、そのパートをこのジェネレータ関数(`iterfile`)から来たものとして `yield` します。
|
||||
|
||||
つまり、内部的に「生成」の作業を別のものへ移譲するジェネレータ関数です。
|
||||
|
||||
このようにすることで `with` ブロックに入れられ、完了後にfile-likeオブジェクトが確実にクローズされます。
|
||||
{* ../../docs_src/custom_response/tutorial008.py hl[2,10:12,14] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
ここでは `async` と `await` をサポートしていない標準の `open()` を使っているため、通常の `def` でpath operationを宣言している点に注意してください。
|
||||
ここでは `async` や `await` をサポートしていない標準の `open()` を使っているので、通常の `def` でpath operationを宣言していることに注意してください。
|
||||
|
||||
///
|
||||
|
||||
### `FileResponse` { #fileresponse }
|
||||
### `FileResponse`
|
||||
|
||||
レスポンスとしてファイルを非同期的にストリームします。
|
||||
|
||||
@@ -250,63 +204,29 @@ HTTPリダイレクトを返します。デフォルトでは307ステータス
|
||||
|
||||
* `path` - ストリームするファイルのファイルパス。
|
||||
* `headers` - 含めたい任意のカスタムヘッダーの辞書。
|
||||
* `media_type` - メディアタイプを示す文字列。未設定の場合、ファイル名やパスからメディアタイプが推測されます。
|
||||
* `filename` - 設定した場合、レスポンスの `Content-Disposition` に含まれます。
|
||||
* `media_type` - メディアタイプを示す文字列。セットされなかった場合は、ファイル名やパスからメディアタイプが推察されます。
|
||||
* `filename` - セットされた場合、レスポンスの `Content-Disposition` に含まれます。
|
||||
|
||||
ファイルレスポンスには、適切な `Content-Length`、`Last-Modified`、`ETag` ヘッダーが含まれます。
|
||||
ファイルレスポンスには、適切な `Content-Length` 、 `Last-Modified` 、 `ETag` ヘッダーが含まれます。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial009_py39.py hl[2,10] *}
|
||||
{* ../../docs_src/custom_response/tutorial009.py hl[2,10] *}
|
||||
|
||||
`response_class` パラメータを使うこともできます:
|
||||
## デフォルトレスポンスクラス
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial009b_py39.py hl[2,8,10] *}
|
||||
**FastAPI** クラスのインスタンスか `APIRouter` を生成するときに、デフォルトのレスポンスクラスを指定できます。
|
||||
|
||||
この場合、*path operation*関数からファイルパスを直接返せます。
|
||||
定義するためのパラメータは、 `default_response_class` です。
|
||||
|
||||
## カスタムレスポンスクラス { #custom-response-class }
|
||||
以下の例では、 **FastAPI** は、全ての *path operation* で `JSONResponse` の代わりに `ORJSONResponse` をデフォルトとして利用します。
|
||||
|
||||
`Response` を継承した独自のカスタムレスポンスクラスを作成して利用できます。
|
||||
|
||||
例えば、<a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>を使いたいが、同梱の `ORJSONResponse` クラスで使われていないカスタム設定も使いたいとします。
|
||||
|
||||
例えば、インデントされ整形されたJSONを返したいので、orjsonオプション `orjson.OPT_INDENT_2` を使いたいとします。
|
||||
|
||||
`CustomORJSONResponse` を作れます。主に必要なのは、コンテンツを `bytes` として返す `Response.render(content)` メソッドを作ることです:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial009c_py39.py hl[9:14,17] *}
|
||||
|
||||
これまでは次のように返していたものが:
|
||||
|
||||
```json
|
||||
{"message": "Hello World"}
|
||||
```
|
||||
|
||||
...このレスポンスでは次のように返されます:
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Hello World"
|
||||
}
|
||||
```
|
||||
|
||||
もちろん、JSONの整形よりも、これを活用するもっと良い方法が見つかるはずです。 😉
|
||||
|
||||
## デフォルトレスポンスクラス { #default-response-class }
|
||||
|
||||
**FastAPI** クラスのインスタンス、または `APIRouter` を作成する際に、デフォルトで使用するレスポンスクラスを指定できます。
|
||||
|
||||
これを定義するパラメータは `default_response_class` です。
|
||||
|
||||
以下の例では、**FastAPI** はすべての*path operation*で、`JSONResponse` の代わりに `ORJSONResponse` をデフォルトとして使います。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial010_py39.py hl[2,4] *}
|
||||
{* ../../docs_src/custom_response/tutorial010.py hl[2,4] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
これまでと同様に、*path operation*で `response_class` をオーバーライドできます。
|
||||
前に見たように、 *path operation* の中で `response_class` をオーバーライドできます。
|
||||
|
||||
///
|
||||
|
||||
## その他のドキュメント { #additional-documentation }
|
||||
## その他のドキュメント
|
||||
|
||||
OpenAPIでは `responses` を使ってメディアタイプやその他の詳細を宣言することもできます: [Additional Responses in OpenAPI](additional-responses.md){.internal-link target=_blank}。
|
||||
また、OpenAPIでは `responses` を使ってメディアタイプやその他の詳細を宣言することもできます: [Additional Responses in OpenAPI](additional-responses.md){.internal-link target=_blank}
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
# 高度なユーザーガイド { #advanced-user-guide }
|
||||
# 高度なユーザーガイド
|
||||
|
||||
## さらなる機能 { #additional-features }
|
||||
## さらなる機能
|
||||
|
||||
メインの[チュートリアル - ユーザーガイド](../tutorial/index.md){.internal-link target=_blank}だけで、**FastAPI**の主要な機能を一通り把握するには十分なはずです。
|
||||
[チュートリアル - ユーザーガイド](../tutorial/index.md){.internal-link target=_blank}により、**FastAPI**の主要な機能は十分に理解できたことでしょう。
|
||||
|
||||
以降のセクションでは、その他のオプション、設定、追加機能を見ていきます。
|
||||
以降のセクションでは、チュートリアルでは説明しきれなかったオプションや設定、および機能について説明します。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
以降のセクションは、**必ずしも「高度」ではありません**。
|
||||
以降のセクションは、 **必ずしも"応用編"ではありません**。
|
||||
|
||||
また、あなたのユースケースに対する解決策が、その中のどれかにある可能性もあります。
|
||||
ユースケースによっては、その中から解決策を見つけられるかもしれません。
|
||||
|
||||
///
|
||||
|
||||
## 先にチュートリアルを読む { #read-the-tutorial-first }
|
||||
## 先にチュートリアルを読む
|
||||
|
||||
メインの[チュートリアル - ユーザーガイド](../tutorial/index.md){.internal-link target=_blank}で得た知識があれば、**FastAPI**の機能の多くは引き続き利用できます。
|
||||
[チュートリアル - ユーザーガイド](../tutorial/index.md){.internal-link target=_blank}の知識があれば、**FastAPI**の主要な機能を利用することができます。
|
||||
|
||||
また、以降のセクションでは、すでにそれを読んでいて、主要な考え方を理解していることを前提としています。
|
||||
以降のセクションは、すでにチュートリアルを読んで、その主要なアイデアを理解できていることを前提としています。
|
||||
|
||||
## テスト駆動開発のコース
|
||||
|
||||
このセクションの内容を補完するために脱初心者用コースを受けたい場合は、**TestDriven.io**による、<a href="https://testdriven.io/courses/tdd-fastapi/" class="external-link" target="_blank">Test-Driven Development with FastAPI and Docker</a>を確認するのがよいかもしれません。
|
||||
|
||||
現在、このコースで得られた利益の10%が**FastAPI**の開発のために寄付されています。🎉 😄
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
# Path Operationの高度な設定 { #path-operation-advanced-configuration }
|
||||
# Path Operationの高度な設定
|
||||
|
||||
## OpenAPI operationId { #openapi-operationid }
|
||||
## OpenAPI operationId
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
OpenAPIの「エキスパート」でなければ、これはおそらく必要ありません。
|
||||
あなたがOpenAPIの「エキスパート」でなければ、これは必要ないかもしれません。
|
||||
|
||||
///
|
||||
|
||||
*path operation* で `operation_id` パラメータを利用することで、OpenAPIの `operationId` を設定できます。
|
||||
|
||||
各オペレーションで一意になるようにする必要があります。
|
||||
`operation_id` は各オペレーションで一意にする必要があります。
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial001.py hl[6] *}
|
||||
|
||||
### *path operation関数* の名前をoperationIdとして使用する { #using-the-path-operation-function-name-as-the-operationid }
|
||||
### *path operation関数* の名前をoperationIdとして使用する
|
||||
|
||||
APIの関数名を `operationId` として利用したい場合、すべてのAPI関数をイテレーションし、各 *path operation* の `operation_id` を `APIRoute.name` で上書きすれば可能です。
|
||||
APIの関数名を `operationId` として利用したい場合、すべてのAPIの関数をイテレーションし、各 *path operation* の `operationId` を `APIRoute.name` で上書きすれば可能です。
|
||||
|
||||
すべての *path operation* を追加した後に行うべきです。
|
||||
そうする場合は、すべての *path operation* を追加した後に行う必要があります。
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial002.py hl[2,12:21,24] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`app.openapi()` を手動で呼び出す場合、その前に `operationId` を更新するべきです。
|
||||
`app.openapi()` を手動でコールする場合、その前に`operationId`を更新する必要があります。
|
||||
|
||||
///
|
||||
|
||||
@@ -32,141 +32,22 @@ APIの関数名を `operationId` として利用したい場合、すべてのAP
|
||||
|
||||
この方法をとる場合、各 *path operation関数* が一意な名前である必要があります。
|
||||
|
||||
異なるモジュール(Pythonファイル)にある場合でも同様です。
|
||||
それらが異なるモジュール (Pythonファイル) にあるとしてもです。
|
||||
|
||||
///
|
||||
|
||||
## OpenAPIから除外する { #exclude-from-openapi }
|
||||
## OpenAPIから除外する
|
||||
|
||||
生成されるOpenAPIスキーマ(つまり、自動ドキュメント生成の仕組み)から *path operation* を除外するには、`include_in_schema` パラメータを使用して `False` に設定します。
|
||||
生成されるOpenAPIスキーマ (つまり、自動ドキュメント生成の仕組み) から *path operation* を除外するには、 `include_in_schema` パラメータを `False` にします。
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial003.py hl[6] *}
|
||||
|
||||
## docstringによる説明の高度な設定 { #advanced-description-from-docstring }
|
||||
## docstringによる説明の高度な設定
|
||||
|
||||
*path operation関数* のdocstringからOpenAPIに使用する行を制限できます。
|
||||
*path operation関数* のdocstringからOpenAPIに使用する行を制限することができます。
|
||||
|
||||
`\f`(エスケープされた「書式送り(form feed)」文字)を追加すると、**FastAPI** はその地点でOpenAPIに使用される出力を切り詰めます。
|
||||
`\f` (「書式送り (Form Feed)」のエスケープ文字) を付与することで、**FastAPI** はOpenAPIに使用される出力をその箇所までに制限します。
|
||||
|
||||
ドキュメントには表示されませんが、他のツール(Sphinxなど)は残りの部分を利用できます。
|
||||
ドキュメントには表示されませんが、他のツール (例えばSphinx) では残りの部分を利用できるでしょう。
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}
|
||||
|
||||
## 追加レスポンス { #additional-responses }
|
||||
|
||||
*path operation* に対して `response_model` と `status_code` を宣言する方法はすでに見たことがあるでしょう。
|
||||
|
||||
それにより、*path operation* のメインのレスポンスに関するメタデータが定義されます。
|
||||
|
||||
追加のレスポンスについても、モデルやステータスコードなどとともに宣言できます。
|
||||
|
||||
これについてはドキュメントに章全体があります。 [OpenAPIの追加レスポンス](additional-responses.md){.internal-link target=_blank} で読めます。
|
||||
|
||||
## OpenAPI Extra { #openapi-extra }
|
||||
|
||||
アプリケーションで *path operation* を宣言すると、**FastAPI** はOpenAPIスキーマに含めるために、その *path operation* に関連するメタデータを自動的に生成します。
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
OpenAPI仕様では <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object" class="external-link" target="_blank">Operation Object</a> と呼ばれています。
|
||||
|
||||
///
|
||||
|
||||
これには *path operation* に関するすべての情報が含まれ、自動ドキュメントを生成するために使われます。
|
||||
|
||||
`tags`、`parameters`、`requestBody`、`responses` などが含まれます。
|
||||
|
||||
この *path operation* 固有のOpenAPIスキーマは通常 **FastAPI** により自動生成されますが、拡張することもできます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
これは低レベルな拡張ポイントです。
|
||||
|
||||
追加レスポンスを宣言するだけなら、より便利な方法として [OpenAPIの追加レスポンス](additional-responses.md){.internal-link target=_blank} を使うことができます。
|
||||
|
||||
///
|
||||
|
||||
`openapi_extra` パラメータを使って、*path operation* のOpenAPIスキーマを拡張できます。
|
||||
|
||||
### OpenAPI Extensions { #openapi-extensions }
|
||||
|
||||
この `openapi_extra` は、例えば [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) を宣言するのに役立ちます。
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py39.py hl[6] *}
|
||||
|
||||
自動APIドキュメントを開くと、その拡張は特定の *path operation* の下部に表示されます。
|
||||
|
||||
<img src="/img/tutorial/path-operation-advanced-configuration/image01.png">
|
||||
|
||||
そして(APIの `/openapi.json` にある)生成されたOpenAPIを見ると、その拡張も特定の *path operation* の一部として確認できます。
|
||||
|
||||
```JSON hl_lines="22"
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "FastAPI",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"paths": {
|
||||
"/items/": {
|
||||
"get": {
|
||||
"summary": "Read Items",
|
||||
"operationId": "read_items_items__get",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-aperture-labs-portal": "blue"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### カスタムOpenAPI *path operation* スキーマ { #custom-openapi-path-operation-schema }
|
||||
|
||||
`openapi_extra` 内の辞書は、*path operation* 用に自動生成されたOpenAPIスキーマと深くマージされます。
|
||||
|
||||
そのため、自動生成されたスキーマに追加データを加えることができます。
|
||||
|
||||
例えば、Pydanticを使ったFastAPIの自動機能を使わずに独自のコードでリクエストを読み取り・検証することを選べますが、それでもOpenAPIスキーマでリクエストを定義したい場合があります。
|
||||
|
||||
それは `openapi_extra` で行えます。
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *}
|
||||
|
||||
この例では、Pydanticモデルを一切宣言していません。実際、リクエストボディはJSONとして <abbr title="converted from some plain format, like bytes, into Python objects – bytesなどのプレーンな形式からPythonオブジェクトに変換すること">parsed</abbr> されず、直接 `bytes` として読み取られます。そして `magic_data_reader()` 関数が、何らかの方法でそれをパースする責務を担います。
|
||||
|
||||
それでも、リクエストボディに期待されるスキーマを宣言できます。
|
||||
|
||||
### カスタムOpenAPI content type { #custom-openapi-content-type }
|
||||
|
||||
同じトリックを使って、PydanticモデルでJSON Schemaを定義し、それを *path operation* 用のカスタムOpenAPIスキーマセクションに含めることができます。
|
||||
|
||||
また、リクエスト内のデータ型がJSONでない場合でもこれを行えます。
|
||||
|
||||
例えばこのアプリケーションでは、PydanticモデルからJSON Schemaを抽出するFastAPIの統合機能や、JSONの自動バリデーションを使っていません。実際、リクエストのcontent typeをJSONではなくYAMLとして宣言しています。
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
|
||||
|
||||
それでも、デフォルトの統合機能を使っていないにもかかわらず、YAMLで受け取りたいデータのために、Pydanticモデルを使って手動でJSON Schemaを生成しています。
|
||||
|
||||
そしてリクエストを直接使い、ボディを `bytes` として抽出します。これは、FastAPIがリクエストペイロードをJSONとしてパースしようとすらしないことを意味します。
|
||||
|
||||
その後、コード内でそのYAMLコンテンツを直接パースし、さらに同じPydanticモデルを使ってYAMLコンテンツを検証しています。
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
ここでは同じPydanticモデルを再利用しています。
|
||||
|
||||
ただし同様に、別の方法で検証することもできます。
|
||||
|
||||
///
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial004.py hl[19:29] *}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# レスポンスを直接返す { #return-a-response-directly }
|
||||
# レスポンスを直接返す
|
||||
|
||||
**FastAPI** の *path operation* では、通常は任意のデータを返すことができます: 例えば、 `dict`、`list`、Pydanticモデル、データベースモデルなどです。
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
これは例えば、カスタムヘッダーやcookieを返すときに便利です。
|
||||
|
||||
## `Response` を返す { #return-a-response }
|
||||
## `Response` を返す
|
||||
|
||||
実際は、`Response` やそのサブクラスを返すことができます。
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
これは多くの柔軟性を提供します。任意のデータ型を返したり、任意のデータ宣言やバリデーションをオーバーライドできます。
|
||||
|
||||
## `jsonable_encoder` を `Response` の中で使う { #using-the-jsonable-encoder-in-a-response }
|
||||
## `jsonable_encoder` を `Response` の中で使う
|
||||
|
||||
**FastAPI** はあなたが返す `Response` に対して何も変更を加えないので、コンテンツが準備できていることを保証しなければなりません。
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
このようなケースでは、レスポンスにデータを含める前に `jsonable_encoder` を使ってデータを変換できます。
|
||||
|
||||
{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}
|
||||
{* ../../docs_src/response_directly/tutorial001.py hl[6:7,21:22] *}
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
///
|
||||
|
||||
## カスタム `Response` を返す { #returning-a-custom-response }
|
||||
## カスタム `Response` を返す
|
||||
|
||||
上記の例では必要な部分を全て示していますが、あまり便利ではありません。`item` を直接返すことができるし、**FastAPI** はそれを `dict` に変換して `JSONResponse` に含めてくれるなど。すべて、デフォルトの動作です。
|
||||
|
||||
@@ -54,9 +54,9 @@
|
||||
|
||||
XMLを文字列にし、`Response` に含め、それを返します。
|
||||
|
||||
{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
|
||||
{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *}
|
||||
|
||||
## 備考 { #notes }
|
||||
## 備考
|
||||
|
||||
`Response` を直接返す場合、バリデーションや、変換 (シリアライズ) や、自動ドキュメントは行われません。
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# WebSockets { #websockets }
|
||||
# WebSocket
|
||||
|
||||
**FastAPI**で<a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" class="external-link" target="_blank">WebSockets</a>が使用できます。
|
||||
**FastAPI**で<a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" class="external-link" target="_blank">WebSocket</a>が使用できます。
|
||||
|
||||
## `websockets`のインストール { #install-websockets }
|
||||
## `WebSockets`のインストール
|
||||
|
||||
[仮想環境](../virtual-environments.md){.internal-link target=_blank}を作成し、それを有効化してから、「WebSocket」プロトコルを簡単に使えるようにするPythonライブラリの`websockets`をインストールしてください。
|
||||
まず `WebSockets`のインストールが必要です。
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -16,13 +16,13 @@ $ pip install websockets
|
||||
|
||||
</div>
|
||||
|
||||
## WebSockets クライアント { #websockets-client }
|
||||
## WebSocket クライアント
|
||||
|
||||
### 本番環境 { #in-production }
|
||||
### 本番環境
|
||||
|
||||
本番環境では、React、Vue.js、Angularなどの最新のフレームワークで作成されたフロントエンドを使用しているでしょう。
|
||||
|
||||
そして、バックエンドとWebSocketsを使用して通信するために、おそらくフロントエンドのユーティリティを使用することになるでしょう。
|
||||
そして、バックエンドとWebSocketを使用して通信するために、おそらくフロントエンドのユーティリティを使用することになるでしょう。
|
||||
|
||||
または、ネイティブコードでWebSocketバックエンドと直接通信するネイティブモバイルアプリケーションがあるかもしれません。
|
||||
|
||||
@@ -30,21 +30,21 @@ $ pip install websockets
|
||||
|
||||
---
|
||||
|
||||
ただし、この例では非常にシンプルなHTML文書といくつかのJavaScriptを、すべて長い文字列の中に入れて使用することにします。
|
||||
ただし、この例では非常にシンプルなHTML文書といくつかのJavaScriptを、すべてソースコードの中に入れて使用することにします。
|
||||
|
||||
もちろん、これは最適な方法ではありませんし、本番環境で使うことはないでしょう。
|
||||
|
||||
本番環境では、上記の方法のいずれかの選択肢を採用することになるでしょう。
|
||||
|
||||
しかし、これはWebSocketsのサーバーサイドに焦点を当て、動作する例を示す最も簡単な方法です。
|
||||
しかし、これはWebSocketのサーバーサイドに焦点を当て、実用的な例を示す最も簡単な方法です。
|
||||
|
||||
{* ../../docs_src/websockets/tutorial001_py39.py hl[2,6:38,41:43] *}
|
||||
{* ../../docs_src/websockets/tutorial001.py hl[2,6:38,41:43] *}
|
||||
|
||||
## `websocket` を作成する { #create-a-websocket }
|
||||
## `websocket` を作成する
|
||||
|
||||
**FastAPI** アプリケーションで、`websocket` を作成します。
|
||||
|
||||
{* ../../docs_src/websockets/tutorial001_py39.py hl[1,46:47] *}
|
||||
{* ../../docs_src/websockets/tutorial001.py hl[1,46:47] *}
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
@@ -54,22 +54,22 @@ $ pip install websockets
|
||||
|
||||
///
|
||||
|
||||
## メッセージを待機して送信する { #await-for-messages-and-send-messages }
|
||||
## メッセージの送受信
|
||||
|
||||
WebSocketルートでは、メッセージを待機して送信するために `await` を使用できます。
|
||||
WebSocketルートでは、 `await` を使ってメッセージの送受信ができます。
|
||||
|
||||
{* ../../docs_src/websockets/tutorial001_py39.py hl[48:52] *}
|
||||
{* ../../docs_src/websockets/tutorial001.py hl[48:52] *}
|
||||
|
||||
バイナリやテキストデータ、JSONデータを送受信できます。
|
||||
|
||||
## 試してみる { #try-it }
|
||||
## 試してみる
|
||||
|
||||
ファイル名が `main.py` である場合、以下でアプリケーションを実行します。
|
||||
ファイル名が `main.py` である場合、以下の方法でアプリケーションを実行します。
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi dev main.py
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
@@ -86,7 +86,7 @@ $ fastapi dev main.py
|
||||
|
||||
<img src="/img/tutorial/websockets/image02.png">
|
||||
|
||||
そして、 WebSocketsを使用した**FastAPI**アプリケーションが応答します。
|
||||
そして、 WebSocketを使用した**FastAPI**アプリケーションが応答します。
|
||||
|
||||
<img src="/img/tutorial/websockets/image03.png">
|
||||
|
||||
@@ -96,7 +96,7 @@ $ fastapi dev main.py
|
||||
|
||||
そして、これらの通信はすべて同じWebSocket接続を使用します。
|
||||
|
||||
## `Depends` などの使用 { #using-depends-and-others }
|
||||
## 依存関係
|
||||
|
||||
WebSocketエンドポイントでは、`fastapi` から以下をインポートして使用できます。
|
||||
|
||||
@@ -107,26 +107,28 @@ WebSocketエンドポイントでは、`fastapi` から以下をインポート
|
||||
* `Path`
|
||||
* `Query`
|
||||
|
||||
これらは、他のFastAPI エンドポイント/*path operations* の場合と同じように機能します。
|
||||
これらは、他のFastAPI エンドポイント/*path operation* の場合と同じように機能します。
|
||||
|
||||
{* ../../docs_src/websockets/tutorial002_an_py310.py hl[68:69,82] *}
|
||||
{* ../../docs_src/websockets/tutorial002.py hl[58:65,68:83] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
これはWebSocketであるため、`HTTPException` を発生させることはあまり意味がありません。代わりに `WebSocketException` を発生させます。
|
||||
WebSocket で `HTTPException` を発生させることはあまり意味がありません。したがって、WebSocketの接続を直接閉じる方がよいでしょう。
|
||||
|
||||
クロージングコードは、<a href="https://tools.ietf.org/html/rfc6455#section-7.4.1" class="external-link" target="_blank">仕様で定義された有効なコード</a>の中から使用することができます。
|
||||
|
||||
将来的には、どこからでも `raise` できる `WebSocketException` が用意され、専用の例外ハンドラを追加できるようになる予定です。これは、Starlette の <a href="https://github.com/encode/starlette/pull/527" class="external-link" target="_blank">PR #527</a> に依存するものです。
|
||||
|
||||
///
|
||||
|
||||
### 依存関係を用いてWebSocketsを試してみる { #try-the-websockets-with-dependencies }
|
||||
### 依存関係を用いてWebSocketsを試してみる
|
||||
|
||||
ファイル名が `main.py` である場合、以下でアプリケーションを実行します。
|
||||
ファイル名が `main.py` である場合、以下の方法でアプリケーションを実行します。
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi dev main.py
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
@@ -135,14 +137,14 @@ $ fastapi dev main.py
|
||||
|
||||
ブラウザで <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a> を開きます。
|
||||
|
||||
そこで、以下を設定できます。
|
||||
クライアントが設定できる項目は以下の通りです。
|
||||
|
||||
* パスで使用される「Item ID」
|
||||
* クエリパラメータとして使用される「Token」
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
クエリ `token` は依存関係によって処理されることに注意してください。
|
||||
クエリ `token` は依存パッケージによって処理されることに注意してください。
|
||||
|
||||
///
|
||||
|
||||
@@ -150,11 +152,11 @@ $ fastapi dev main.py
|
||||
|
||||
<img src="/img/tutorial/websockets/image05.png">
|
||||
|
||||
## 切断や複数クライアントの処理 { #handling-disconnections-and-multiple-clients }
|
||||
## 切断や複数クライアントへの対応
|
||||
|
||||
WebSocket接続が閉じられると、 `await websocket.receive_text()` は例外 `WebSocketDisconnect` を発生させ、この例のようにキャッチして処理することができます。
|
||||
|
||||
{* ../../docs_src/websockets/tutorial003_py39.py hl[79:81] *}
|
||||
{* ../../docs_src/websockets/tutorial003.py hl[81:83] *}
|
||||
|
||||
試してみるには、
|
||||
|
||||
@@ -172,15 +174,15 @@ Client #1596980209979 left the chat
|
||||
|
||||
上記のアプリは、複数の WebSocket 接続に対してメッセージを処理し、ブロードキャストする方法を示すための最小限のシンプルな例です。
|
||||
|
||||
しかし、すべてがメモリ内の単一のリストで処理されるため、プロセスの実行中にのみ機能し、単一のプロセスでのみ機能することに注意してください。
|
||||
しかし、すべての接続がメモリ内の単一のリストで処理されるため、プロセスの実行中にのみ機能し、単一のプロセスでのみ機能することに注意してください。
|
||||
|
||||
FastAPIと簡単に統合できて、RedisやPostgreSQLなどでサポートされている、より堅牢なものが必要なら、<a href="https://github.com/encode/broadcaster" class="external-link" target="_blank">encode/broadcaster</a> を確認してください。
|
||||
もしFastAPIと簡単に統合できて、RedisやPostgreSQLなどでサポートされている、より堅牢なものが必要なら、<a href="https://github.com/encode/broadcaster" class="external-link" target="_blank">encode/broadcaster</a> を確認してください。
|
||||
|
||||
///
|
||||
|
||||
## 詳細情報 { #more-info }
|
||||
## その他のドキュメント
|
||||
|
||||
オプションの詳細については、Starletteのドキュメントを確認してください。
|
||||
|
||||
* <a href="https://www.starlette.dev/websockets/" class="external-link" target="_blank">`WebSocket` クラス</a>.
|
||||
* <a href="https://www.starlette.dev/endpoints/#websocketendpoint" class="external-link" target="_blank">クラスベースのWebSocket処理</a>.
|
||||
* <a href="https://www.starlette.dev/websockets/" class="external-link" target="_blank"> `WebSocket` クラス</a>
|
||||
* <a href="https://www.starlette.dev/endpoints/#websocketendpoint" class="external-link" target="_blank">クラスベースのWebSocket処理</a>
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
# ベンチマーク { #benchmarks }
|
||||
# ベンチマーク
|
||||
|
||||
TechEmpowerの独立したベンチマークでは、Uvicornの下で動作する**FastAPI**アプリケーションは、<a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">利用可能な最速のPythonフレームワークの1つ</a>であり、下回っているのはStarletteとUvicorn自体(FastAPIによって内部で使用される)のみだと示されています。
|
||||
TechEmpowerの独立したベンチマークでは、Uvicornの下で動作する**FastAPI**アプリケーションは、<a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">利用可能な最速のPythonフレームワークの1つ</a>であり、下回っているのはStarletteとUvicorn自体 (FastAPIによって内部で使用される) のみだと示されています。
|
||||
|
||||
ただし、ベンチマークを確認し、比較する際には下記の内容に気を付けてください。
|
||||
|
||||
## ベンチマークと速度 { #benchmarks-and-speed }
|
||||
## ベンチマークと速度
|
||||
|
||||
ベンチマークを確認する時、異なるタイプの複数のツールが同等のものとして比較されているのを目にするのが一般的です。
|
||||
ベンチマークを確認する時、異なるツールを同等なものと比較するのが一般的です。
|
||||
|
||||
具体的には、Uvicorn、Starlette、FastAPIを(他の多くのツールの中で)まとめて比較しているのを目にすることがあります。
|
||||
具体的には、Uvicorn、Starlette、FastAPIを (他の多くのツールと) 比較しました。
|
||||
|
||||
ツールで解決する問題がシンプルなほど、パフォーマンスが向上します。また、ほとんどのベンチマークは、ツールから提供される追加機能をテストしていません。
|
||||
|
||||
階層関係はこのようになります。
|
||||
|
||||
* **Uvicorn**: ASGIサーバー
|
||||
* **Starlette**: (Uvicornを使用)webマイクロフレームワーク
|
||||
* **FastAPI**: (Starletteを使用)データバリデーションなど、APIを構築するためのいくつかの追加機能を備えたAPIマイクロフレームワーク
|
||||
* **Starlette**: (Uvicornを使用) WEBマイクロフレームワーク
|
||||
* **FastAPI**: (Starletteを使用) データバリデーションなどの、APIを構築する追加機能を備えたAPIマイクロフレームワーク
|
||||
|
||||
* **Uvicorn**:
|
||||
* サーバー自体以外に余分なコードがあまりないため、最高のパフォーマンスになります。
|
||||
* Uvicornにアプリケーションを直接書くことはないでしょう。それは、あなたのコードに、Starlette(または**FastAPI**)が提供するコードを、少なくとも多かれ少なかれ含める必要があるということです。そして、もしそうした場合、最終的なアプリケーションは、フレームワークを使用してアプリのコードとバグを最小限に抑えた場合と同じオーバーヘッドになります。
|
||||
* Uvicornを比較する場合は、Daphne、Hypercorn、uWSGIなどのアプリケーションサーバーと比較してください。
|
||||
* サーバー自体に余分なコードが少ないので、最高のパフォーマンスが得られます。
|
||||
* Uvicornにアプリケーションを直接書くことはできません。つまり、あなたのコードには、Starlette (または** FastAPI **) が提供するコードを、多かれ少なかれ含める必要があります。そうすると、最終的なアプリケーションは、フレームワークを使用してアプリのコードとバグを最小限に抑えた場合と同じオーバーヘッドになります。
|
||||
* もしUvicornを比較する場合は、Daphne、Hypercorn、uWSGIなどのアプリケーションサーバーと比較してください。
|
||||
* **Starlette**:
|
||||
* Uvicornに次ぐ性能になるでしょう。実際、Starletteは実行にUvicornを使用しています。そのため、おそらく、より多くのコードを実行しなければならない分だけ、Uvicornより「遅く」なるだけです。
|
||||
* しかし、パスに基づくルーティングなどを使って、シンプルなwebアプリケーションを構築するためのツールを提供します。
|
||||
* Starletteを比較する場合は、Sanic、Flask、Djangoなどのwebフレームワーク(またはマイクロフレームワーク)と比較してください。
|
||||
* Uvicornに次ぐ性能を持つでしょう。実際、StarletteはUvicornを使用しています。だから、より多くのコードを実行する必要があり、Uvicornよりも「遅く」なってしまうだけなのです。
|
||||
* しかし、パスベースのルーティングなどのシンプルなWEBアプリケーションを構築する機能を提供します。
|
||||
* もしStarletteを比較する場合は、Sanic、Flask、DjangoなどのWEBフレームワーク (もしくはマイクロフレームワーク) と比較してください。
|
||||
* **FastAPI**:
|
||||
* StarletteがUvicornを使用しており、それより速くできないのと同じように、**FastAPI**はStarletteを使用しているため、それより速くできません。
|
||||
* FastAPIはStarletteの上に、より多くの機能を提供します。データバリデーションやシリアライゼーションのように、APIを構築する際にほとんど常に必要な機能です。また、それを使用することで、自動ドキュメント化を無料で利用できます(自動ドキュメントは実行中のアプリケーションにオーバーヘッドを追加せず、起動時に生成されます)。
|
||||
* FastAPIを使用せず、Starletteを直接(またはSanic、Flask、Responderなど別のツールを)使用した場合、データバリデーションとシリアライゼーションをすべて自分で実装する必要があります。そのため、最終的なアプリケーションはFastAPIを使用して構築した場合と同じオーバーヘッドが発生します。そして多くの場合、このデータバリデーションとシリアライゼーションは、アプリケーションで書かれるコードの大部分になります。
|
||||
* そのため、FastAPIを使用することで、開発時間、バグ、コード行数を節約でき、使用しない場合(あなたがそれをすべて自分のコードで実装する必要があるため)と比べて、同じパフォーマンス(またはそれ以上)を得られる可能性があります。
|
||||
* FastAPIを比較する場合は、Flask-apispec、NestJS、Moltenなど、データバリデーション、シリアライゼーション、ドキュメント化を提供するwebアプリケーションフレームワーク(またはツール群)と比較してください。自動データバリデーション、シリアライゼーション、ドキュメント化が統合されたフレームワークです。
|
||||
* StarletteがUvicornを使っているのと同じで、**FastAPI**はStarletteを使っており、それより速くできません。
|
||||
* FastAPIはStarletteの上にさらに多くの機能を提供します。データの検証やシリアライゼーションなど、APIを構築する際に常に必要な機能です。また、それを使用することで、自動ドキュメント化を無料で取得できます (ドキュメントは実行中のアプリケーションにオーバーヘッドを追加せず、起動時に生成されます) 。
|
||||
* FastAPIを使用せず、直接Starlette (またはSanic, Flask, Responderなど) を使用した場合、データの検証とシリアライズをすべて自分で実装する必要があります。そのため、最終的なアプリケーションはFastAPIを使用して構築した場合と同じオーバーヘッドが発生します。そして、多くの場合、このデータ検証とシリアライズは、アプリケーションのコードの中で最大の記述量になります。
|
||||
* FastAPIを使用することで、開発時間、バグ、コード行数を節約でき、使用しない場合 (あなたが全ての機能を実装し直した場合) と同じかそれ以上のパフォーマンスを得られます。
|
||||
* もしFastAPIを比較する場合は、Flask-apispec、NestJS、Moltenなどのデータ検証や、シリアライズの機能を提供するWEBフレームワーク (や機能のセット) と比較してください。これらはデータの自動検証や、シリアライズ、ドキュメント化が統合されたフレームワークです。
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# デプロイメントのコンセプト { #deployments-concepts }
|
||||
# デプロイメントのコンセプト
|
||||
|
||||
**FastAPI**を用いたアプリケーションをデプロイするとき、もしくはどのようなタイプのWeb APIであっても、おそらく気になるコンセプトがいくつかあります。
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
* 起動時の実行
|
||||
* 再起動
|
||||
* レプリケーション(実行中のプロセス数)
|
||||
* メモリ
|
||||
* メモリー
|
||||
* 開始前の事前のステップ
|
||||
|
||||
これらが**デプロイメント**にどのような影響を与えるかを見ていきましょう。
|
||||
|
||||
最終的な目的は、**安全な方法で**APIクライアントに**サービスを提供**し、**中断を回避**するだけでなく、**計算リソース**(例えばリモートサーバー/仮想マシン)を可能な限り効率的に使用することです。 🚀
|
||||
最終的な目的は、**安全な方法で**APIクライアントに**サービスを提供**し、**中断を回避**するだけでなく、**計算リソース**(例えばリモートサーバー/仮想マシン)を可能な限り効率的に使用することです。🚀
|
||||
|
||||
この章では前述した**コンセプト**についてそれぞれ説明します。
|
||||
|
||||
@@ -27,16 +27,16 @@
|
||||
|
||||
しかし、今はこれらの重要な**コンセプトに基づくアイデア**を確認しましょう。これらのコンセプトは、他のどのタイプのWeb APIにも当てはまります。💡
|
||||
|
||||
## セキュリティ - HTTPS { #security-https }
|
||||
## セキュリティ - HTTPS
|
||||
|
||||
<!-- NOTE: https.md written in Japanese does not exist, so it redirects to English one -->
|
||||
[前チャプターのHTTPSについて](https.md){.internal-link target=_blank}では、HTTPSがどのようにAPIを暗号化するのかについて学びました。
|
||||
|
||||
通常、アプリケーションサーバにとって**外部の**コンポーネントである**TLS Termination Proxy**によって提供されることが一般的です。このプロキシは通信の暗号化を担当します。
|
||||
|
||||
さらに、HTTPS証明書の更新を担当するものが必要で、同じコンポーネントが担当することもあれば、別のコンポーネントが担当することもあります。
|
||||
さらにセキュアな通信において、HTTPS証明書の定期的な更新を行いますが、これはTLS Termination Proxyと同じコンポーネントが担当することもあれば、別のコンポーネントが担当することもあります。
|
||||
|
||||
### HTTPS 用ツールの例 { #example-tools-for-https }
|
||||
### HTTPS 用ツールの例
|
||||
TLS Termination Proxyとして使用できるツールには以下のようなものがあります:
|
||||
|
||||
* Traefik
|
||||
@@ -59,11 +59,11 @@ TLS Termination Proxyとして使用できるツールには以下のような
|
||||
|
||||
次に考慮すべきコンセプトは、実際のAPIを実行するプログラム(例:Uvicorn)に関連するものすべてです。
|
||||
|
||||
## プログラム と プロセス { #program-and-process }
|
||||
## プログラム と プロセス
|
||||
|
||||
私たちは「**プロセス**」という言葉についてたくさん話すので、その意味や「**プログラム**」という言葉との違いを明確にしておくと便利です。
|
||||
|
||||
### プログラムとは何か { #what-is-a-program }
|
||||
### プログラムとは何か
|
||||
|
||||
**プログラム**という言葉は、一般的にいろいろなものを表現するのに使われます:
|
||||
|
||||
@@ -71,7 +71,7 @@ TLS Termination Proxyとして使用できるツールには以下のような
|
||||
* OSによって実行することができるファイル(例: `python`, `python.exe` or `uvicorn`)
|
||||
* OS上で**実行**している間、CPUを使用し、メモリ上に何かを保存する特定のプログラム(**プロセス**とも呼ばれる)
|
||||
|
||||
### プロセスとは何か { #what-is-a-process }
|
||||
### プロセスとは何か
|
||||
|
||||
**プロセス**という言葉は通常、より具体的な意味で使われ、OSで実行されているものだけを指します(先ほどの最後の説明のように):
|
||||
|
||||
@@ -92,29 +92,27 @@ OSの「タスク・マネージャー」や「システム・モニター」(
|
||||
|
||||
さて、**プロセス**と**プログラム**という用語の違いを確認したところで、デプロイメントについて話を続けます。
|
||||
|
||||
## 起動時の実行 { #running-on-startup }
|
||||
## 起動時の実行
|
||||
|
||||
ほとんどの場合、Web APIを作成するときは、クライアントがいつでもアクセスできるように、**常に**中断されることなく**実行される**ことを望みます。もちろん、特定の状況でのみ実行させたい特別な理由がある場合は別ですが、その時間のほとんどは、常に実行され、**利用可能**であることを望みます。
|
||||
|
||||
### リモートサーバー上での実行 { #in-a-remote-server }
|
||||
### リモートサーバー上での実行
|
||||
|
||||
リモートサーバー(クラウドサーバー、仮想マシンなど)をセットアップするときにできる最も簡単なことは、ローカルで開発するときと同じように、`fastapi run`(Uvicornを使用します)や同様のものを手動で実行することです。
|
||||
|
||||
そしてこれは動作し、**開発中**には役に立つでしょう。
|
||||
リモートサーバー(クラウドサーバー、仮想マシンなど)をセットアップするときにできる最も簡単なことは、ローカルで開発するときと同じように、Uvicorn(または同様のもの)を手動で実行することです。 この方法は**開発中**には役に立つと思われます。
|
||||
|
||||
しかし、サーバーへの接続が切れた場合、**実行中のプロセス**はおそらくダウンしてしまうでしょう。
|
||||
|
||||
そしてサーバーが再起動された場合(アップデートやクラウドプロバイダーからのマイグレーションの後など)、おそらくあなたはそれに**気づかないでしょう**。そのため、プロセスを手動で再起動しなければならないことすら気づかないでしょう。つまり、APIはダウンしたままなのです。😱
|
||||
|
||||
### 起動時に自動的に実行 { #run-automatically-on-startup }
|
||||
### 起動時に自動的に実行
|
||||
|
||||
一般的に、サーバープログラム(Uvicornなど)はサーバー起動時に自動的に開始され、**人の介入**を必要とせずに、APIと一緒にプロセスが常に実行されるようにしたいと思われます(UvicornがFastAPIアプリを実行するなど)。
|
||||
|
||||
### 別のプログラムの用意 { #separate-program }
|
||||
### 別のプログラムの用意
|
||||
|
||||
これを実現するために、通常は**別のプログラム**を用意し、起動時にアプリケーションが実行されるようにします。そして多くの場合、他のコンポーネントやアプリケーション、例えばデータベースも実行されるようにします。
|
||||
|
||||
### 起動時に実行するツールの例 { #example-tools-to-run-at-startup }
|
||||
### 起動時に実行するツールの例
|
||||
|
||||
実行するツールの例をいくつか挙げます:
|
||||
|
||||
@@ -129,33 +127,31 @@ OSの「タスク・マネージャー」や「システム・モニター」(
|
||||
|
||||
次の章で、より具体的な例を挙げていきます。
|
||||
|
||||
## 再起動 { #restarts }
|
||||
## 再起動
|
||||
|
||||
起動時にアプリケーションが実行されることを確認するのと同様に、失敗後にアプリケーションが**再起動**されることも確認したいと思われます。
|
||||
|
||||
### 我々は間違いを犯す { #we-make-mistakes }
|
||||
### 我々は間違いを犯す
|
||||
|
||||
私たち人間は常に**間違い**を犯します。ソフトウェアには、ほとんど常に**バグ**があらゆる箇所に隠されています。🐛
|
||||
|
||||
そして私たち開発者は、それらのバグを見つけたり新しい機能を実装したりしながらコードを改善し続けます(新しいバグも追加してしまうかもしれません😅)。
|
||||
|
||||
### 小さなエラーは自動的に処理される { #small-errors-automatically-handled }
|
||||
### 小さなエラーは自動的に処理される
|
||||
|
||||
FastAPIでWeb APIを構築する際に、コードにエラーがある場合、FastAPIは通常、エラーを引き起こした単一のリクエストにエラーを含めます。🛡
|
||||
|
||||
クライアントはそのリクエストに対して**500 Internal Server Error**を受け取りますが、アプリケーションは完全にクラッシュするのではなく、次のリクエストのために動作を続けます。
|
||||
|
||||
### 重大なエラー - クラッシュ { #bigger-errors-crashes }
|
||||
### 重大なエラー - クラッシュ
|
||||
|
||||
しかしながら、**アプリケーション全体をクラッシュさせるようなコードを書いて**UvicornとPythonをクラッシュさせるようなケースもあるかもしれません。💥
|
||||
|
||||
それでも、ある箇所でエラーが発生したからといって、アプリケーションを停止させたままにしたくないでしょう。 少なくとも壊れていない*path operation*については、**実行し続けたい**はずです。
|
||||
それでも、ある箇所でエラーが発生したからといって、アプリケーションを停止させたままにしたくないでしょう。 少なくとも壊れていない*パスオペレーション*については、**実行し続けたい**はずです。
|
||||
|
||||
### クラッシュ後の再起動 { #restart-after-crash }
|
||||
### クラッシュ後の再起動
|
||||
|
||||
しかし、実行中の**プロセス**をクラッシュさせるような本当にひどいエラーの場合、少なくとも2〜3回ほどプロセスを**再起動**させる外部コンポーネントが必要でしょう。
|
||||
|
||||
/// tip | 豆知識
|
||||
/// tip
|
||||
|
||||
...とはいえ、アプリケーション全体が**すぐにクラッシュする**のであれば、いつまでも再起動し続けるのは意味がないでしょう。しかし、その場合はおそらく開発中か少なくともデプロイ直後に気づくと思われます。
|
||||
|
||||
@@ -165,7 +161,7 @@ FastAPIでWeb APIを構築する際に、コードにエラーがある場合、
|
||||
|
||||
あなたはおそらく**外部コンポーネント**がアプリケーションの再起動を担当することを望むと考えます。 なぜなら、その時点でUvicornとPythonを使った同じアプリケーションはすでにクラッシュしており、同じアプリケーションの同じコードに対して何もできないためです。
|
||||
|
||||
### 自動的に再起動するツールの例 { #example-tools-to-restart-automatically }
|
||||
### 自動的に再起動するツールの例
|
||||
|
||||
ほとんどの場合、前述した**起動時にプログラムを実行する**ために使用されるツールは、自動で**再起動**することにも利用されます。
|
||||
|
||||
@@ -180,19 +176,19 @@ FastAPIでWeb APIを構築する際に、コードにエラーがある場合、
|
||||
* クラウドプロバイダーがサービスの一部として内部的に処理
|
||||
* そのほか...
|
||||
|
||||
## レプリケーション - プロセスとメモリ { #replication-processes-and-memory }
|
||||
## レプリケーション - プロセスとメモリー
|
||||
|
||||
FastAPI アプリケーションでは、Uvicorn を実行する `fastapi` コマンドのようなサーバープログラムを使用し、**1つのプロセス**で1度に複数のクライアントに同時に対応できます。
|
||||
FastAPI アプリケーションでは、Uvicorn のようなサーバープログラムを使用し、**1つのプロセス**で1度に複数のクライアントに同時に対応できます。
|
||||
|
||||
しかし、多くの場合、複数のワーカー・プロセスを同時に実行したいと考えるでしょう。
|
||||
|
||||
### 複数のプロセス - Worker { #multiple-processes-workers }
|
||||
### 複数のプロセス - Worker
|
||||
|
||||
クライアントの数が単一のプロセスで処理できる数を超えており(たとえば仮想マシンがそれほど大きくない場合)、かつサーバーの CPU に**複数のコア**がある場合、同じアプリケーションで同時に**複数のプロセス**を実行させ、すべてのリクエストを分散させることができます。
|
||||
|
||||
同じAPIプログラムの**複数のプロセス**を実行する場合、それらは一般的に**Worker/ワーカー**と呼ばれます。
|
||||
|
||||
### ワーカー・プロセス と ポート { #worker-processes-and-ports }
|
||||
### ワーカー・プロセス と ポート
|
||||
<!-- NOTE: https.md written in Japanese does not exist, so it redirects to English one -->
|
||||
|
||||
[HTTPSについて](https.md){.internal-link target=_blank}のドキュメントで、1つのサーバーで1つのポートとIPアドレスの組み合わせでリッスンできるのは1つのプロセスだけであることを覚えていますでしょうか?
|
||||
@@ -201,13 +197,13 @@ FastAPI アプリケーションでは、Uvicorn を実行する `fastapi` コ
|
||||
|
||||
そのため、**複数のプロセス**を同時に持つには**ポートでリッスンしている単一のプロセス**が必要であり、それが何らかの方法で各ワーカー・プロセスに通信を送信することが求められます。
|
||||
|
||||
### プロセスあたりのメモリ { #memory-per-process }
|
||||
### プロセスあたりのメモリー
|
||||
|
||||
さて、プログラムがメモリにロードする際には、例えば機械学習モデルや大きなファイルの内容を変数に入れたりする場合では、**サーバーのメモリ(RAM)**を少し消費します。
|
||||
|
||||
そして複数のプロセスは通常、**メモリを共有しません**。これは、実行中の各プロセスがそれぞれ独自の変数やメモリ等を持っていることを意味します。つまり、コード内で大量のメモリを消費している場合、**各プロセス**は同等の量のメモリを消費することになります。
|
||||
|
||||
### サーバーメモリ { #server-memory }
|
||||
### サーバーメモリー
|
||||
|
||||
例えば、あなたのコードが **1GBのサイズの機械学習モデル**をロードする場合、APIで1つのプロセスを実行すると、少なくとも1GBのRAMを消費します。
|
||||
|
||||
@@ -215,7 +211,7 @@ FastAPI アプリケーションでは、Uvicorn を実行する `fastapi` コ
|
||||
|
||||
リモートサーバーや仮想マシンのRAMが3GBしかない場合、4GB以上のRAMをロードしようとすると問題が発生します。🚨
|
||||
|
||||
### 複数プロセス - 例 { #multiple-processes-an-example }
|
||||
### 複数プロセス - 例
|
||||
|
||||
この例では、2つの**ワーカー・プロセス**を起動し制御する**マネージャー・ プロセス**があります。
|
||||
|
||||
@@ -231,7 +227,7 @@ FastAPI アプリケーションでは、Uvicorn を実行する `fastapi` コ
|
||||
|
||||
毎回同程度の計算を行うAPIがあり、多くのクライアントがいるのであれば、**CPU使用率**もおそらく**安定**するでしょう(常に急激に上下するのではなく)。
|
||||
|
||||
### レプリケーション・ツールと戦略の例 { #examples-of-replication-tools-and-strategies }
|
||||
### レプリケーション・ツールと戦略の例
|
||||
|
||||
これを実現するにはいくつかのアプローチがありますが、具体的な戦略については次の章(Dockerやコンテナの章など)で詳しく説明します。
|
||||
|
||||
@@ -241,22 +237,25 @@ FastAPI アプリケーションでは、Uvicorn を実行する `fastapi` コ
|
||||
|
||||
考えられる組み合わせと戦略をいくつか紹介します:
|
||||
|
||||
* `--workers` を指定した **Uvicorn**
|
||||
* **Gunicorn**が**Uvicornワーカー**を管理
|
||||
* Gunicornは**IP**と**ポート**をリッスンする**プロセスマネージャ**で、レプリケーションは**複数のUvicornワーカー・プロセス**を持つことによって行われる。
|
||||
* **Uvicorn**が**Uvicornワーカー**を管理
|
||||
* 1つのUvicornの**プロセスマネージャー**が**IP**と**ポート**をリッスンし、**複数のUvicornワーカー・プロセス**を起動する。
|
||||
* **Kubernetes**やその他の分散**コンテナ・システム**
|
||||
* **Kubernetes**レイヤーの何かが**IP**と**ポート**をリッスンする。レプリケーションは、**複数のコンテナ**にそれぞれ**1つのUvicornプロセス**を実行させることで行われる。
|
||||
* **クラウド・サービス**によるレプリケーション
|
||||
* クラウド・サービスはおそらく**あなたのためにレプリケーションを処理**します。**実行するプロセス**や使用する**コンテナイメージ**を定義できるかもしれませんが、いずれにせよ、それはおそらく**単一のUvicornプロセス**であり、クラウドサービスはそのレプリケーションを担当するでしょう。
|
||||
|
||||
/// tip | 豆知識
|
||||
/// tip
|
||||
|
||||
これらの**コンテナ**やDockerそしてKubernetesに関する項目が、まだあまり意味をなしていなくても心配しないでください。
|
||||
<!-- NOTE: the current version of docker.md is outdated compared to English one. -->
|
||||
|
||||
コンテナ・イメージ、Docker、Kubernetesなどについては、将来の章で詳しく説明します: [コンテナ内のFastAPI - Docker](docker.md){.internal-link target=_blank}.
|
||||
コンテナ・イメージ、Docker、Kubernetesなどについては、次の章で詳しく説明します: [コンテナ内のFastAPI - Docker](docker.md){.internal-link target=_blank}.
|
||||
|
||||
///
|
||||
|
||||
## 開始前の事前のステップ { #previous-steps-before-starting }
|
||||
## 開始前の事前のステップ
|
||||
|
||||
アプリケーションを**開始する前**に、いくつかのステップを実行したい場合が多くあります。
|
||||
|
||||
@@ -272,7 +271,7 @@ FastAPI アプリケーションでは、Uvicorn を実行する `fastapi` コ
|
||||
|
||||
もちろん、事前のステップを何度も実行しても問題がない場合もあり、その際は対処がかなり楽になります。
|
||||
|
||||
/// tip | 豆知識
|
||||
/// tip
|
||||
|
||||
また、セットアップによっては、アプリケーションを開始する前の**事前のステップ**が必要ない場合もあることを覚えておいてください。
|
||||
|
||||
@@ -280,7 +279,7 @@ FastAPI アプリケーションでは、Uvicorn を実行する `fastapi` コ
|
||||
|
||||
///
|
||||
|
||||
### 事前ステップの戦略例 { #examples-of-previous-steps-strategies }
|
||||
### 事前ステップの戦略例
|
||||
|
||||
これは**システムを**デプロイする方法に**大きく依存**するだろうし、おそらくプログラムの起動方法や再起動の処理などにも関係してくるでしょう。
|
||||
|
||||
@@ -290,13 +289,14 @@ FastAPI アプリケーションでは、Uvicorn を実行する `fastapi` コ
|
||||
* 事前のステップを実行し、アプリケーションを起動するbashスクリプト
|
||||
* 利用するbashスクリプトを起動/再起動したり、エラーを検出したりする方法は以前として必要になるでしょう。
|
||||
|
||||
/// tip | 豆知識
|
||||
/// tip
|
||||
|
||||
コンテナを使った具体的な例については、将来の章で紹介します: [コンテナ内のFastAPI - Docker](docker.md){.internal-link target=_blank}.
|
||||
<!-- NOTE: the current version of docker.md is outdated compared to English one. -->
|
||||
コンテナを使った具体的な例については、次の章で紹介します: [コンテナ内のFastAPI - Docker](docker.md){.internal-link target=_blank}.
|
||||
|
||||
///
|
||||
|
||||
## リソースの利用 { #resource-utilization }
|
||||
## リソースの利用
|
||||
|
||||
あなたのサーバーは**リソース**であり、プログラムを実行しCPUの計算時間や利用可能なRAMメモリを消費または**利用**することができます。
|
||||
|
||||
@@ -319,7 +319,7 @@ FastAPI アプリケーションでは、Uvicorn を実行する `fastapi` コ
|
||||
|
||||
`htop`のような単純なツールを使って、サーバーで使用されているCPUやRAM、あるいは各プロセスで使用されている量を見ることができます。あるいは、より複雑な監視ツールを使って、サーバに分散して使用することもできます。
|
||||
|
||||
## まとめ { #recap }
|
||||
## まとめ
|
||||
|
||||
アプリケーションのデプロイ方法を決定する際に、考慮すべきであろう主要なコンセプトのいくつかを紹介していきました:
|
||||
|
||||
@@ -327,7 +327,7 @@ FastAPI アプリケーションでは、Uvicorn を実行する `fastapi` コ
|
||||
* 起動時の実行
|
||||
* 再起動
|
||||
* レプリケーション(実行中のプロセス数)
|
||||
* メモリ
|
||||
* メモリー
|
||||
* 開始前の事前ステップ
|
||||
|
||||
これらの考え方とその適用方法を理解することで、デプロイメントを設定したり調整したりする際に必要な直感的な判断ができるようになるはずです。🤓
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
# コンテナ内のFastAPI - Docker { #fastapi-in-containers-docker }
|
||||
# コンテナ内のFastAPI - Docker
|
||||
|
||||
FastAPIアプリケーションをデプロイする場合、一般的なアプローチは**Linuxコンテナ・イメージ**をビルドすることです。基本的には <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a>を用いて行われます。生成されたコンテナ・イメージは、いくつかの方法のいずれかでデプロイできます。
|
||||
FastAPIアプリケーションをデプロイする場合、一般的なアプローチは**Linuxコンテナ・イメージ**をビルドすることです。
|
||||
|
||||
基本的には <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a>を用いて行われます。生成されたコンテナ・イメージは、いくつかの方法のいずれかでデプロイできます。
|
||||
|
||||
Linuxコンテナの使用には、**セキュリティ**、**反復可能性(レプリカビリティ)**、**シンプリシティ**など、いくつかの利点があります。
|
||||
|
||||
/// tip | 豆知識
|
||||
/// tip
|
||||
|
||||
TODO: なぜか遷移できない
|
||||
お急ぎで、すでにこれらの情報をご存じですか? [以下の`Dockerfile`の箇所👇](#build-a-docker-image-for-fastapi)へジャンプしてください。
|
||||
|
||||
///
|
||||
|
||||
<details>
|
||||
<summary>Dockerfile Preview 👀</summary>
|
||||
<summary>Dockerfile プレビュー 👀</summary>
|
||||
|
||||
```Dockerfile
|
||||
FROM python:3.9
|
||||
@@ -24,15 +27,15 @@ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
COPY ./app /code/app
|
||||
|
||||
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
|
||||
# If running behind a proxy like Nginx or Traefik add --proxy-headers
|
||||
# CMD ["fastapi", "run", "app/main.py", "--port", "80", "--proxy-headers"]
|
||||
# CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--proxy-headers"]
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## コンテナとは何か { #what-is-a-container }
|
||||
## コンテナとは何か
|
||||
|
||||
コンテナ(主にLinuxコンテナ)は、同じシステム内の他のコンテナ(他のアプリケーションやコンポーネント)から隔離された状態を保ちながら、すべての依存関係や必要なファイルを含むアプリケーションをパッケージ化する非常に**軽量**な方法です。
|
||||
|
||||
@@ -42,7 +45,7 @@ Linuxコンテナは、ホスト(マシン、仮想マシン、クラウドサ
|
||||
|
||||
コンテナはまた、独自の**分離された**実行プロセス(通常は1つのプロセスのみ)や、ファイルシステム、ネットワークを持ちます。 このことはデプロイ、セキュリティ、開発などを簡素化させます。
|
||||
|
||||
## コンテナ・イメージとは何か { #what-is-a-container-image }
|
||||
## コンテナ・イメージとは何か
|
||||
|
||||
**コンテナ**は、**コンテナ・イメージ**から実行されます。
|
||||
|
||||
@@ -50,17 +53,23 @@ Linuxコンテナは、ホスト(マシン、仮想マシン、クラウドサ
|
||||
|
||||
保存された静的コンテンツである「**コンテナイメージ**」とは対照的に、「**コンテナ**」は通常、実行中のインスタンス、つまり**実行**されているものを指します。
|
||||
|
||||
**コンテナ**が起動され実行されるとき(**コンテナイメージ**から起動されるとき)、ファイルや環境変数などが作成されたり変更されたりする可能性があります。これらの変更はそのコンテナ内にのみ存在しますが、基盤となるコンテナ・イメージには残りません(ディスクに保存されません)。
|
||||
**コンテナ**が起動され実行されるとき(**コンテナイメージ**から起動されるとき)、ファイルや環境変数などが作成されたり変更されたりする可能性があります。
|
||||
|
||||
これらの変更はそのコンテナ内にのみ存在しますが、基盤となるコンテナ・イメージには残りません(ディスクに保存されません)。
|
||||
|
||||
コンテナイメージは **プログラム** ファイルやその内容、例えば `python` と `main.py` ファイルに匹敵します。
|
||||
|
||||
そして、**コンテナ**自体は(**コンテナイメージ**とは対照的に)イメージをもとにした実際の実行中のインスタンスであり、**プロセス**に匹敵します。実際、コンテナが実行されているのは、**プロセスが実行されている**ときだけです(通常は単一のプロセスだけです)。 コンテナ内で実行中のプロセスがない場合、コンテナは停止します。
|
||||
そして、**コンテナ**自体は(**コンテナイメージ**とは対照的に)イメージをもとにした実際の実行中のインスタンスであり、**プロセス**に匹敵します。
|
||||
|
||||
## コンテナ・イメージ { #container-images }
|
||||
実際、コンテナが実行されているのは、**プロセスが実行されている**ときだけです(通常は単一のプロセスだけです)。 コンテナ内で実行中のプロセスがない場合、コンテナは停止します。
|
||||
|
||||
## コンテナ・イメージ
|
||||
|
||||
Dockerは、**コンテナ・イメージ**と**コンテナ**を作成・管理するための主要なツールの1つです。
|
||||
|
||||
そして、多くのツールや環境、データベース、アプリケーションに対応している予め作成された**公式のコンテナ・イメージ**をパブリックに提供している<a href="https://hub.docker.com/" class="external-link" target="_blank">Docker Hub</a>というものがあります。
|
||||
そして、DockerにはDockerイメージ(コンテナ)を共有する<a href="https://hub.docker.com/" class="external-link" target="_blank">Docker Hub</a>というものがあります。
|
||||
|
||||
Docker Hubは 多くのツールや環境、データベース、アプリケーションに対応している予め作成された**公式のコンテナ・イメージ**をパブリックに提供しています。
|
||||
|
||||
例えば、公式イメージの1つに<a href="https://hub.docker.com/_/python" class="external-link" target="_blank">Python Image</a>があります。
|
||||
|
||||
@@ -79,7 +88,7 @@ Dockerは、**コンテナ・イメージ**と**コンテナ**を作成・管理
|
||||
|
||||
すべてのコンテナ管理システム(DockerやKubernetesなど)には、こうしたネットワーキング機能が統合されています。
|
||||
|
||||
## コンテナとプロセス { #containers-and-processes }
|
||||
## コンテナとプロセス
|
||||
|
||||
通常、**コンテナ・イメージ**はそのメタデータに**コンテナ**の起動時に実行されるデフォルトのプログラムまたはコマンドと、そのプログラムに渡されるパラメータを含みます。コマンドラインでの操作とよく似ています。
|
||||
|
||||
@@ -91,7 +100,7 @@ Dockerは、**コンテナ・イメージ**と**コンテナ**を作成・管理
|
||||
|
||||
しかし、**少なくとも1つの実行中のプロセス**がなければ、実行中のコンテナを持つことはできないです。メイン・プロセスが停止すれば、コンテナも停止します。
|
||||
|
||||
## FastAPI用のDockerイメージをビルドする { #build-a-docker-image-for-fastapi }
|
||||
## Build a Docker Image for FastAPI
|
||||
|
||||
ということで、何か作りましょう!🚀
|
||||
|
||||
@@ -103,7 +112,7 @@ FastAPI用の**Dockerイメージ**を、**公式Python**イメージに基づ
|
||||
* **Raspberry Pi**で実行する場合
|
||||
* コンテナ・イメージを実行してくれるクラウド・サービスなどを利用する場合
|
||||
|
||||
### パッケージ要件 { #package-requirements }
|
||||
### パッケージ要件(package requirements)
|
||||
|
||||
アプリケーションの**パッケージ要件**は通常、何らかのファイルに記述されているはずです。
|
||||
|
||||
@@ -116,8 +125,9 @@ FastAPI用の**Dockerイメージ**を、**公式Python**イメージに基づ
|
||||
例えば、`requirements.txt` は次のようになります:
|
||||
|
||||
```
|
||||
fastapi[standard]>=0.113.0,<0.114.0
|
||||
pydantic>=2.7.0,<3.0.0
|
||||
fastapi>=0.68.0,<0.69.0
|
||||
pydantic>=1.8.0,<2.0.0
|
||||
uvicorn>=0.15.0,<0.16.0
|
||||
```
|
||||
|
||||
そして通常、例えば `pip` を使ってこれらのパッケージの依存関係をインストールします:
|
||||
@@ -127,24 +137,28 @@ pydantic>=2.7.0,<3.0.0
|
||||
```console
|
||||
$ pip install -r requirements.txt
|
||||
---> 100%
|
||||
Successfully installed fastapi pydantic
|
||||
Successfully installed fastapi pydantic uvicorn
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
/// info | 情報
|
||||
/// info
|
||||
|
||||
パッケージの依存関係を定義しインストールするためのフォーマットやツールは他にもあります。
|
||||
|
||||
Poetryを使った例は、後述するセクションでご紹介します。👇
|
||||
|
||||
///
|
||||
|
||||
### **FastAPI**コードを作成する { #create-the-fastapi-code }
|
||||
### **FastAPI**コードを作成する
|
||||
|
||||
* `app` ディレクトリを作成し、その中に入ります。
|
||||
* 空のファイル `__init__.py` を作成します。
|
||||
* 次の内容で `main.py` ファイルを作成します:
|
||||
* `app` ディレクトリを作成し、その中に入ります
|
||||
* 空のファイル `__init__.py` を作成します
|
||||
* `main.py` ファイルを作成します:
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -156,32 +170,32 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
### Dockerfile { #dockerfile }
|
||||
### Dockerfile
|
||||
|
||||
同じプロジェクト・ディレクトリに`Dockerfile`というファイルを作成します:
|
||||
|
||||
```{ .dockerfile .annotate }
|
||||
# (1)!
|
||||
# (1)
|
||||
FROM python:3.9
|
||||
|
||||
# (2)!
|
||||
# (2)
|
||||
WORKDIR /code
|
||||
|
||||
# (3)!
|
||||
# (3)
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
|
||||
# (4)!
|
||||
# (4)
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
# (5)!
|
||||
# (5)
|
||||
COPY ./app /code/app
|
||||
|
||||
# (6)!
|
||||
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
|
||||
# (6)
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
```
|
||||
|
||||
1. 公式のPythonベースイメージから始めます
|
||||
@@ -197,10 +211,9 @@ CMD ["fastapi", "run", "app/main.py", "--port", "80"]
|
||||
このファイルは**頻繁には変更されない**ので、Dockerはこのステップではそれを検知し**キャッシュ**を使用し、次のステップでもキャッシュを有効にします。
|
||||
|
||||
4. 要件ファイルにあるパッケージの依存関係をインストールします
|
||||
|
||||
`--no-cache-dir` オプションはダウンロードしたパッケージをローカルに保存しないように `pip` に指示します。これは、同じパッケージをインストールするために `pip` を再度実行する場合にのみ有効ですが、コンテナで作業する場合はそうではないです。
|
||||
|
||||
/// note | 備考
|
||||
/// note
|
||||
|
||||
`--no-cache-dir`は`pip`に関連しているだけで、Dockerやコンテナとは何の関係もないです。
|
||||
|
||||
@@ -212,56 +225,26 @@ CMD ["fastapi", "run", "app/main.py", "--port", "80"]
|
||||
|
||||
このステップでキャッシュを使用すると、開発中にイメージを何度もビルドする際に、**毎回**すべての依存関係を**ダウンロードしてインストールする**代わりに多くの**時間**を**節約**できます。
|
||||
|
||||
5. `./app` ディレクトリを `/code` ディレクトリの中にコピーする。
|
||||
5. ./app` ディレクトリを `/code` ディレクトリの中にコピーする。
|
||||
|
||||
これには**最も頻繁に変更される**すべてのコードが含まれているため、Dockerの**キャッシュ**は**これ以降のステップ**に簡単に使用されることはありません。
|
||||
|
||||
そのため、コンテナイメージのビルド時間を最適化するために、`Dockerfile`の **最後** にこれを置くことが重要です。
|
||||
|
||||
6. 内部でUvicornを使用する `fastapi run` を使うための**コマンド**を設定します
|
||||
6. `uvicorn`サーバーを実行するための**コマンド**を設定します
|
||||
|
||||
`CMD` は文字列のリストを取り、それぞれの文字列はスペースで区切られたコマンドラインに入力するものです。
|
||||
|
||||
このコマンドは **現在の作業ディレクトリ**から実行され、上記の `WORKDIR /code` にて設定した `/code` ディレクトリと同じです。
|
||||
|
||||
/// tip | 豆知識
|
||||
そのためプログラムは `/code` で開始しその中にあなたのコードがある `./app` ディレクトリがあるので、**Uvicorn** は `app.main` から `app` を参照し、**インポート** することができます。
|
||||
|
||||
コード内の各番号バブルをクリックして、各行が何をするのかをレビューしてください。👆
|
||||
/// tip
|
||||
|
||||
コード内の"+"の吹き出しをクリックして、各行が何をするのかをレビューしてください。👆
|
||||
|
||||
///
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
以下で説明する通り、`CMD` 命令は**常に** **exec形式**を使用してください。
|
||||
|
||||
///
|
||||
|
||||
#### `CMD` を使う - Exec形式 { #use-cmd-exec-form }
|
||||
|
||||
Docker命令 <a href="https://docs.docker.com/reference/dockerfile/#cmd" class="external-link" target="_blank">`CMD`</a> は2つの形式で書けます:
|
||||
|
||||
✅ **Exec** 形式:
|
||||
|
||||
```Dockerfile
|
||||
# ✅ Do this
|
||||
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
|
||||
```
|
||||
|
||||
⛔️ **Shell** 形式:
|
||||
|
||||
```Dockerfile
|
||||
# ⛔️ Don't do this
|
||||
CMD fastapi run app/main.py --port 80
|
||||
```
|
||||
|
||||
FastAPIが正常にシャットダウンでき、[lifespan events](../advanced/events.md){.internal-link target=_blank}がトリガーされるように、常に **exec** 形式を使用してください。
|
||||
|
||||
詳しくは、<a href="https://docs.docker.com/reference/dockerfile/#shell-and-exec-form" class="external-link" target="_blank">shell形式とexec形式に関するDockerドキュメント</a>をご覧ください。
|
||||
|
||||
これは `docker compose` を使用する場合にかなり目立つことがあります。より技術的な詳細は、このDocker ComposeのFAQセクションをご覧ください:<a href="https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop" class="external-link" target="_blank">Why do my services take 10 seconds to recreate or stop?</a>。
|
||||
|
||||
#### ディレクトリ構造 { #directory-structure }
|
||||
|
||||
これで、次のようなディレクトリ構造になるはずです:
|
||||
|
||||
```
|
||||
@@ -273,15 +256,17 @@ FastAPIが正常にシャットダウンでき、[lifespan events](../advanced/e
|
||||
└── requirements.txt
|
||||
```
|
||||
|
||||
#### TLS Termination Proxyの裏側 { #behind-a-tls-termination-proxy }
|
||||
#### TLS Termination Proxyの裏側
|
||||
|
||||
Nginx や Traefik のような TLS Termination Proxy (ロードバランサ) の後ろでコンテナを動かしている場合は、`--proxy-headers`オプションを追加します。これにより、(FastAPI CLI経由で)Uvicornに対して、そのプロキシから送信されるヘッダを信頼し、アプリケーションがHTTPSの裏で実行されていることなどを示すよう指示します。
|
||||
Nginx や Traefik のような TLS Termination Proxy (ロードバランサ) の後ろでコンテナを動かしている場合は、`--proxy-headers`オプションを追加します。
|
||||
|
||||
このオプションは、Uvicornにプロキシ経由でHTTPSで動作しているアプリケーションに対して、送信されるヘッダを信頼するよう指示します。
|
||||
|
||||
```Dockerfile
|
||||
CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"]
|
||||
CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
|
||||
```
|
||||
|
||||
#### Dockerキャッシュ { #docker-cache }
|
||||
#### Dockerキャッシュ
|
||||
|
||||
この`Dockerfile`には重要なトリックがあり、まず**依存関係だけのファイル**をコピーします。その理由を説明します。
|
||||
|
||||
@@ -315,11 +300,11 @@ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
COPY ./app /code/app
|
||||
```
|
||||
|
||||
### Dockerイメージをビルドする { #build-the-docker-image }
|
||||
### Dockerイメージをビルドする
|
||||
|
||||
すべてのファイルが揃ったので、コンテナ・イメージをビルドしましょう。
|
||||
|
||||
* プロジェクトディレクトリに移動します(`Dockerfile`がある場所で、`app`ディレクトリがあります)。
|
||||
* プロジェクトディレクトリに移動します(`Dockerfile`がある場所で、`app`ディレクトリがあります)
|
||||
* FastAPI イメージをビルドします:
|
||||
|
||||
<div class="termy">
|
||||
@@ -332,7 +317,7 @@ $ docker build -t myimage .
|
||||
|
||||
</div>
|
||||
|
||||
/// tip | 豆知識
|
||||
/// tip
|
||||
|
||||
末尾の `.` に注目してほしいです。これは `./` と同じ意味です。 これはDockerにコンテナイメージのビルドに使用するディレクトリを指示します。
|
||||
|
||||
@@ -340,7 +325,7 @@ $ docker build -t myimage .
|
||||
|
||||
///
|
||||
|
||||
### Dockerコンテナの起動する { #start-the-docker-container }
|
||||
### Dockerコンテナの起動する
|
||||
|
||||
* イメージに基づいてコンテナを実行します:
|
||||
|
||||
@@ -352,7 +337,7 @@ $ docker run -d --name mycontainer -p 80:80 myimage
|
||||
|
||||
</div>
|
||||
|
||||
## 確認する { #check-it }
|
||||
## 確認する
|
||||
|
||||
Dockerコンテナの<a href="http://192.168.99.100/items/5?q=somequery" class="external-link" target="_blank">http://192.168.99.100/items/5?q=somequery</a> や <a href="http://127.0.0.1/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1/items/5?q=somequery</a> (またはそれに相当するDockerホストを使用したもの)といったURLで確認できるはずです。
|
||||
|
||||
@@ -362,7 +347,7 @@ Dockerコンテナの<a href="http://192.168.99.100/items/5?q=somequery" class="
|
||||
{"item_id": 5, "q": "somequery"}
|
||||
```
|
||||
|
||||
## インタラクティブなAPIドキュメント { #interactive-api-docs }
|
||||
## インタラクティブなAPIドキュメント
|
||||
|
||||
これらのURLにもアクセスできます: <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> や <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a> (またはそれに相当するDockerホストを使用したもの)
|
||||
|
||||
@@ -370,7 +355,7 @@ Dockerコンテナの<a href="http://192.168.99.100/items/5?q=somequery" class="
|
||||
|
||||

|
||||
|
||||
## 代替のAPIドキュメント { #alternative-api-docs }
|
||||
## 代替のAPIドキュメント
|
||||
|
||||
また、<a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> や <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a> (またはそれに相当するDockerホストを使用したもの)にもアクセスできます。
|
||||
|
||||
@@ -378,10 +363,9 @@ Dockerコンテナの<a href="http://192.168.99.100/items/5?q=somequery" class="
|
||||
|
||||

|
||||
|
||||
## 単一ファイルのFastAPIでDockerイメージをビルドする { #build-a-docker-image-with-a-single-file-fastapi }
|
||||
## 単一ファイルのFastAPIでDockerイメージをビルドする
|
||||
|
||||
FastAPI が単一のファイル、例えば `./app` ディレクトリのない `main.py` の場合、ファイル構造は次のようになります:
|
||||
|
||||
```
|
||||
.
|
||||
├── Dockerfile
|
||||
@@ -400,43 +384,43 @@ COPY ./requirements.txt /code/requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
# (1)!
|
||||
# (1)
|
||||
COPY ./main.py /code/
|
||||
|
||||
# (2)!
|
||||
CMD ["fastapi", "run", "main.py", "--port", "80"]
|
||||
# (2)
|
||||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
```
|
||||
|
||||
1. `main.py`ファイルを `/code` ディレクトリに直接コピーします(`./app` ディレクトリなし)。
|
||||
1. main.py`ファイルを `/code` ディレクトリに直接コピーします。
|
||||
|
||||
2. 単一ファイル `main.py` 内のアプリケーションを配信するために `fastapi run` を使用します。
|
||||
2. Uvicornを実行し、`main`から`app`オブジェクトをインポートするように指示します(`app.main`からインポートするのではなく)。
|
||||
|
||||
`fastapi run` にファイルを渡すと、それがパッケージの一部ではなく単一ファイルであることを自動的に検出し、インポートしてFastAPIアプリを配信する方法を判断します。😎
|
||||
次にUvicornコマンドを調整して、`app.main` の代わりに新しいモジュール `main` を使用し、FastAPIオブジェクトである `app` をインポートします。
|
||||
|
||||
## デプロイメントのコンセプト { #deployment-concepts }
|
||||
## デプロイメントのコンセプト
|
||||
|
||||
コンテナという観点から、[デプロイのコンセプト](concepts.md){.internal-link target=_blank}に共通するいくつかについて、もう一度説明しましょう。
|
||||
|
||||
コンテナは主に、アプリケーションの**ビルドとデプロイ**のプロセスを簡素化するためのツールですが、これらの**デプロイのコンセプト**を扱うための特定のアプローチを強制するものではなく、いくつかの戦略があります。
|
||||
コンテナは主に、アプリケーションの**ビルドとデプロイ**のプロセスを簡素化するためのツールですが、これらの**デプロイのコンセプト**を扱うための特定のアプローチを強制するものではないです。
|
||||
|
||||
**良いニュース**は、それぞれの異なる戦略には、すべてのデプロイメントのコンセプトをカバーする方法があるということです。🎉
|
||||
|
||||
これらの**デプロイメントのコンセプト**をコンテナの観点から見直してみましょう:
|
||||
|
||||
* HTTPS
|
||||
* セキュリティ - HTTPS
|
||||
* 起動時の実行
|
||||
* 再起動
|
||||
* レプリケーション(実行中のプロセス数)
|
||||
* **レプリケーション(実行中のプロセス数)**
|
||||
* メモリ
|
||||
* 開始前の事前ステップ
|
||||
|
||||
## HTTPS { #https }
|
||||
## HTTPS
|
||||
|
||||
FastAPI アプリケーションの **コンテナ・イメージ**(および後で実行中の **コンテナ**)だけに焦点を当てると、通常、HTTPSは別のツールを用いて**外部で**処理されます。
|
||||
|
||||
例えば<a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a>のように、**HTTPS**と**証明書**の**自動**取得を扱う別のコンテナである可能性もあります。
|
||||
|
||||
/// tip | 豆知識
|
||||
/// tip
|
||||
|
||||
TraefikはDockerやKubernetesなどと統合されているので、コンテナ用のHTTPSの設定や構成はとても簡単です。
|
||||
|
||||
@@ -444,7 +428,7 @@ TraefikはDockerやKubernetesなどと統合されているので、コンテナ
|
||||
|
||||
あるいは、(コンテナ内でアプリケーションを実行しながら)クラウド・プロバイダーがサービスの1つとしてHTTPSを処理することもできます。
|
||||
|
||||
## 起動時および再起動時の実行 { #running-on-startup-and-restarts }
|
||||
## 起動時および再起動時の実行
|
||||
|
||||
通常、コンテナの**起動と実行**を担当する別のツールがあります。
|
||||
|
||||
@@ -454,21 +438,21 @@ TraefikはDockerやKubernetesなどと統合されているので、コンテナ
|
||||
|
||||
コンテナを使わなければ、アプリケーションを起動時や再起動時に実行させるのは面倒で難しいかもしれません。しかし、**コンテナ**で作業する場合、ほとんどのケースでその機能はデフォルトで含まれています。✨
|
||||
|
||||
## レプリケーション - プロセス数 { #replication-number-of-processes }
|
||||
## レプリケーション - プロセス数
|
||||
|
||||
**Kubernetes** や Docker Swarm モード、Nomad、あるいは複数のマシン上で分散コンテナを管理するための同様の複雑なシステムを使ってマシンの<abbr title="A group of machines that are configured to be connected and work together in some way. - ある方法で接続され、連携して動作するように構成されたマシンの集まり">cluster</abbr>を構成している場合、 各コンテナで(Workerを持つUvicornのような)**プロセスマネージャ**を使用する代わりに、**クラスター・レベル**で**レプリケーション**を処理したいと思うでしょう。
|
||||
**Kubernetes** や Docker Swarm モード、Nomad、あるいは複数のマシン上で分散コンテナを管理するための同様の複雑なシステムを使ってマシンの<abbr title="何らかの方法で接続され、一緒に動作するように構成されたマシンのグループ">クラスター</abbr>を構成している場合、 各コンテナで(Workerを持つGunicornのような)**プロセスマネージャ**を使用する代わりに、**クラスター・レベル**で**レプリケーション**を処理したいと思うでしょう。
|
||||
|
||||
Kubernetesのような分散コンテナ管理システムの1つは通常、入ってくるリクエストの**ロードバランシング**をサポートしながら、**コンテナのレプリケーション**を処理する統合された方法を持っています。このことはすべて**クラスタレベル**にてです。
|
||||
|
||||
そのような場合、[上記の説明](#dockerfile)のように**Dockerイメージをゼロから**ビルドし、依存関係をインストールして、**単一のUvicornプロセス**を実行したいでしょう。複数のUvicornワーカーを使う代わりにです。
|
||||
そのような場合、UvicornワーカーでGunicornのようなものを実行するのではなく、[上記の説明](#dockerfile)のように**Dockerイメージをゼロから**ビルドし、依存関係をインストールして、**単一のUvicornプロセス**を実行したいでしょう。
|
||||
|
||||
### ロードバランサー { #load-balancer }
|
||||
### ロードバランサー
|
||||
|
||||
コンテナを使用する場合、通常はメイン・ポート**でリスニング**しているコンポーネントがあるはずです。それはおそらく、**HTTPS**を処理するための**TLS Termination Proxy**でもある別のコンテナであったり、同様のツールであったりするでしょう。
|
||||
|
||||
このコンポーネントはリクエストの **負荷** を受け、 (うまくいけば) その負荷を**バランスよく** ワーカーに分配するので、一般に **ロードバランサ** とも呼ばれます。
|
||||
|
||||
/// tip | 豆知識
|
||||
/// tip
|
||||
|
||||
HTTPSに使われるものと同じ**TLS Termination Proxy**コンポーネントは、おそらく**ロードバランサー**にもなるでしょう。
|
||||
|
||||
@@ -476,7 +460,7 @@ HTTPSに使われるものと同じ**TLS Termination Proxy**コンポーネン
|
||||
|
||||
そしてコンテナで作業する場合、コンテナの起動と管理に使用する同じシステムには、**ロードバランサー**(**TLS Termination Proxy**の可能性もある)から**ネットワーク通信**(HTTPリクエストなど)をアプリのあるコンテナ(複数可)に送信するための内部ツールが既にあるはずです。
|
||||
|
||||
### 1つのロードバランサー - 複数のワーカーコンテナー { #one-load-balancer-multiple-worker-containers }
|
||||
### 1つのロードバランサー - 複数のワーカーコンテナー
|
||||
|
||||
**Kubernetes**や同様の分散コンテナ管理システムで作業する場合、その内部のネットワーキングのメカニズムを使用することで、メインの**ポート**でリッスンしている単一の**ロードバランサー**が、アプリを実行している可能性のある**複数のコンテナ**に通信(リクエスト)を送信できるようになります。
|
||||
|
||||
@@ -486,61 +470,56 @@ HTTPSに使われるものと同じ**TLS Termination Proxy**コンポーネン
|
||||
|
||||
そして通常、この**ロードバランサー**は、クラスタ内の*他の*アプリケーション(例えば、異なるドメインや異なるURLパスのプレフィックスの配下)へのリクエストを処理することができ、その通信をクラスタ内で実行されている*他の*アプリケーションのための適切なコンテナに送信します。
|
||||
|
||||
### 1コンテナにつき1プロセス { #one-process-per-container }
|
||||
### 1コンテナにつき1プロセス
|
||||
|
||||
この種のシナリオでは、すでにクラスタ・レベルでレプリケーションを処理しているため、おそらくコンテナごとに**単一の(Uvicorn)プロセス**を持ちたいでしょう。
|
||||
|
||||
この場合、例えばコマンドラインオプションの `--workers` で、コンテナ内に複数のワーカーを持つことは**避けたい**でしょう。**コンテナごとにUvicornのプロセスは1つだけ**にしたいでしょう(おそらく複数のコンテナが必要でしょう)。
|
||||
この場合、Uvicornワーカーを持つGunicornのようなプロセスマネージャーや、Uvicornワーカーを使うUvicornは**避けたい**でしょう。**コンテナごとにUvicornのプロセスは1つだけ**にしたいでしょう(おそらく複数のコンテナが必要でしょう)。
|
||||
|
||||
(複数のワーカーの場合のように)コンテナ内に別のプロセスマネージャーを持つことは、クラスターシステムですでに対処しているであろう**不要な複雑さ**を追加するだけです。
|
||||
(GunicornやUvicornがUvicornワーカーを管理するように)コンテナ内に別のプロセスマネージャーを持つことは、クラスターシステムですでに対処しているであろう**不要な複雑さ**を追加するだけです。
|
||||
|
||||
### 複数プロセスのコンテナと特殊なケース { #containers-with-multiple-processes-and-special-cases }
|
||||
### Containers with Multiple Processes and Special Cases
|
||||
|
||||
もちろん、**特殊なケース**として、**コンテナ**内で複数の**Uvicornワーカープロセス**を起動させたい場合があります。
|
||||
もちろん、**特殊なケース**として、**Gunicornプロセスマネージャ**を持つ**コンテナ**内で複数の**Uvicornワーカープロセス**を起動させたい場合があります。
|
||||
|
||||
そのような場合、`--workers` コマンドラインオプションを使って、実行したいワーカー数を設定できます:
|
||||
|
||||
```{ .dockerfile .annotate }
|
||||
FROM python:3.9
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
COPY ./app /code/app
|
||||
|
||||
# (1)!
|
||||
CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"]
|
||||
```
|
||||
|
||||
1. ここでは `--workers` コマンドラインオプションを使って、ワーカー数を4に設定しています。
|
||||
このような場合、**公式のDockerイメージ**を使用することができます。このイメージには、複数の**Uvicornワーカープロセス**を実行するプロセスマネージャとして**Gunicorn**が含まれており、現在のCPUコアに基づいてワーカーの数を自動的に調整するためのデフォルト設定がいくつか含まれています。詳しくは後述の[Gunicornによる公式Dockerイメージ - Uvicorn](#gunicorndocker-uvicorn)で説明します。
|
||||
|
||||
以下は、それが理にかなっている場合の例です:
|
||||
|
||||
#### シンプルなアプリ { #a-simple-app }
|
||||
#### シンプルなアプリケーション
|
||||
|
||||
アプリケーションが、クラスタではなく**単一サーバ**で実行できるほど**シンプル**である場合、コンテナ内にプロセスマネージャが欲しくなることがあります。
|
||||
アプリケーションを**シンプル**な形で実行する場合、プロセス数の細かい調整が必要ない場合、自動化されたデフォルトを使用するだけで、コンテナ内にプロセスマネージャが必要かもしれません。例えば、公式Dockerイメージでシンプルな設定が可能です。
|
||||
|
||||
#### Docker Compose { #docker-compose }
|
||||
#### Docker Compose
|
||||
|
||||
Docker Composeで**単一サーバ**(クラスタではない)にデプロイすることもできますので、共有ネットワークと**ロードバランシング**を維持しながら(Docker Composeで)コンテナのレプリケーションを管理する簡単な方法はないでしょう。
|
||||
Docker Composeで**シングルサーバ**(クラスタではない)にデプロイすることもできますので、共有ネットワークと**ロードバランシング**を維持しながら(Docker Composeで)コンテナのレプリケーションを管理する簡単な方法はないでしょう。
|
||||
|
||||
その場合、**単一のコンテナ**で、**プロセスマネージャ**が内部で**複数のワーカープロセス**を起動するようにします。
|
||||
|
||||
#### Prometheusとその他の理由
|
||||
|
||||
また、**1つのコンテナ**に**1つのプロセス**を持たせるのではなく、**1つのコンテナ**に**複数のプロセス**を持たせる方が簡単だという**他の理由**もあるでしょう。
|
||||
|
||||
例えば、(セットアップにもよりますが)Prometheusエクスポーターのようなツールを同じコンテナ内に持つことができます。
|
||||
|
||||
この場合、**複数のコンテナ**があると、デフォルトでは、Prometheusが**メトリクスを**読みに来たとき、すべてのレプリケートされたコンテナの**蓄積されたメトリクス**を取得するのではなく、毎回**単一のコンテナ**(その特定のリクエストを処理したコンテナ)のものを取得することになります。
|
||||
|
||||
その場合、**複数のプロセス**を持つ**1つのコンテナ**を用意し、同じコンテナ上のローカルツール(例えばPrometheusエクスポーター)がすべての内部プロセスのPrometheusメトリクスを収集し、その1つのコンテナ上でそれらのメトリクスを公開する方がシンプルかもしれません。
|
||||
|
||||
---
|
||||
|
||||
重要なのは、これらのどれも、盲目的に従わなければならない「**絶対的なルール**」ではないということです。これらのアイデアは、**あなた自身のユースケース**を評価し、あなたのシステムに最適なアプローチを決定するために使用できます。次の概念をどう管理するかを確認してください:
|
||||
重要なのは、盲目的に従わなければならない普遍のルールはないということです。
|
||||
|
||||
これらのアイデアは、**あなた自身のユースケース**を評価し、あなたのシステムに最適なアプローチを決定するために使用することができます:
|
||||
|
||||
* セキュリティ - HTTPS
|
||||
* 起動時の実行
|
||||
* 再起動
|
||||
* レプリケーション(実行中のプロセス数)
|
||||
* **レプリケーション(実行中のプロセス数)**
|
||||
* メモリ
|
||||
* 開始前の事前ステップ
|
||||
|
||||
## メモリ { #memory }
|
||||
## メモリー
|
||||
|
||||
コンテナごとに**単一のプロセスを実行する**と、それらのコンテナ(レプリケートされている場合は1つ以上)によって消費される多かれ少なかれ明確に定義された、安定し制限された量のメモリを持つことになります。
|
||||
|
||||
@@ -552,47 +531,109 @@ Docker Composeで**単一サーバ**(クラスタではない)にデプロ
|
||||
|
||||
しかし、**多くのメモリを使用**している場合(たとえば**機械学習**モデルなど)、どれだけのメモリを消費しているかを確認し、**各マシンで実行するコンテナの数**を調整する必要があります(そしておそらくクラスタにマシンを追加します)。
|
||||
|
||||
**コンテナごとに複数のプロセス**を実行する場合、起動するプロセスの数が**利用可能なメモリ以上に消費しない**ようにする必要があります。
|
||||
**コンテナごとに複数のプロセス**を実行する場合(たとえば公式のDockerイメージで)、起動するプロセスの数が**利用可能なメモリ以上に消費しない**ようにする必要があります。
|
||||
|
||||
## 開始前の事前ステップとコンテナ { #previous-steps-before-starting-and-containers }
|
||||
## 開始前の事前ステップとコンテナ
|
||||
|
||||
コンテナ(DockerやKubernetesなど)を使っている場合、主に2つのアプローチがあります。
|
||||
|
||||
### 複数のコンテナ { #multiple-containers }
|
||||
### 複数のコンテナ
|
||||
|
||||
複数の**コンテナ**があり、おそらくそれぞれが**単一のプロセス**を実行している場合(例えば、**Kubernetes**クラスタなど)、レプリケートされたワーカーコンテナを実行する**前に**、単一のコンテナで**事前のステップ**の作業を行う**別のコンテナ**を持ちたいと思うでしょう。
|
||||
複数の**コンテナ**があり、おそらくそれぞれが**単一のプロセス**を実行している場合(**Kubernetes**クラスタなど)、レプリケートされたワーカーコンテナを実行する**前に**、単一のコンテナで**事前のステップ**の作業を行う**別のコンテナ**を持ちたいと思うでしょう。
|
||||
|
||||
/// info | 情報
|
||||
/// info
|
||||
|
||||
もしKubernetesを使用している場合, これはおそらく<a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/" class="external-link" target="_blank">Init Container</a>でしょう。
|
||||
もしKubernetesを使用している場合, これはおそらく<a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/" class="external-link" target="_blank">Init コンテナ</a>でしょう。
|
||||
|
||||
///
|
||||
|
||||
ユースケースが事前のステップを**並列で複数回**実行するのに問題がない場合(例:データベースマイグレーションを実行するのではなく、データベースの準備ができたかをチェックするだけの場合)、メインプロセスを開始する直前に、それらのステップを各コンテナに入れることも可能です。
|
||||
ユースケースが事前のステップを**並列で複数回**実行するのに問題がない場合(例:データベースの準備チェック)、メインプロセスを開始する前に、それらのステップを各コンテナに入れることが可能です。
|
||||
|
||||
### 単一コンテナ { #single-container }
|
||||
### 単一コンテナ
|
||||
|
||||
単純なセットアップで、**単一のコンテナ**で複数の**ワーカープロセス**(または1つのプロセスのみ)を起動する場合、アプリでプロセスを開始する直前に、同じコンテナで事前のステップを実行できます。
|
||||
単純なセットアップで、**単一のコンテナ**で複数の**ワーカー・プロセス**(または1つのプロセスのみ)を起動する場合、アプリでプロセスを開始する直前に、同じコンテナで事前のステップを実行できます。公式Dockerイメージは、内部的にこれをサポートしています。
|
||||
|
||||
### ベースDockerイメージ { #base-docker-image }
|
||||
## Gunicornによる公式Dockerイメージ - Uvicorn
|
||||
|
||||
以前は、公式のFastAPI Dockerイメージがありました:<a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>。しかし、現在は非推奨です。⛔️
|
||||
前の章で詳しく説明したように、Uvicornワーカーで動作するGunicornを含む公式のDockerイメージがあります: [Server Workers - Gunicorn と Uvicorn](server-workers.md){.internal-link target=_blank}で詳しく説明しています。
|
||||
|
||||
おそらく、このベースDockerイメージ(またはその他の類似のもの)は**使用しない**方がよいでしょう。
|
||||
このイメージは、主に上記で説明した状況で役に立つでしょう: [複数のプロセスと特殊なケースを持つコンテナ(Containers with Multiple Processes and Special Cases)](#containers-with-multiple-processes-and-special-cases)
|
||||
|
||||
すでに**Kubernetes**(または他のもの)を使用していて、複数の**コンテナ**で、クラスタレベルで**レプリケーション**を設定している場合。そのような場合は、上記で説明したように**ゼロから**イメージを構築する方がよいでしょう:[FastAPI用のDockerイメージをビルドする](#build-a-docker-image-for-fastapi)。
|
||||
* <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
|
||||
|
||||
また、複数のワーカーが必要な場合は、単純に `--workers` コマンドラインオプションを使用できます。
|
||||
/// warning
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
このDockerイメージは、Uvicornが停止したワーカーの管理と再起動をサポートしていなかった頃に作成されたため、Uvicornと一緒にGunicornを使う必要がありました。これは、GunicornにUvicornワーカープロセスの管理と再起動をさせるだけのために、かなりの複雑さを追加していました。
|
||||
|
||||
しかし現在は、Uvicorn(および `fastapi` コマンド)が `--workers` をサポートしているため、自分でビルドする代わりにベースDockerイメージを使う理由はありません(コード量もだいたい同じです 😅)。
|
||||
このベースイメージや類似のイメージは**必要ない**可能性が高いので、[上記の: FastAPI用のDockerイメージをビルドする(Build a Docker Image for FastAPI)](#build-a-docker-image-for-fastapi)のようにゼロからイメージをビルドする方が良いでしょう。
|
||||
|
||||
///
|
||||
|
||||
## コンテナ・イメージのデプロイ { #deploy-the-container-image }
|
||||
このイメージには、利用可能なCPUコアに基づいて**ワーカー・プロセスの数**を設定する**オートチューニング**メカニズムが含まれています。
|
||||
|
||||
これは**賢明なデフォルト**を備えていますが、**環境変数**や設定ファイルを使ってすべての設定を変更したり更新したりすることができます。
|
||||
|
||||
また、スクリプトで<a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker#pre_start_path" class="external-link" target="_blank">**開始前の事前ステップ**</a>を実行することもサポートしている。
|
||||
|
||||
/// tip
|
||||
|
||||
すべての設定とオプションを見るには、Dockerイメージのページをご覧ください: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>
|
||||
|
||||
///
|
||||
|
||||
### 公式Dockerイメージのプロセス数
|
||||
|
||||
このイメージの**プロセス数**は、利用可能なCPU**コア**から**自動的に計算**されます。
|
||||
|
||||
つまり、CPUから可能な限り**パフォーマンス**を**引き出そう**とします。
|
||||
|
||||
また、**環境変数**などを使った設定で調整することもできます。
|
||||
|
||||
しかし、プロセスの数はコンテナが実行しているCPUに依存するため、**消費されるメモリの量**もそれに依存することになります。
|
||||
|
||||
そのため、(機械学習モデルなどで)大量のメモリを消費するアプリケーションで、サーバーのCPUコアが多いが**メモリが少ない**場合、コンテナは利用可能なメモリよりも多くのメモリを使おうとすることになります。
|
||||
|
||||
その結果、パフォーマンスが大幅に低下する(あるいはクラッシュする)可能性があります。🚨
|
||||
|
||||
### Dockerfileを作成する
|
||||
|
||||
この画像に基づいて`Dockerfile`を作成する方法を以下に示します:
|
||||
|
||||
```Dockerfile
|
||||
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9
|
||||
|
||||
COPY ./requirements.txt /app/requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
|
||||
|
||||
COPY ./app /app
|
||||
```
|
||||
|
||||
### より大きなアプリケーション
|
||||
|
||||
[複数のファイルを持つ大きなアプリケーション](../tutorial/bigger-applications.md){.internal-link target=_blank}を作成するセクションに従った場合、`Dockerfile`は次のようになります:
|
||||
|
||||
```Dockerfile hl_lines="7"
|
||||
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9
|
||||
|
||||
COPY ./requirements.txt /app/requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
|
||||
|
||||
COPY ./app /app/app
|
||||
```
|
||||
|
||||
### いつ使うのか
|
||||
|
||||
おそらく、**Kubernetes**(または他のもの)を使用していて、すでにクラスタレベルで複数の**コンテナ**で**レプリケーション**を設定している場合は、この公式ベースイメージ(または他の類似のもの)は**使用すべきではありません**。
|
||||
|
||||
そのような場合は、上記のように**ゼロから**イメージを構築する方がよいでしょう: [FastAPI用のDockerイメージをビルドする(Build a Docker Image for FastAPI)](#build-a-docker-image-for-fastapi) を参照してください。
|
||||
|
||||
このイメージは、主に上記の[複数のプロセスと特殊なケースを持つコンテナ(Containers with Multiple Processes and Special Cases)](#containers-with-multiple-processes-and-special-cases)で説明したような特殊なケースで役に立ちます。
|
||||
|
||||
例えば、アプリケーションが**シンプル**で、CPUに応じたデフォルトのプロセス数を設定すればうまくいく場合や、クラスタレベルでレプリケーションを手動で設定する手間を省きたい場合、アプリで複数のコンテナを実行しない場合などです。
|
||||
|
||||
または、**Docker Compose**でデプロイし、単一のサーバで実行している場合などです。
|
||||
|
||||
## コンテナ・イメージのデプロイ
|
||||
|
||||
コンテナ(Docker)イメージを手に入れた後、それをデプロイするにはいくつかの方法があります。
|
||||
|
||||
@@ -604,21 +645,104 @@ Docker Composeで**単一サーバ**(クラスタではない)にデプロ
|
||||
* Nomadのような別のツール
|
||||
* コンテナ・イメージをデプロイするクラウド・サービス
|
||||
|
||||
## `uv` を使ったDockerイメージ { #docker-image-with-uv }
|
||||
## Poetryを利用したDockerイメージ
|
||||
|
||||
<a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a> を使ってプロジェクトのインストールと管理をしている場合は、<a href="https://docs.astral.sh/uv/guides/integration/docker/" class="external-link" target="_blank">uv Docker guide</a>に従ってください。
|
||||
もしプロジェクトの依存関係を管理するために<a href="https://python-poetry.org/" class="external-link" target="_blank">Poetry</a>を利用する場合、マルチステージビルドを使うと良いでしょう。
|
||||
|
||||
## まとめ { #recap }
|
||||
```{ .dockerfile .annotate }
|
||||
# (1)
|
||||
FROM python:3.9 as requirements-stage
|
||||
|
||||
# (2)
|
||||
WORKDIR /tmp
|
||||
|
||||
# (3)
|
||||
RUN pip install poetry
|
||||
|
||||
# (4)
|
||||
COPY ./pyproject.toml ./poetry.lock* /tmp/
|
||||
|
||||
# (5)
|
||||
RUN poetry export -f requirements.txt --output requirements.txt --without-hashes
|
||||
|
||||
# (6)
|
||||
FROM python:3.9
|
||||
|
||||
# (7)
|
||||
WORKDIR /code
|
||||
|
||||
# (8)
|
||||
COPY --from=requirements-stage /tmp/requirements.txt /code/requirements.txt
|
||||
|
||||
# (9)
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
# (10)
|
||||
COPY ./app /code/app
|
||||
|
||||
# (11)
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
```
|
||||
|
||||
1. これは最初のステージで、`requirements-stage`と名付けられます
|
||||
2. `/tmp` を現在の作業ディレクトリに設定します
|
||||
ここで `requirements.txt` というファイルを生成します。
|
||||
|
||||
3. このDockerステージにPoetryをインストールします
|
||||
|
||||
4. pyproject.toml`と`poetry.lock`ファイルを`/tmp` ディレクトリにコピーします
|
||||
|
||||
`./poetry.lock*`(末尾に`*`)を使用するため、そのファイルがまだ利用できない場合でもクラッシュすることはないです。
|
||||
5. requirements.txt`ファイルを生成します
|
||||
|
||||
6. これは最後のステージであり、ここにあるものはすべて最終的なコンテナ・イメージに保存されます
|
||||
7. 現在の作業ディレクトリを `/code` に設定します
|
||||
8. `requirements.txt`ファイルを `/code` ディレクトリにコピーします
|
||||
このファイルは前のDockerステージにしか存在しないため、`--from-requirements-stage`を使ってコピーします。
|
||||
9. 生成された `requirements.txt` ファイルにあるパッケージの依存関係をインストールします
|
||||
10. app` ディレクトリを `/code` ディレクトリにコピーします
|
||||
11. uvicorn` コマンドを実行して、`app.main` からインポートした `app` オブジェクトを使用するように指示します
|
||||
/// tip
|
||||
|
||||
"+"の吹き出しをクリックすると、それぞれの行が何をするのかを見ることができます
|
||||
|
||||
///
|
||||
|
||||
**Dockerステージ**は`Dockerfile`の一部で、**一時的なコンテナイメージ**として動作します。
|
||||
|
||||
最初のステージは **Poetryのインストール**と Poetry の `pyproject.toml` ファイルからプロジェクトの依存関係を含む**`requirements.txt`を生成**するためだけに使用されます。
|
||||
|
||||
この `requirements.txt` ファイルは後半の **次のステージ**で `pip` と共に使用されます。
|
||||
|
||||
最終的なコンテナイメージでは、**最終ステージ**のみが保存されます。前のステージは破棄されます。
|
||||
|
||||
Poetryを使用する場合、**Dockerマルチステージビルド**を使用することは理にかなっています。
|
||||
|
||||
なぜなら、最終的なコンテナイメージにPoetryとその依存関係がインストールされている必要はなく、**必要なのは**プロジェクトの依存関係をインストールするために生成された `requirements.txt` ファイルだけだからです。
|
||||
|
||||
そして次の(そして最終的な)ステージでは、前述とほぼ同じ方法でイメージをビルドします。
|
||||
|
||||
### TLS Termination Proxyの裏側 - Poetry
|
||||
|
||||
繰り返しになりますが、NginxやTraefikのようなTLS Termination Proxy(ロードバランサー)の後ろでコンテナを動かしている場合は、`--proxy-headers`オプションをコマンドに追加します:
|
||||
|
||||
```Dockerfile
|
||||
CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
|
||||
```
|
||||
|
||||
## まとめ
|
||||
|
||||
コンテナ・システム(例えば**Docker**や**Kubernetes**など)を使えば、すべての**デプロイメントのコンセプト**を扱うのがかなり簡単になります:
|
||||
|
||||
* HTTPS
|
||||
* セキュリティ - HTTPS
|
||||
* 起動時の実行
|
||||
* 再起動
|
||||
* レプリケーション(実行中のプロセス数)
|
||||
* **レプリケーション(実行中のプロセス数)**
|
||||
* メモリ
|
||||
* 開始前の事前ステップ
|
||||
|
||||
ほとんどの場合、ベースとなるイメージは使用せず、公式のPython Dockerイメージをベースにした**コンテナイメージをゼロからビルド**します。
|
||||
|
||||
`Dockerfile`と**Dockerキャッシュ**内の命令の**順番**に注意することで、**ビルド時間を最小化**し、生産性を最大化できます(そして退屈を避けることができます)。😎
|
||||
`Dockerfile`と**Dockerキャッシュ**内の命令の**順番**に注意することで、**ビルド時間を最小化**することができ、生産性を最大化することができます(そして退屈を避けることができます)。😎
|
||||
|
||||
特別なケースでは、FastAPI用の公式Dockerイメージを使いたいかもしれません。🤓
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# HTTPS について { #about-https }
|
||||
# HTTPS について
|
||||
|
||||
HTTPSは単に「有効」か「無効」かで決まるものだと思いがちです。
|
||||
|
||||
しかし、それよりもはるかに複雑です。
|
||||
|
||||
/// tip | 豆知識
|
||||
/// tip
|
||||
|
||||
もし急いでいたり、HTTPSの仕組みについて気にしないのであれば、次のセクションに進み、さまざまなテクニックを使ってすべてをセットアップするステップ・バイ・ステップの手順をご覧ください。
|
||||
|
||||
@@ -22,19 +22,25 @@ HTTPSは単に「有効」か「無効」かで決まるものだと思いがち
|
||||
* 接続の暗号化は**TCPレベル**で行われます。
|
||||
* それは**HTTPの1つ下**のレイヤーです。
|
||||
* つまり、**証明書と暗号化**の処理は、**HTTPの前**に行われます。
|
||||
* **TCPは「ドメイン」について知りません**。IPアドレスについてのみ知っています。
|
||||
* **TCPは "ドメイン "について知りません**。IPアドレスについてのみ知っています。
|
||||
* 要求された**特定のドメイン**に関する情報は、**HTTPデータ**に入ります。
|
||||
* **HTTPS証明書**は、**特定のドメイン**を「証明」しますが、プロトコルと暗号化はTCPレベルで行われ、どのドメインが扱われているかを**知る前**に行われます。
|
||||
* **デフォルトでは**、**IPアドレスごとに1つのHTTPS証明書**しか持てないことになります。
|
||||
* これは、サーバーの規模やアプリケーションの規模に寄りません。
|
||||
* しかし、これには**解決策**があります。
|
||||
* **TLS**プロトコル(HTTPの前に、TCPレベルで暗号化を処理するもの)には、**<a href="https://en.wikipedia.org/wiki/Server_Name_Indication" class="external-link" target="_blank"><abbr title="Server Name Indication">SNI</abbr></a>**と呼ばれる**拡張**があります。
|
||||
* **TLS**プロトコル(HTTPの前に、TCPレベルで暗号化を処理するもの)には、**<a href="https://en.wikipedia.org/wiki/Server_Name_Indication" class="external-link" target="_blank"><abbr title="サーバー名表示">SNI</abbr></a>**と呼ばれる**拡張**があります。
|
||||
* このSNI拡張機能により、1つのサーバー(**単一のIPアドレス**を持つ)が**複数のHTTPS証明書**を持ち、**複数のHTTPSドメイン/アプリケーション**にサービスを提供できるようになります。
|
||||
* これが機能するためには、**パブリックIPアドレス**でリッスンしている、サーバー上で動作している**単一の**コンポーネント(プログラム)が、サーバー内の**すべてのHTTPS証明書**を持っている必要があります。
|
||||
|
||||
* セキュアな接続を取得した**後**でも、通信プロトコルは**HTTPのまま**です。
|
||||
* コンテンツは**HTTPプロトコル**で送信されているにもかかわらず、**暗号化**されています。
|
||||
|
||||
サーバー(マシン、ホストなど)上で**1つのプログラム/HTTPサーバー**を実行させ、**HTTPSに関する全てのこと**を管理するのが一般的です。**暗号化された HTTPS リクエスト** を受信し、**復号化された HTTP リクエスト** を同じサーバーで実行されている実際の HTTP アプリケーション(この場合は **FastAPI** アプリケーション)に送信し、アプリケーションから **HTTP レスポンス** を受け取り、適切な **HTTPS 証明書** を使用して **暗号化** し、そして**HTTPS** を使用してクライアントに送り返します。このサーバーはしばしば **<a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" class="external-link" target="_blank">TLS Termination Proxy</a>**と呼ばれます。
|
||||
|
||||
サーバー(マシン、ホストなど)上で**1つのプログラム/HTTPサーバー**を実行させ、**HTTPSに関する全てのこと**を管理するのが一般的です。
|
||||
|
||||
**暗号化された HTTPS リクエスト** を受信し、**復号化された HTTP リクエスト** を同じサーバーで実行されている実際の HTTP アプリケーション(この場合は **FastAPI** アプリケーション)に送信し、アプリケーションから **HTTP レスポンス** を受け取り、適切な **HTTPS 証明書** を使用して **暗号化** し、そして**HTTPS** を使用してクライアントに送り返します。
|
||||
|
||||
このサーバーはしばしば **<a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" class="external-link" target="_blank">TLS Termination Proxy</a>**と呼ばれます。
|
||||
|
||||
TLS Termination Proxyとして使えるオプションには、以下のようなものがあります:
|
||||
|
||||
@@ -44,7 +50,7 @@ TLS Termination Proxyとして使えるオプションには、以下のよう
|
||||
* HAProxy
|
||||
|
||||
|
||||
## Let's Encrypt { #lets-encrypt }
|
||||
## Let's Encrypt
|
||||
|
||||
Let's Encrypt以前は、これらの**HTTPS証明書**は信頼できる第三者によって販売されていました。
|
||||
|
||||
@@ -58,27 +64,27 @@ Let's Encrypt以前は、これらの**HTTPS証明書**は信頼できる第三
|
||||
|
||||
このアイデアは、これらの証明書の取得と更新を自動化することで、**安全なHTTPSを、無料で、永遠に**利用できるようにすることです。
|
||||
|
||||
## 開発者のための HTTPS { #https-for-developers }
|
||||
## 開発者のための HTTPS
|
||||
|
||||
ここでは、HTTPS APIがどのように見えるかの例を、主に開発者にとって重要なアイデアに注意を払いながら、ステップ・バイ・ステップで説明します。
|
||||
|
||||
### ドメイン名 { #domain-name }
|
||||
### ドメイン名
|
||||
|
||||
ステップの初めは、**ドメイン名**を**取得すること**から始まるでしょう。その後、DNSサーバー(おそらく同じクラウドプロバイダー)に設定します。
|
||||
|
||||
おそらくクラウドサーバー(仮想マシン)かそれに類するものを手に入れ、<abbr title="That doesn't change – 変わらない">fixed</abbr> **パブリックIPアドレス**を持つことになるでしょう。
|
||||
おそらくクラウドサーバー(仮想マシン)かそれに類するものを手に入れ、<abbr title="変わらない">固定の</abbr> **パブリックIPアドレス**を持つことになるでしょう。
|
||||
|
||||
DNSサーバーでは、**取得したドメイン**をあなたのサーバーのパプリック**IPアドレス**に向けるレコード(「`A record`」)を設定します。
|
||||
DNSサーバーでは、**取得したドメイン**をあなたのサーバーのパプリック**IPアドレス**に向けるレコード(「`Aレコード`」)を設定します。
|
||||
|
||||
これはおそらく、最初の1回だけあり、すべてをセットアップするときに行うでしょう。
|
||||
|
||||
/// tip | 豆知識
|
||||
/// tip
|
||||
|
||||
ドメイン名の話はHTTPSに関する話のはるか前にありますが、すべてがドメインとIPアドレスに依存するため、ここで言及する価値があります。
|
||||
|
||||
///
|
||||
|
||||
### DNS { #dns }
|
||||
### DNS
|
||||
|
||||
では、実際のHTTPSの部分に注目してみよう。
|
||||
|
||||
@@ -88,7 +94,7 @@ DNSサーバーは、ブラウザに特定の**IPアドレス**を使用する
|
||||
|
||||
<img src="/img/deployment/https/https01.drawio.svg">
|
||||
|
||||
### TLS Handshake の開始 { #tls-handshake-start }
|
||||
### TLS Handshake の開始
|
||||
|
||||
ブラウザはIPアドレスと**ポート443**(HTTPSポート)で通信します。
|
||||
|
||||
@@ -98,7 +104,7 @@ DNSサーバーは、ブラウザに特定の**IPアドレス**を使用する
|
||||
|
||||
TLS接続を確立するためのクライアントとサーバー間のこのやりとりは、**TLSハンドシェイク**と呼ばれます。
|
||||
|
||||
### SNI拡張機能付きのTLS { #tls-with-sni-extension }
|
||||
### SNI拡張機能付きのTLS
|
||||
|
||||
サーバー内の**1つのプロセス**だけが、特定 の**IPアドレス**の特定の**ポート** で待ち受けることができます。
|
||||
|
||||
@@ -106,7 +112,7 @@ TLS接続を確立するためのクライアントとサーバー間のこの
|
||||
|
||||
TLS(HTTPS)はデフォルトで`443`という特定のポートを使用する。つまり、これが必要なポートです。
|
||||
|
||||
このポートをリクエストできるのは1つのプロセスだけなので、これを実行するプロセスは**TLS Termination Proxy**となります。
|
||||
このポートをリッスンできるのは1つのプロセスだけなので、これを実行するプロセスは**TLS Termination Proxy**となります。
|
||||
|
||||
TLS Termination Proxyは、1つ以上の**TLS証明書**(HTTPS証明書)にアクセスできます。
|
||||
|
||||
@@ -124,13 +130,13 @@ TLS Termination Proxyは、1つ以上の**TLS証明書**(HTTPS証明書)に
|
||||
|
||||
これが**HTTPS**であり、純粋な(暗号化されていない)TCP接続ではなく、**セキュアなTLS接続**の中に**HTTP**があるだけです。
|
||||
|
||||
/// tip | 豆知識
|
||||
/// tip
|
||||
|
||||
通信の暗号化は、HTTPレベルではなく、**TCPレベル**で行われることに注意してください。
|
||||
|
||||
///
|
||||
|
||||
### HTTPS リクエスト { #https-request }
|
||||
### HTTPS リクエスト
|
||||
|
||||
これでクライアントとサーバー(具体的にはブラウザとTLS Termination Proxy)は**暗号化されたTCP接続**を持つことになり、**HTTP通信**を開始することができます。
|
||||
|
||||
@@ -138,19 +144,19 @@ TLS Termination Proxyは、1つ以上の**TLS証明書**(HTTPS証明書)に
|
||||
|
||||
<img src="/img/deployment/https/https04.drawio.svg">
|
||||
|
||||
### リクエストの復号化 { #decrypt-the-request }
|
||||
### リクエストの復号化
|
||||
|
||||
TLS Termination Proxy は、合意が取れている暗号化を使用して、**リクエストを復号化**し、**プレーン (復号化された) HTTP リクエスト** をアプリケーションを実行しているプロセス (例えば、FastAPI アプリケーションを実行している Uvicorn を持つプロセス) に送信します。
|
||||
|
||||
<img src="/img/deployment/https/https05.drawio.svg">
|
||||
|
||||
### HTTP レスポンス { #http-response }
|
||||
### HTTP レスポンス
|
||||
|
||||
アプリケーションはリクエストを処理し、**プレーン(暗号化されていない)HTTPレスポンス** をTLS Termination Proxyに送信します。
|
||||
|
||||
<img src="/img/deployment/https/https06.drawio.svg">
|
||||
|
||||
### HTTPS レスポンス { #https-response }
|
||||
### HTTPS レスポンス
|
||||
|
||||
TLS Termination Proxyは次に、事前に合意が取れている暗号(`someapp.example.com`の証明書から始まる)を使って**レスポンスを暗号化し**、ブラウザに送り返す。
|
||||
|
||||
@@ -160,7 +166,7 @@ TLS Termination Proxyは次に、事前に合意が取れている暗号(`someap
|
||||
|
||||
クライアント(ブラウザ)は、レスポンスが正しいサーバーから来たことを知ることができます。 なぜなら、そのサーバーは、以前に**HTTPS証明書**を使って合意した暗号を使っているからです。
|
||||
|
||||
### 複数のアプリケーション { #multiple-applications }
|
||||
### 複数のアプリケーション
|
||||
|
||||
同じサーバー(または複数のサーバー)に、例えば他のAPIプログラムやデータベースなど、**複数のアプリケーション**が存在する可能性があります。
|
||||
|
||||
@@ -170,7 +176,7 @@ TLS Termination Proxyは次に、事前に合意が取れている暗号(`someap
|
||||
|
||||
そうすれば、TLS Termination Proxy は、**複数のドメイン**や複数のアプリケーションのHTTPSと証明書を処理し、それぞれのケースで適切なアプリケーションにリクエストを送信することができます。
|
||||
|
||||
### 証明書の更新 { #certificate-renewal }
|
||||
### 証明書の更新
|
||||
|
||||
将来のある時点で、各証明書は(取得後約3ヶ月で)**失効**します。
|
||||
|
||||
@@ -194,42 +200,10 @@ TLS Termination Proxyは次に、事前に合意が取れている暗号(`someap
|
||||
|
||||
アプリを提供しながらこのような更新処理を行うことは、アプリケーション・サーバー(Uvicornなど)でTLS証明書を直接使用するのではなく、TLS Termination Proxyを使用して**HTTPSを処理する別のシステム**を用意したくなる主な理由の1つです。
|
||||
|
||||
## プロキシ転送ヘッダー { #proxy-forwarded-headers }
|
||||
|
||||
プロキシを使ってHTTPSを処理する場合、**アプリケーションサーバー**(たとえばFastAPI CLI経由のUvicorn)はHTTPS処理について何も知らず、**TLS Termination Proxy**とはプレーンなHTTPで通信します。
|
||||
|
||||
この**プロキシ**は通常、リクエストを**アプリケーションサーバー**に転送する前に、その場でいくつかのHTTPヘッダーを設定し、リクエストがプロキシによって**転送**されていることをアプリケーションサーバーに知らせます。
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
プロキシヘッダーは次のとおりです:
|
||||
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For" class="external-link" target="_blank">X-Forwarded-For</a>
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto" class="external-link" target="_blank">X-Forwarded-Proto</a>
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host" class="external-link" target="_blank">X-Forwarded-Host</a>
|
||||
|
||||
///
|
||||
|
||||
それでも、**アプリケーションサーバー**は信頼できる**プロキシ**の背後にあることを知らないため、デフォルトではそれらのヘッダーを信頼しません。
|
||||
|
||||
しかし、**アプリケーションサーバー**が**プロキシ**から送信される*forwarded*ヘッダーを信頼するように設定できます。FastAPI CLIを使用している場合は、*CLI Option* `--forwarded-allow-ips` を使って、どのIPからの*forwarded*ヘッダーを信頼すべきかを指定できます。
|
||||
|
||||
たとえば、**アプリケーションサーバー**が信頼できる**プロキシ**からの通信のみを受け取っている場合、`--forwarded-allow-ips="*"` に設定して、受信するすべてのIPを信頼するようにできます。受け取るリクエストは、**プロキシ**が使用するIPからのものだけになるためです。
|
||||
|
||||
こうすることで、アプリケーションは、HTTPSを使用しているかどうか、ドメインなど、自身のパブリックURLが何であるかを把握できるようになります。
|
||||
|
||||
これは、たとえばリダイレクトを適切に処理するのに便利です。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
これについては、[Behind a Proxy - Enable Proxy Forwarded Headers](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers){.internal-link target=_blank} のドキュメントで詳しく学べます。
|
||||
|
||||
///
|
||||
|
||||
## まとめ { #recap }
|
||||
## まとめ
|
||||
|
||||
**HTTPS**を持つことは非常に重要であり、ほとんどの場合、かなり**クリティカル**です。開発者として HTTPS に関わる労力のほとんどは、これらの**概念とその仕組みを理解する**ことです。
|
||||
|
||||
しかし、ひとたび**開発者向けHTTPS**の基本的な情報を知れば、簡単な方法ですべてを管理するために、さまざまなツールを組み合わせて設定することができます。
|
||||
|
||||
次の章のいくつかでは、**FastAPI** アプリケーションのために **HTTPS** をセットアップする方法について、いくつかの具体例を紹介します。🔒
|
||||
次の章では、**FastAPI** アプリケーションのために **HTTPS** をセットアップする方法について、いくつかの具体例を紹介します。🔒
|
||||
|
||||
@@ -1,23 +1,7 @@
|
||||
# デプロイ { #deployment }
|
||||
# デプロイ
|
||||
|
||||
**FastAPI** アプリケーションのデプロイは比較的簡単です。
|
||||
**FastAPI** 製のアプリケーションは比較的容易にデプロイできます。
|
||||
|
||||
## デプロイとは { #what-does-deployment-mean }
|
||||
ユースケースや使用しているツールによっていくつかの方法に分かれます。
|
||||
|
||||
アプリケーションを**デプロイ**するとは、**ユーザーが利用できるようにする**ために必要な手順を実行することを意味します。
|
||||
|
||||
**Web API** の場合、通常は **リモートマシン** 上に配置し、優れたパフォーマンス、安定性などを提供する **サーバープログラム** と組み合わせて、**ユーザー** が中断や問題なく効率的にアプリケーションへ**アクセス**できるようにします。
|
||||
|
||||
これは **開発** 段階とは対照的です。開発では、コードを常に変更し、壊しては直し、開発サーバーを停止したり再起動したりします。
|
||||
|
||||
## デプロイ戦略 { #deployment-strategies }
|
||||
|
||||
具体的なユースケースや使用するツールによって、いくつかの方法があります。
|
||||
|
||||
複数のツールを組み合わせて自分で**サーバーをデプロイ**することもできますし、作業の一部を代行してくれる **クラウドサービス** を使うこともできます。ほかにも選択肢があります。
|
||||
|
||||
たとえば、FastAPI の開発チームである私たちは、クラウドへの FastAPI アプリのデプロイを可能な限り合理化し、FastAPI を使って開発するのと同じ開発者体験を提供するために、<a href="https://fastapicloud.com" class="external-link" target="_blank">**FastAPI Cloud**</a> を構築しました。
|
||||
|
||||
**FastAPI** アプリケーションをデプロイする際に、おそらく念頭に置くべき主要な概念をいくつか紹介します(ただし、そのほとんどは他の種類の Web アプリケーションにも当てはまります)。
|
||||
|
||||
次のセクションでは、留意すべき点の詳細や、それを実現するためのいくつかの手法を確認します。 ✨
|
||||
次のセクションでより詳しくそれらの方法について説明します。
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Server Workers - ワーカー付きUvicorn { #server-workers-uvicorn-with-workers }
|
||||
# Server Workers - Gunicorn と Uvicorn
|
||||
|
||||
前回のデプロイメントのコンセプトを振り返ってみましょう:
|
||||
|
||||
@@ -9,79 +9,124 @@
|
||||
* メモリ
|
||||
* 開始前の事前ステップ
|
||||
|
||||
ここまでのドキュメントのチュートリアルでは、おそらく `fastapi` コマンドなど(Uvicornを実行するもの)を使って、**単一のプロセス**として動作する**サーバープログラム**を実行してきたはずです。
|
||||
ここまでのドキュメントのチュートリアルでは、おそらくUvicornのような**サーバープログラム**を**単一のプロセス**で実行しています。
|
||||
|
||||
アプリケーションをデプロイする際には、**複数のコア**を利用し、そしてより多くのリクエストを処理できるようにするために、プロセスの**レプリケーション**を持つことを望むでしょう。
|
||||
|
||||
前のチャプターである[デプロイメントのコンセプト](concepts.md){.internal-link target=_blank}にて見てきたように、有効な戦略がいくつかあります。
|
||||
|
||||
ここでは、`fastapi` コマンド、または `uvicorn` コマンドを直接使って、**ワーカープロセス**付きの **Uvicorn** を使う方法を紹介します。
|
||||
ここでは<a href="https://gunicorn.org/" class="external-link" target="_blank">**Gunicorn**</a>が**Uvicornのワーカー・プロセス**を管理する場合の使い方について紹介していきます。
|
||||
|
||||
/// info | 情報
|
||||
/// info
|
||||
|
||||
DockerやKubernetesなどのコンテナを使用している場合は、次の章で詳しく説明します: [コンテナ内のFastAPI - Docker](docker.md){.internal-link target=_blank}。
|
||||
<!-- NOTE: the current version of docker.md is outdated compared to English one. -->
|
||||
DockerやKubernetesなどのコンテナを使用している場合は、次の章で詳しく説明します: [コンテナ内のFastAPI - Docker](docker.md){.internal-link target=_blank}
|
||||
|
||||
特に**Kubernetes**上で実行する場合は、おそらくワーカーは使わず、代わりに**コンテナごとに単一のUvicornプロセス**を実行したいはずですが、それについてはその章の後半で説明します。
|
||||
特に**Kubernetes**上で実行する場合は、おそらく**Gunicornを使用せず**、**コンテナごとに単一のUvicornプロセス**を実行することになりますが、それについてはこの章の後半で説明します。
|
||||
|
||||
///
|
||||
|
||||
## 複数ワーカー { #multiple-workers }
|
||||
## GunicornによるUvicornのワーカー・プロセスの管理
|
||||
|
||||
`--workers` コマンドラインオプションで複数のワーカーを起動できます。
|
||||
**Gunicorn**は**WSGI標準**のアプリケーションサーバーです。このことは、GunicornはFlaskやDjangoのようなアプリケーションにサービスを提供できることを意味します。Gunicornそれ自体は**FastAPI**と互換性がないですが、というのもFastAPIは最新の**<a href="https://asgi.readthedocs.io/en/latest/" class="external-link" target="_blank">ASGI 標準</a>**を使用しているためです。
|
||||
|
||||
//// tab | `fastapi`
|
||||
しかし、Gunicornは**プロセスマネージャー**として動作し、ユーザーが特定の**ワーカー・プロセスクラス**を使用するように指示することができます。するとGunicornはそのクラスを使い1つ以上の**ワーカー・プロセス**を開始します。
|
||||
|
||||
`fastapi` コマンドを使う場合:
|
||||
そして**Uvicorn**には**Gunicorn互換のワーカークラス**があります。
|
||||
|
||||
この組み合わせで、Gunicornは**プロセスマネージャー**として動作し、**ポート**と**IP**をリッスンします。そして、**Uvicornクラス**を実行しているワーカー・プロセスに通信を**転送**します。
|
||||
|
||||
そして、Gunicorn互換の**Uvicornワーカー**クラスが、FastAPIが使えるように、Gunicornから送られてきたデータをASGI標準に変換する役割を担います。
|
||||
|
||||
## GunicornとUvicornをインストールする
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ <font color="#4E9A06">fastapi</font> run --workers 4 <u style="text-decoration-style:solid">main.py</u>
|
||||
$ pip install "uvicorn[standard]" gunicorn
|
||||
|
||||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting production server 🚀
|
||||
|
||||
Searching for package file structure from directories with
|
||||
<font color="#3465A4">__init__.py</font> files
|
||||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with the
|
||||
following code:
|
||||
|
||||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000/docs</u></font>
|
||||
|
||||
Logs:
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C to
|
||||
quit<b>)</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started parent process <b>[</b><font color="#34E2E2"><b>27365</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>27368</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>27369</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>27370</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>27367</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
////
|
||||
これによりUvicornと(高性能を得るための)標準(`standard`)の追加パッケージとGunicornの両方がインストールされます。
|
||||
|
||||
//// tab | `uvicorn`
|
||||
## UvicornのワーカーとともにGunicornを実行する
|
||||
|
||||
`uvicorn` コマンドを直接使いたい場合:
|
||||
Gunicornを以下のように起動させることができます:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ gunicorn main:app --workers 4 --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:80
|
||||
|
||||
[19499] [INFO] Starting gunicorn 20.1.0
|
||||
[19499] [INFO] Listening at: http://0.0.0.0:80 (19499)
|
||||
[19499] [INFO] Using worker: uvicorn.workers.UvicornWorker
|
||||
[19511] [INFO] Booting worker with pid: 19511
|
||||
[19513] [INFO] Booting worker with pid: 19513
|
||||
[19514] [INFO] Booting worker with pid: 19514
|
||||
[19515] [INFO] Booting worker with pid: 19515
|
||||
[19511] [INFO] Started server process [19511]
|
||||
[19511] [INFO] Waiting for application startup.
|
||||
[19511] [INFO] Application startup complete.
|
||||
[19513] [INFO] Started server process [19513]
|
||||
[19513] [INFO] Waiting for application startup.
|
||||
[19513] [INFO] Application startup complete.
|
||||
[19514] [INFO] Started server process [19514]
|
||||
[19514] [INFO] Waiting for application startup.
|
||||
[19514] [INFO] Application startup complete.
|
||||
[19515] [INFO] Started server process [19515]
|
||||
[19515] [INFO] Waiting for application startup.
|
||||
[19515] [INFO] Application startup complete.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
それぞれのオプションの意味を見てみましょう:
|
||||
|
||||
* `main:app`: `main`は"`main`"という名前のPythonモジュール、つまりファイル`main.py`を意味します。そして `app` は **FastAPI** アプリケーションの変数名です。
|
||||
* main:app`はPythonの`import`文と同じようなものだと想像できます:
|
||||
|
||||
```Python
|
||||
from main import app
|
||||
```
|
||||
|
||||
* つまり、`main:app`のコロンは、`from main import app`のPythonの`import`の部分と同じになります。
|
||||
|
||||
* `--workers`: 使用するワーカー・プロセスの数で、それぞれがUvicornのワーカーを実行します。
|
||||
|
||||
* `--worker-class`: ワーカー・プロセスで使用するGunicorn互換のワーカークラスです。
|
||||
* ここではGunicornがインポートして使用できるクラスを渡します:
|
||||
|
||||
```Python
|
||||
import uvicorn.workers.UvicornWorker
|
||||
```
|
||||
|
||||
* `--bind`: GunicornにリッスンするIPとポートを伝えます。コロン(`:`)でIPとポートを区切ります。
|
||||
* Uvicornを直接実行している場合は、`--bind 0.0.0.0:80` (Gunicornのオプション)の代わりに、`--host 0.0.0.0`と `--port 80`を使います。
|
||||
|
||||
出力では、各プロセスの**PID**(プロセスID)が表示されているのがわかります(単なる数字です)。
|
||||
|
||||
以下の通りです:
|
||||
|
||||
* Gunicornの**プロセス・マネージャー**はPID `19499`(あなたの場合は違う番号でしょう)で始まります。
|
||||
* 次に、`Listening at: http://0.0.0.0:80`を開始します。
|
||||
* それから `uvicorn.workers.UvicornWorker` でワーカークラスを使用することを検出します。
|
||||
* そして、**4つのワーカー**を起動します。それぞれのワーカーのPIDは、`19511`、`19513`、`19514`、`19515`です。
|
||||
|
||||
Gunicornはまた、ワーカーの数を維持するために必要であれば、**ダウンしたプロセス**を管理し、**新しいプロセスを**再起動**させます。そのため、上記のリストにある**再起動**の概念に一部役立ちます。
|
||||
|
||||
しかしながら、必要であればGunicornを**再起動**させ、**起動時に実行**させるなど、外部のコンポーネントを持たせることも必要かもしれません。
|
||||
|
||||
## Uvicornとワーカー
|
||||
|
||||
Uvicornには複数の**ワーカー・プロセス**を起動し実行するオプションもあります。
|
||||
|
||||
とはいうものの、今のところUvicornのワーカー・プロセスを扱う機能はGunicornよりも制限されています。そのため、このレベル(Pythonレベル)でプロセスマネージャーを持ちたいのであれば、Gunicornをプロセスマネージャーとして使ってみた方が賢明かもしれないです。
|
||||
|
||||
どんな場合であれ、以下のように実行します:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -105,35 +150,36 @@ $ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4
|
||||
|
||||
</div>
|
||||
|
||||
////
|
||||
ここで唯一の新しいオプションは `--workers` で、Uvicornに4つのワーカー・プロセスを起動するように指示しています。
|
||||
|
||||
ここで唯一の新しいオプションは `--workers` で、Uvicornに4つのワーカープロセスを起動するように指示しています。
|
||||
各プロセスの **PID** が表示され、親プロセスの `27365` (これは **プロセスマネージャ**) と、各ワーカー・プロセスの **PID** が表示されます: `27368`、`27369`、`27370`、`27367`になります。
|
||||
|
||||
各プロセスの **PID** も表示されていて、親プロセス(これは**プロセスマネージャー**)が `27365`、各ワーカープロセスがそれぞれ `27368`、`27369`、`27370`、`27367` です。
|
||||
## デプロイメントのコンセプト
|
||||
|
||||
## デプロイメントのコンセプト { #deployment-concepts }
|
||||
ここでは、アプリケーションの実行を**並列化**し、CPUの**マルチコア**を活用し、**より多くのリクエスト**に対応できるようにするために、**Gunicorn**(またはUvicorn)を使用して**Uvicornワーカー・プロセス**を管理する方法を見ていきました。
|
||||
|
||||
ここでは、複数の **ワーカー** を使ってアプリケーションの実行を**並列化**し、CPUの**複数コア**を活用して、**より多くのリクエスト**を処理できるようにする方法を見てきました。
|
||||
上記のデプロイのコンセプトのリストから、ワーカーを使うことは主に**レプリケーション**の部分と、**再起動**を少し助けてくれます:
|
||||
|
||||
上のデプロイメントのコンセプトのリストから、ワーカーを使うことは主に**レプリケーション**の部分と、**再起動**を少し助けてくれますが、それ以外については引き続き対処が必要です:
|
||||
|
||||
* **セキュリティ - HTTPS**
|
||||
* **起動時の実行**
|
||||
* ***再起動***
|
||||
* セキュリティ - HTTPS
|
||||
* 起動時の実行
|
||||
* 再起動
|
||||
* レプリケーション(実行中のプロセス数)
|
||||
* **メモリ**
|
||||
* **開始前の事前ステップ**
|
||||
* メモリー
|
||||
* 開始前の事前のステップ
|
||||
|
||||
## コンテナとDocker { #containers-and-docker }
|
||||
|
||||
次章の[コンテナ内のFastAPI - Docker](docker.md){.internal-link target=_blank}では、その他の**デプロイメントのコンセプト**を扱うために使える戦略をいくつか説明します。
|
||||
## コンテナとDocker
|
||||
<!-- NOTE: the current version of docker.md is outdated compared to English one. -->
|
||||
次章の[コンテナ内のFastAPI - Docker](docker.md){.internal-link target=_blank}では、その他の**デプロイのコンセプト**を扱うために実施するであろう戦略をいくつか紹介します。
|
||||
|
||||
単一のUvicornプロセスを実行するために、**ゼロから独自のイメージを構築する**方法も紹介します。これは簡単なプロセスで、**Kubernetes**のような分散コンテナ管理システムを使う場合に、おそらくやりたいことでしょう。
|
||||
また、**GunicornとUvicornワーカー**を含む**公式Dockerイメージ**と、簡単なケースに役立ついくつかのデフォルト設定も紹介します。
|
||||
|
||||
## まとめ { #recap }
|
||||
また、(Gunicornを使わずに)Uvicornプロセスを1つだけ実行するために、**ゼロから独自のイメージを**構築する方法も紹介します。これは簡単なプロセスで、おそらく**Kubernetes**のような分散コンテナ管理システムを使うときにやりたいことでしょう。
|
||||
|
||||
`fastapi` または `uvicorn` コマンドで `--workers` CLIオプションを使うことで、**マルチコアCPU**を活用し、**複数のプロセスを並列実行**できるように複数のワーカープロセスを利用できます。
|
||||
## まとめ
|
||||
|
||||
他のデプロイメントのコンセプトを自分で対応しながら、**独自のデプロイシステム**を構築している場合にも、これらのツールやアイデアを使えます。
|
||||
Uvicornワーカーを使ったプロセスマネージャとして**Gunicorn**(またはUvicorn)を使えば、**マルチコアCPU**を活用して**複数のプロセスを並列実行**できます。
|
||||
|
||||
次の章で、コンテナ(例:DockerやKubernetes)を使った **FastAPI** について学びましょう。これらのツールにも、他の**デプロイメントのコンセプト**を解決する簡単な方法があることがわかります。✨
|
||||
これらのツールやアイデアは、**あなた自身のデプロイシステム**をセットアップしながら、他のデプロイコンセプトを自分で行う場合にも使えます。
|
||||
|
||||
次の章では、コンテナ(DockerやKubernetesなど)を使った**FastAPI**について学んでいきましょう。これらのツールには、他の**デプロイのコンセプト**も解決する簡単な方法があることがわかるでしょう。✨
|
||||
|
||||
@@ -1,93 +1,93 @@
|
||||
# FastAPIのバージョンについて { #about-fastapi-versions }
|
||||
# FastAPIのバージョンについて
|
||||
|
||||
**FastAPI** はすでに多くのアプリケーションやシステムで本番環境にて使われています。また、テストカバレッジは 100% に維持されています。しかし、開発は依然として急速に進んでいます。
|
||||
**FastAPI** は既に多くのアプリケーションやシステムに本番環境で使われています。また、100%のテストカバレッジを維持しています。しかし、活発な開発が続いています。
|
||||
|
||||
新機能が高頻度で追加され、定期的にバグが修正され、コードは継続的に改善されています。
|
||||
高頻度で新機能が追加され、定期的にバグが修正され、実装は継続的に改善されています。
|
||||
|
||||
これが現在のバージョンがいまだに `0.x.x` な理由であり、それぞれのバージョンは破壊的な変更がなされる可能性があります。これは、<a href="https://semver.org/" class="external-link" target="_blank">セマンティック バージョニング</a>の規則に則っています。
|
||||
|
||||
**FastAPI** を使用すると本番用アプリケーションを今すぐ作成できます(そして、おそらくあなたはしばらく前からそうしているはずです)。必要なのは、残りのコードと正しく動作するバージョンを使用していることを確認することだけです。
|
||||
**FastAPI** を使用すると本番用アプリケーションをすぐに作成できますが (すでに何度も経験しているかもしれませんが)、残りのコードが正しく動作するバージョンなのか確認しなければいけません。
|
||||
|
||||
## `fastapi` のバージョンを固定 { #pin-your-fastapi-version }
|
||||
## `fastapi` のバージョンを固定
|
||||
|
||||
最初にすべきことは、使用している **FastAPI** のバージョンを、アプリケーションで正しく動作することが分かっている特定の最新バージョンに「固定(pin)」することです。
|
||||
最初にすべきことは、アプリケーションが正しく動作する **FastAPI** のバージョンを固定することです。
|
||||
|
||||
例えば、アプリでバージョン `0.112.0` を使っているとしましょう。
|
||||
例えば、バージョン `0.45.0` を使っているとしましょう。
|
||||
|
||||
`requirements.txt` ファイルを使う場合は、以下のようにバージョンを指定できます:
|
||||
`requirements.txt` を使っているなら、以下の様にバージョンを指定できます:
|
||||
|
||||
```txt
|
||||
fastapi[standard]==0.112.0
|
||||
fastapi==0.45.0
|
||||
```
|
||||
|
||||
これは、厳密にバージョン `0.112.0` だけを使うことを意味します。
|
||||
これは、厳密にバージョン `0.45.0` だけを使うことを意味します。
|
||||
|
||||
または、以下のように固定することもできます:
|
||||
|
||||
```txt
|
||||
fastapi[standard]>=0.112.0,<0.113.0
|
||||
```
|
||||
|
||||
これは `0.112.0` 以上、`0.113.0` 未満のバージョンを使うことを意味します。例えば、バージョン `0.112.2` は使用可能です。
|
||||
|
||||
`uv`、Poetry、Pipenv など、他のインストール管理ツールを使用している場合でも、いずれもパッケージの特定バージョンを定義する方法があります。
|
||||
|
||||
## 利用可能なバージョン { #available-versions }
|
||||
|
||||
利用可能なバージョン(例: 現在の最新が何かを確認するため)は、[Release Notes](../release-notes.md){.internal-link target=_blank} で確認できます。
|
||||
|
||||
## バージョンについて { #about-versions }
|
||||
|
||||
セマンティック バージョニングの規約に従って、`1.0.0` 未満のバージョンは破壊的な変更が加わる可能性があります。
|
||||
|
||||
FastAPI では「PATCH」バージョンの変更はバグ修正と非破壊的な変更に使う、という規約にも従っています。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
「PATCH」は最後の数字です。例えば、`0.2.3` では PATCH バージョンは `3` です。
|
||||
|
||||
///
|
||||
|
||||
従って、以下のようなバージョンの固定ができるはずです:
|
||||
または、以下の様に固定することもできます:
|
||||
|
||||
```txt
|
||||
fastapi>=0.45.0,<0.46.0
|
||||
```
|
||||
|
||||
破壊的な変更と新機能は「MINOR」バージョンで追加されます。
|
||||
これは `0.45.0` 以上、`0.46.0` 未満のバージョンを使うことを意味します。例えば、バージョン `0.45.2` は使用可能です。
|
||||
|
||||
PoetryやPipenvなど、他のインストール管理ツールを使用している場合でも、それぞれパッケージのバージョンを指定する機能があります。
|
||||
|
||||
## 利用可能なバージョン
|
||||
|
||||
[Release Notes](../release-notes.md){.internal-link target=_blank}で利用可能なバージョンが確認できます (現在の最新版の確認などのため)。
|
||||
|
||||
## バージョンについて
|
||||
|
||||
セマンティック バージョニングの規約に従って、`1.0.0` 未満の全てのバージョンは破壊的な変更が加わる可能性があります。
|
||||
|
||||
FastAPIでは「パッチ」バージョンはバグ修正と非破壊的な変更に留めるという規約に従っています。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
「MINOR」は真ん中の数字です。例えば、`0.2.3` では MINOR バージョンは `2` です。
|
||||
「パッチ」は最後の数字を指します。例えば、`0.2.3` ではパッチバージョンは `3` です。
|
||||
|
||||
///
|
||||
|
||||
## FastAPIのバージョンのアップグレード { #upgrading-the-fastapi-versions }
|
||||
従って、以下の様なバージョンの固定が望ましいです:
|
||||
|
||||
アプリケーションにテストを追加すべきです。
|
||||
```txt
|
||||
fastapi>=0.45.0,<0.46.0
|
||||
```
|
||||
|
||||
**FastAPI** では非常に簡単に実現できます(Starlette のおかげです)。ドキュメントを確認して下さい: [テスト](../tutorial/testing.md){.internal-link target=_blank}
|
||||
破壊的な変更と新機能実装は「マイナー」バージョンで加えられます。
|
||||
|
||||
テストを追加したら、**FastAPI** のバージョンをより新しいものにアップグレードし、テストを実行することで全てのコードが正しく動作するか確認できます。
|
||||
/// tip | 豆知識
|
||||
|
||||
全てが動作する、または必要な変更を行った後に全てのテストが通るなら、その新しいバージョンに `fastapi` を固定できます。
|
||||
「マイナー」は真ん中の数字です。例えば、`0.2.3` ではマイナーバージョンは `2` です。
|
||||
|
||||
## Starletteについて { #about-starlette }
|
||||
///
|
||||
|
||||
`starlette` のバージョンは固定すべきではありません。
|
||||
## FastAPIのバージョンのアップグレード
|
||||
|
||||
**FastAPI** のバージョンが異なれば、Starlette の特定のより新しいバージョンが使われます。
|
||||
アプリケーションにテストを加えるべきです。
|
||||
|
||||
そのため、正しい Starlette バージョンを **FastAPI** に任せればよいです。
|
||||
**FastAPI** では非常に簡単に実現できます (Starletteのおかげで)。ドキュメントを確認して下さい: [テスト](../tutorial/testing.md){.internal-link target=_blank}
|
||||
|
||||
## Pydanticについて { #about-pydantic }
|
||||
テストを加えた後で、**FastAPI** のバージョンをより最新のものにアップグレードし、テストを実行することで全てのコードが正常に動作するか確認できます。
|
||||
|
||||
Pydantic は自身のテストに **FastAPI** のテストも含んでいるため、Pydantic の新しいバージョン(`1.0.0` より上)は常に FastAPI と互換性があります。
|
||||
全てが動作するか、修正を行った上で全てのテストを通過した場合、使用している`fastapi` のバージョンをより最新のバージョンに固定できます。
|
||||
|
||||
Pydantic は、自分にとって動作する `1.0.0` より上の任意のバージョンに固定できます。
|
||||
## Starletteについて
|
||||
|
||||
`Starlette` のバージョンは固定すべきではありません。
|
||||
|
||||
**FastAPI** は、バージョン毎にStarletteのより新しいバージョンを使用します。
|
||||
|
||||
よって、最適なStarletteのバージョン選択を**FastAPI** に任せることができます。
|
||||
|
||||
## Pydanticについて
|
||||
|
||||
Pydanticは自身のテストだけでなく**FastAPI** のためのテストを含んでいます。なので、Pydanticの新たなバージョン ( `1.0.0` 以降) は全てFastAPIと整合性があります。
|
||||
|
||||
Pydanticのバージョンを、動作が保証できる`1.0.0`以降のいずれかのバージョンから`2.0.0` 未満の間に固定できます。
|
||||
|
||||
例えば:
|
||||
|
||||
```txt
|
||||
pydantic>=2.7.0,<3.0.0
|
||||
pydantic>=1.2.0,<2.0.0
|
||||
```
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
# 環境変数 { #environment-variables }
|
||||
# 環境変数
|
||||
|
||||
/// tip | 豆知識
|
||||
/// tip
|
||||
|
||||
もし、「環境変数」とは何か、それをどう使うかを既に知っている場合は、このセクションをスキップして構いません。
|
||||
|
||||
///
|
||||
|
||||
環境変数(「**env var**」とも呼ばれます)とは、Pythonコードの**外側**、つまり**オペレーティングシステム**に存在する変数で、Pythonコード(または他のプログラム)から読み取れます。
|
||||
環境変数(**env var**とも呼ばれる)はPythonコードの**外側**、つまり**OS**に存在する変数で、Pythonから読み取ることができます。(他のプログラムでも同様に読み取れます。)
|
||||
|
||||
環境変数は、アプリケーションの**設定**の扱い、Pythonの**インストール**の一部などで役立ちます。
|
||||
環境変数は、アプリケーションの**設定**の管理や、Pythonの**インストール**などに役立ちます。
|
||||
|
||||
## 環境変数の作成と使用 { #create-and-use-env-vars }
|
||||
## 環境変数の作成と使用
|
||||
|
||||
環境変数は、Pythonを必要とせず、**シェル(ターミナル)**で**作成**して使用できます。
|
||||
環境変数は**シェル(ターミナル)**内で**作成**して使用でき、それらにPythonは不要です。
|
||||
|
||||
//// tab | Linux, macOS, Windows Bash
|
||||
|
||||
@@ -36,6 +36,7 @@ Hello Wade Wilson
|
||||
|
||||
<div class="termy">
|
||||
|
||||
|
||||
```console
|
||||
// Create an env var MY_NAME
|
||||
$ $Env:MY_NAME = "Wade Wilson"
|
||||
@@ -50,9 +51,9 @@ Hello Wade Wilson
|
||||
|
||||
////
|
||||
|
||||
## Pythonで環境変数を読み取る { #read-env-vars-in-python }
|
||||
## Pythonで環境変数を読み取る
|
||||
|
||||
環境変数はPythonの**外側**(ターミナル、またはその他の方法)で作成し、その後に**Pythonで読み取る**こともできます。
|
||||
環境変数をPythonの**外側**、ターミナル(や他の方法)で作成し、**Python内で読み取る**こともできます。
|
||||
|
||||
例えば、以下のような`main.py`ファイルを用意します:
|
||||
|
||||
@@ -63,11 +64,11 @@ name = os.getenv("MY_NAME", "World")
|
||||
print(f"Hello {name} from Python")
|
||||
```
|
||||
|
||||
/// tip | 豆知識
|
||||
/// tip
|
||||
|
||||
<a href="https://docs.python.org/3.8/library/os.html#os.getenv" class="external-link" target="_blank">`os.getenv()`</a> の第2引数は、デフォルトで返される値です。
|
||||
<a href="https://docs.python.org/3.8/library/os.html#os.getenv" class="external-link" target="_blank">`os.getenv()`</a> の第2引数は、デフォルトで返される値を指定します。
|
||||
|
||||
指定しない場合、デフォルトは`None`ですが、ここでは使用するデフォルト値として`"World"`を指定しています。
|
||||
この引数を省略するとデフォルト値として`None`が返されますが、ここではデフォルト値として`"World"`を指定しています。
|
||||
|
||||
///
|
||||
|
||||
@@ -127,11 +128,11 @@ Hello Wade Wilson from Python
|
||||
|
||||
////
|
||||
|
||||
環境変数はコードの外側で設定でき、コードから読み取れ、他のファイルと一緒に(`git`に)保存(コミット)する必要がないため、設定や**settings**に使うのが一般的です。
|
||||
環境変数はコードの外側で設定し、内側から読み取ることができるので、他のファイルと一緒に(`git`に)保存する必要がありません。そのため、環境変数をコンフィグレーションや**設定**に使用することが一般的です。
|
||||
|
||||
また、**特定のプログラムの呼び出し**のためだけに、そのプログラムでのみ、実行中の間だけ利用できる環境変数を作成することもできます。
|
||||
また、**特定のプログラムの呼び出し**のための環境変数を、そのプログラムのみ、その実行中に限定して利用できるよう作成できます。
|
||||
|
||||
そのためには、同じ行で、プログラム自体の直前に作成してください。
|
||||
そのためには、プログラム起動コマンドと同じコマンドライン上の、起動コマンド直前で環境変数を作成してください。
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -151,25 +152,25 @@ Hello World from Python
|
||||
|
||||
</div>
|
||||
|
||||
/// tip | 豆知識
|
||||
/// tip
|
||||
|
||||
詳しくは <a href="https://12factor.net/config" class="external-link" target="_blank">The Twelve-Factor App: Config</a> を参照してください。
|
||||
|
||||
///
|
||||
|
||||
## 型とバリデーション { #types-and-validation }
|
||||
## 型とバリデーション
|
||||
|
||||
これらの環境変数が扱えるのは**テキスト文字列**のみです。環境変数はPythonの外部にあり、他のプログラムやシステム全体(Linux、Windows、macOSなど異なるオペレーティングシステム間も)との互換性が必要になるためです。
|
||||
環境変数は**テキスト文字列**のみを扱うことができます。これは、環境変数がPython外部に存在し、他のプログラムやシステム全体(Linux、Windows、macOS間の互換性を含む)と連携する必要があるためです。
|
||||
|
||||
つまり、環境変数からPythonで読み取る**あらゆる値**は **`str`になり**、他の型への変換やバリデーションはコード内で行う必要があります。
|
||||
つまり、Pythonが環境変数から読み取る**あらゆる値**は **`str`型となり**、他の型への変換やバリデーションはコード内で行う必要があります。
|
||||
|
||||
環境変数を使って**アプリケーション設定**を扱う方法については、[高度なユーザーガイド - Settings and Environment Variables](./advanced/settings.md){.internal-link target=_blank} で詳しく学べます。
|
||||
環境変数を使用して**アプリケーション設定**を管理する方法については、[高度なユーザーガイド - Settings and Environment Variables](./advanced/settings.md){.internal-link target=_blank}で詳しく学べます。
|
||||
|
||||
## `PATH`環境変数 { #path-environment-variable }
|
||||
## `PATH`環境変数
|
||||
|
||||
**`PATH`**という**特別な**環境変数があります。これはオペレーティングシステム(Linux、macOS、Windows)が実行するプログラムを見つけるために使用されます。
|
||||
**`PATH`**という**特別な**環境変数があります。この環境変数は、OS(Linux、macOS、Windows)が実行するプログラムを発見するために使用されます。
|
||||
|
||||
変数`PATH`の値は長い文字列で、LinuxとmacOSではコロン`:`、Windowsではセミコロン`;`で区切られたディレクトリで構成されます。
|
||||
`PATH`変数は、複数のディレクトリのパスから成る長い文字列です。このパスはLinuxやMacOSの場合は`:`で、Windowsの場合は`;`で区切られています。
|
||||
|
||||
例えば、`PATH`環境変数は次のような文字列かもしれません:
|
||||
|
||||
@@ -179,7 +180,7 @@ Hello World from Python
|
||||
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
|
||||
```
|
||||
|
||||
これは、システムが次のディレクトリでプログラムを探すことを意味します:
|
||||
これは、OSはプログラムを見つけるために以下のディレクトリを探す、ということを意味します:
|
||||
|
||||
* `/usr/local/bin`
|
||||
* `/usr/bin`
|
||||
@@ -195,7 +196,7 @@ Hello World from Python
|
||||
C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32
|
||||
```
|
||||
|
||||
これは、システムが次のディレクトリでプログラムを探すことを意味します:
|
||||
これは、OSはプログラムを見つけるために以下のディレクトリを探す、ということを意味します:
|
||||
|
||||
* `C:\Program Files\Python312\Scripts`
|
||||
* `C:\Program Files\Python312`
|
||||
@@ -203,61 +204,63 @@ C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System3
|
||||
|
||||
////
|
||||
|
||||
ターミナル上で**コマンド**を入力すると、オペレーティングシステムは`PATH`環境変数に記載された**それぞれのディレクトリ**の中からプログラムを**探し**ます。
|
||||
ターミナル上で**コマンド**を入力すると、 OSはそのプログラムを見つけるために、`PATH`環境変数のリストに記載された**それぞれのディレクトリを探し**ます。
|
||||
|
||||
例えば、ターミナルで`python`と入力すると、オペレーティングシステムはそのリストの**最初のディレクトリ**で`python`というプログラムを探します。
|
||||
例えば、ターミナル上で`python`を入力すると、OSは`python`によって呼ばれるプログラムを見つけるために、そのリストの**先頭のディレクトリ**を最初に探します。
|
||||
|
||||
見つかればそれを**使用**します。見つからなければ、**他のディレクトリ**を探し続けます。
|
||||
OSは、もしそのプログラムをそこで発見すれば**実行し**ますが、そうでなければリストの**他のディレクトリ**を探していきます。
|
||||
|
||||
### Pythonのインストールと`PATH`の更新 { #installing-python-and-updating-the-path }
|
||||
### PythonのインストールとPATH環境変数の更新
|
||||
|
||||
Pythonのインストール時に、`PATH`環境変数を更新するかどうかを尋ねられるかもしれません。
|
||||
Pythonのインストール時に`PATH`環境変数を更新したいか聞かれるかもしれません。
|
||||
|
||||
//// tab | Linux, macOS
|
||||
/// tab | Linux, macOS
|
||||
|
||||
Pythonをインストールして、その結果`/opt/custompython/bin`というディレクトリに配置されたとします。
|
||||
Pythonをインストールして、そのプログラムが`/opt/custompython/bin`というディレクトリに配置されたとします。
|
||||
|
||||
`PATH`環境変数を更新することに同意すると、インストーラーは`PATH`環境変数に`/opt/custompython/bin`を追加します。
|
||||
もし、`PATH`環境変数を更新するように答えると、`PATH`環境変数に`/opt/custompython/bin`が追加されます。
|
||||
|
||||
例えば次のようになります:
|
||||
`PATH`環境変数は以下のように更新されるでしょう:
|
||||
|
||||
```plaintext
|
||||
``` plaintext
|
||||
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin
|
||||
```
|
||||
|
||||
このようにして、ターミナルで`python`と入力すると、システムは`/opt/custompython/bin`(最後のディレクトリ)にあるPythonプログラムを見つけ、それを使用します。
|
||||
このようにして、ターミナルで`python`と入力したときに、OSは`/opt/custompython/bin`(リストの末尾のディレクトリ)にあるPythonプログラムを見つけ、使用します。
|
||||
|
||||
////
|
||||
///
|
||||
|
||||
//// tab | Windows
|
||||
/// tab | Windows
|
||||
|
||||
Pythonをインストールして、その結果`C:\opt\custompython\bin`というディレクトリに配置されたとします。
|
||||
Pythonをインストールして、そのプログラムが`C:\opt\custompython\bin`というディレクトリに配置されたとします。
|
||||
|
||||
`PATH`環境変数を更新することに同意すると、インストーラーは`PATH`環境変数に`C:\opt\custompython\bin`を追加します。
|
||||
もし、`PATH`環境変数を更新するように答えると、`PATH`環境変数に`C:\opt\custompython\bin`が追加されます。
|
||||
|
||||
`PATH`環境変数は以下のように更新されるでしょう:
|
||||
|
||||
```plaintext
|
||||
C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32;C:\opt\custompython\bin
|
||||
```
|
||||
|
||||
このようにして、ターミナルで`python`と入力すると、システムは`C:\opt\custompython\bin`(最後のディレクトリ)にあるPythonプログラムを見つけ、それを使用します。
|
||||
このようにして、ターミナルで`python`と入力したときに、OSは`C:\opt\custompython\bin\python`(リストの末尾のディレクトリ)にあるPythonプログラムを見つけ、使用します。
|
||||
|
||||
////
|
||||
///
|
||||
|
||||
つまり、ターミナルで次のように入力すると:
|
||||
つまり、ターミナルで以下のコマンドを入力すると:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
``` console
|
||||
$ python
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
//// tab | Linux, macOS
|
||||
/// tab | Linux, macOS
|
||||
|
||||
システムは`/opt/custompython/bin`にある`python`プログラムを**見つけ**て実行します。
|
||||
OSは`/opt/custompython/bin`にある`python`プログラムを**見つけ**て実行します。
|
||||
|
||||
これは、次のように入力するのとおおむね同等です:
|
||||
これは、次のコマンドを入力した場合とほとんど同等です:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -267,13 +270,13 @@ $ /opt/custompython/bin/python
|
||||
|
||||
</div>
|
||||
|
||||
////
|
||||
///
|
||||
|
||||
//// tab | Windows
|
||||
/// tab | Windows
|
||||
|
||||
システムは`C:\opt\custompython\bin\python`にある`python`プログラムを**見つけ**て実行します。
|
||||
OSは`C:\opt\custompython\bin\python`にある`python`プログラムを**見つけ**て実行します。
|
||||
|
||||
これは、次のように入力するのとおおむね同等です:
|
||||
これは、次のコマンドを入力した場合とほとんど同等です:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -283,16 +286,16 @@ $ C:\opt\custompython\bin\python
|
||||
|
||||
</div>
|
||||
|
||||
////
|
||||
///
|
||||
|
||||
この情報は、[Virtual Environments](virtual-environments.md){.internal-link target=_blank} について学ぶ際にも役立ちます。
|
||||
この情報は、[Virtual Environments](virtual-environments.md) について学ぶ際にも役立ちます。
|
||||
|
||||
## まとめ { #conclusion }
|
||||
## まとめ
|
||||
|
||||
これで、**環境変数**とは何か、Pythonでどのように使用するかについて、基本的な理解が得られたはずです。
|
||||
|
||||
環境変数についての詳細は、<a href="https://en.wikipedia.org/wiki/Environment_variable" class="external-link" target="_blank">Wikipedia for Environment Variable</a> も参照してください。
|
||||
環境変数についての詳細は、<a href="https://en.wikipedia.org/wiki/Environment_variable" class="external-link" target="_blank">Wikipedia: Environment Variable</a> を参照してください。
|
||||
|
||||
多くの場合、環境変数がどのように役立ち、すぐに適用できるのかはあまり明確ではありません。しかし、開発中のさまざまなシナリオで何度も登場するため、知っておくとよいでしょう。
|
||||
環境変数の用途や適用方法が最初は直感的ではないかもしれませんが、開発中のさまざまなシナリオで繰り返し登場します。そのため、基本を知っておくことが重要です。
|
||||
|
||||
例えば、次のセクションの[Virtual Environments](virtual-environments.md)でこの情報が必要になります。
|
||||
たとえば、この情報は次のセクションで扱う[Virtual Environments](virtual-environments.md)にも関連します。
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# 条件付き OpenAPI { #conditional-openapi }
|
||||
# 条件付き OpenAPI
|
||||
|
||||
必要であれば、設定と環境変数を利用して、環境に応じて条件付きでOpenAPIを構成することが可能です。また、完全にOpenAPIを無効にすることもできます。
|
||||
|
||||
## セキュリティとAPI、およびドキュメントについて { #about-security-apis-and-docs }
|
||||
## セキュリティとAPI、およびドキュメントについて
|
||||
|
||||
本番環境においてドキュメントのUIを非表示にすることによって、APIを保護しようと *すべきではありません*。
|
||||
|
||||
@@ -17,19 +17,19 @@
|
||||
* リクエストボディとレスポンスのためのPydanticモデルの定義を見直す。
|
||||
* 依存関係に基づきすべての必要なパーミッションとロールを設定する。
|
||||
* パスワードを絶対に平文で保存しない。パスワードハッシュのみを保存する。
|
||||
* pwdlibやJWTトークンに代表される、よく知られた暗号化ツールを使って実装する。
|
||||
* PasslibやJWTトークンに代表される、よく知られた暗号化ツールを使って実装する。
|
||||
* そして必要なところでは、もっと細かいパーミッション制御をOAuth2スコープを使って行う。
|
||||
* ...など
|
||||
* など
|
||||
|
||||
それでも、例えば本番環境のような特定の環境のみで、あるいは環境変数の設定によってAPIドキュメントをどうしても無効にしたいという、非常に特殊なユースケースがあるかもしれません。
|
||||
|
||||
## 設定と環境変数による条件付き OpenAPI { #conditional-openapi-from-settings-and-env-vars }
|
||||
## 設定と環境変数による条件付き OpenAPI
|
||||
|
||||
生成するOpenAPIとドキュメントUIの構成は、共通のPydanticの設定を使用して簡単に切り替えられます。
|
||||
|
||||
例えば、
|
||||
|
||||
{* ../../docs_src/conditional_openapi/tutorial001_py39.py hl[6,11] *}
|
||||
{* ../../docs_src/conditional_openapi/tutorial001.py hl[6,11] *}
|
||||
|
||||
ここでは `openapi_url` の設定を、デフォルトの `"/openapi.json"` のまま宣言しています。
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# FastAPI { #fastapi }
|
||||
# FastAPI
|
||||
|
||||
<style>
|
||||
.md-content .md-typeset h1 { display: none; }
|
||||
</style>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://fastapi.tiangolo.com/ja"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
|
||||
<a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<em>FastAPI フレームワーク、高パフォーマンス、学びやすい、素早くコーディングできる、本番運用に対応</em>
|
||||
<em>FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster" target="_blank">
|
||||
@@ -27,138 +27,129 @@
|
||||
|
||||
---
|
||||
|
||||
**ドキュメント**: <a href="https://fastapi.tiangolo.com/ja" target="_blank">https://fastapi.tiangolo.com</a>
|
||||
**ドキュメント**: <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a>
|
||||
|
||||
**ソースコード**: <a href="https://github.com/fastapi/fastapi" target="_blank">https://github.com/fastapi/fastapi</a>
|
||||
|
||||
---
|
||||
|
||||
FastAPI は、Python の標準である型ヒントに基づいて Python で API を構築するための、モダンで、高速(高パフォーマンス)な Web フレームワークです。
|
||||
FastAPI は、Pythonの標準である型ヒントに基づいてPython 以降でAPI を構築するための、モダンで、高速(高パフォーマンス)な、Web フレームワークです。
|
||||
|
||||
主な特徴:
|
||||
|
||||
* **高速**: **NodeJS** や **Go** 並みのとても高いパフォーマンス(Starlette と Pydantic のおかげです)。 [利用可能な最も高速な Python フレームワークの一つです](#performance)。
|
||||
* **高速なコーディング**: 開発速度を約 200%〜300% 向上させます。*
|
||||
* **少ないバグ**: 開発者起因のヒューマンエラーを約 40% 削減します。*
|
||||
* **直感的**: 素晴らしいエディタサポート。あらゆる場所で <abbr title="also known as auto-complete, autocompletion, IntelliSense">補完</abbr> が使えます。デバッグ時間を削減します。
|
||||
* **簡単**: 簡単に利用・習得できるようにデザインされています。ドキュメントを読む時間を削減します。
|
||||
* **短い**: コードの重複を最小限にします。各パラメータ宣言から複数の機能を得られます。バグも減ります。
|
||||
* **堅牢性**: 自動対話型ドキュメントにより、本番環境向けのコードが得られます。
|
||||
* **Standards-based**: API のオープンスタンダードに基づいており(そして完全に互換性があります)、<a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a>(以前は Swagger として知られていました)や <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a> をサポートします。
|
||||
- **高速**: **NodeJS** や **Go** 並みのとても高いパフォーマンス (Starlette と Pydantic のおかげです)。 [最も高速な Python フレームワークの一つです](#_10).
|
||||
|
||||
<small>* 本番アプリケーションを構築している社内開発チームのテストに基づく見積もりです。</small>
|
||||
- **高速なコーディング**: 開発速度を約 200%~300%向上させます。 \*
|
||||
- **少ないバグ**: 開発者起因のヒューマンエラーを約 40%削減します。 \*
|
||||
- **直感的**: 素晴らしいエディタのサポートや <abbr title="also known as auto-complete, autocompletion, IntelliSense">オートコンプリート。</abbr> デバッグ時間を削減します。
|
||||
- **簡単**: 簡単に利用、習得できるようにデザインされています。ドキュメントを読む時間を削減します。
|
||||
- **短い**: コードの重複を最小限にしています。各パラメータからの複数の機能。少ないバグ。
|
||||
- **堅牢性**: 自動対話ドキュメントを使用して、本番環境で使用できるコードを取得します。
|
||||
- **Standards-based**: API のオープンスタンダードに基づいており、完全に互換性があります: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (以前は Swagger として知られていました) や <a href="https://json-schema.org/" class="external-link" target="_blank">JSON スキーマ</a>.
|
||||
|
||||
## Sponsors { #sponsors }
|
||||
<small>\* 本番アプリケーションを構築している開発チームのテストによる見積もり。</small>
|
||||
|
||||
## Sponsors
|
||||
|
||||
<!-- sponsors -->
|
||||
|
||||
### Keystone Sponsor { #keystone-sponsor }
|
||||
|
||||
{% for sponsor in sponsors.keystone -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
|
||||
{% endfor -%}
|
||||
|
||||
### Gold and Silver Sponsors { #gold-and-silver-sponsors }
|
||||
|
||||
{% if sponsors %}
|
||||
{% for sponsor in sponsors.gold -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
|
||||
{% endfor -%}
|
||||
{%- for sponsor in sponsors.silver -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<!-- /sponsors -->
|
||||
|
||||
<a href="https://fastapi.tiangolo.com/ja/fastapi-people/#sponsors" class="external-link" target="_blank">その他のスポンサー</a>
|
||||
<a href="https://fastapi.tiangolo.com/fastapi-people/#sponsors" class="external-link" target="_blank">Other sponsors</a>
|
||||
|
||||
## 評価 { #opinions }
|
||||
## 評価
|
||||
|
||||
"_[...] 最近 **FastAPI** を使っています。 [...] 実際に私のチームの全ての **Microsoft の機械学習サービス** で使用する予定です。 そのうちのいくつかのコアな **Windows** 製品と **Office** 製品に統合されつつあります。_"
|
||||
"_[...] 最近 **FastAPI** を使っています。 [...] 実際に私のチームの全ての **Microsoft の機械学習サービス** で使用する予定です。 そのうちのいくつかのコアな**Windows**製品と**Office**製品に統合されつつあります。_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Kabir Khan - <strong>Microsoft</strong> <a href="https://github.com/fastapi/fastapi/pull/26" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_FastAPIライブラリを採用し、クエリで **予測値** を取得できる **REST** サーバを構築しました。 [for Ludwig]_"
|
||||
"_FastAPIライブラリを採用し、クエリで**予測値**を取得できる**REST**サーバを構築しました。 [for Ludwig]_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_**Netflix** は、**危機管理**オーケストレーションフレームワーク、**Dispatch** のオープンソースリリースを発表できることをうれしく思います。 [built with **FastAPI**]_"
|
||||
"_**Netflix** は、**危機管理**オーケストレーションフレームワーク、**Dispatch**のオープンソースリリースを発表できることをうれしく思います。 [built with **FastAPI**]_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href="https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_私は **FastAPI** にワクワクしています。 めちゃくちゃ楽しいです!_"
|
||||
"_私は**FastAPI**にワクワクしています。 めちゃくちゃ楽しいです!_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> podcast host</strong> <a href="https://x.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_正直、あなたが作ったものは超堅実で洗練されているように見えます。いろんな意味で、それは私が **Hug** にそうなってほしかったものです。誰かがそれを作るのを見るのは本当に刺激的です。_"
|
||||
"_正直、超堅実で洗練されているように見えます。いろんな意味で、それは私がハグしたかったものです。_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="https://github.com/hugapi/hug" target="_blank">Hug</a> creator</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_REST API を構築するための **モダンなフレームワーク** を学びたい方は、**FastAPI** [...] をチェックしてみてください。 [...] 高速で、使用・習得が簡単です [...]_"
|
||||
"_REST API を構築するための**モダンなフレームワーク**を学びたい方は、**FastAPI** [...] をチェックしてみてください。 [...] 高速で, 使用、習得が簡単です。[...]_"
|
||||
|
||||
"_私たちの **API** は **FastAPI** に切り替えました [...] きっと気に入ると思います [...]_"
|
||||
"_私たちの**API**は**FastAPI**に切り替えました。[...] きっと気に入ると思います。 [...]_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong><a href="https://explosion.ai" target="_blank">Explosion AI</a> founders - <a href="https://spacy.io" target="_blank">spaCy</a> creators</strong> <a href="https://x.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://x.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_本番運用の Python API を構築したい方には、**FastAPI** を強くおすすめします。**美しく設計**されており、**使いやすく**、**高いスケーラビリティ**があります。私たちの API ファースト開発戦略の **主要コンポーネント** となり、Virtual TAC Engineer などの多くの自動化やサービスを推進しています。_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Deon Pillsbury - <strong>Cisco</strong> <a href="https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
## FastAPI ミニドキュメンタリー { #fastapi-mini-documentary }
|
||||
|
||||
2025 年末に公開された <a href="https://www.youtube.com/watch?v=mpR8ngthqiE" class="external-link" target="_blank">FastAPI ミニドキュメンタリー</a>があります。オンラインで視聴できます:
|
||||
|
||||
<a href="https://www.youtube.com/watch?v=mpR8ngthqiE" target="_blank"><img src="https://fastapi.tiangolo.com/img/fastapi-documentary.jpg" alt="FastAPI Mini Documentary"></a>
|
||||
|
||||
## **Typer**、CLI 版 FastAPI { #typer-the-fastapi-of-clis }
|
||||
## **Typer**, the FastAPI of CLIs
|
||||
|
||||
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
|
||||
|
||||
Web API の代わりにターミナルで使用する <abbr title="Command Line Interface">CLI</abbr> アプリを構築する場合は、<a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a> を確認してください。
|
||||
もし Web API の代わりにターミナルで使用する<abbr title="Command Line Interface">CLI</abbr>アプリを構築する場合は、<a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>を確認してください。
|
||||
|
||||
**Typer** は FastAPI の弟分です。そして、**CLI 版 FastAPI** を意図しています。 ⌨️ 🚀
|
||||
**Typer**は FastAPI の弟分です。そして、**CLI 版 の FastAPI**を意味しています。
|
||||
|
||||
## 必要条件 { #requirements }
|
||||
## 必要条件
|
||||
|
||||
FastAPI は巨人の肩の上に立っています。
|
||||
|
||||
* Web の部分は <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a>
|
||||
* データの部分は <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>
|
||||
- Web の部分は<a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a>
|
||||
- データの部分は<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>
|
||||
|
||||
## インストール { #installation }
|
||||
|
||||
<a href="https://fastapi.tiangolo.com/ja/virtual-environments/" class="external-link" target="_blank">virtual environment</a> を作成して有効化し、それから FastAPI をインストールします。
|
||||
## インストール
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install "fastapi[standard]"
|
||||
$ pip install fastapi
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
**注**: すべてのターミナルで動作するように、`"fastapi[standard]"` は必ずクォートで囲んでください。
|
||||
本番環境では、<a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a> または、 <a href="https://github.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>のような、 ASGI サーバーが必要になります。
|
||||
|
||||
## アプリケーション例 { #example }
|
||||
<div class="termy">
|
||||
|
||||
### 作成 { #create-it }
|
||||
```console
|
||||
$ pip install "uvicorn[standard]"
|
||||
|
||||
`main.py` ファイルを作成し、以下のコードを入力します。
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## アプリケーション例
|
||||
|
||||
### アプリケーションの作成
|
||||
|
||||
- `main.py` を作成し、以下のコードを入力します:
|
||||
|
||||
```Python
|
||||
from fastapi import FastAPI
|
||||
@@ -172,16 +163,16 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
def read_item(item_id: int, q: str = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
<details markdown="1">
|
||||
<summary>または <code>async def</code> を使います...</summary>
|
||||
<summary>または<code>async def</code>を使います...</summary>
|
||||
|
||||
コードで `async` / `await` を使用する場合は、`async def` を使います。
|
||||
`async` / `await`を使用するときは、 `async def`を使います:
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
```Python hl_lines="7 12"
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -193,41 +184,28 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: str | None = None):
|
||||
async def read_item(item_id: int, q: str = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
**注**:
|
||||
|
||||
わからない場合は、<a href="https://fastapi.tiangolo.com/ja/async/#in-a-hurry" target="_blank">ドキュメントの `async` と `await` の _"In a hurry?"_ セクション</a>を確認してください。
|
||||
わからない場合は、<a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">ドキュメントの`async` と `await`にある</a>"In a hurry?"セクションをチェックしてください。
|
||||
|
||||
</details>
|
||||
|
||||
### 実行 { #run-it }
|
||||
### 実行
|
||||
|
||||
以下のコマンドでサーバーを起動します。
|
||||
以下のコマンドでサーバーを起動します:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi dev main.py
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
╭────────── FastAPI CLI - Development mode ───────────╮
|
||||
│ │
|
||||
│ Serving at: http://127.0.0.1:8000 │
|
||||
│ │
|
||||
│ API docs: http://127.0.0.1:8000/docs │
|
||||
│ │
|
||||
│ Running in development mode, for production use: │
|
||||
│ │
|
||||
│ fastapi run │
|
||||
│ │
|
||||
╰─────────────────────────────────────────────────────╯
|
||||
|
||||
INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
|
||||
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
INFO: Started reloader process [2248755] using WatchFiles
|
||||
INFO: Started server process [2248757]
|
||||
INFO: Started reloader process [28720]
|
||||
INFO: Started server process [28722]
|
||||
INFO: Waiting for application startup.
|
||||
INFO: Application startup complete.
|
||||
```
|
||||
@@ -235,56 +213,56 @@ INFO: Application startup complete.
|
||||
</div>
|
||||
|
||||
<details markdown="1">
|
||||
<summary><code>fastapi dev main.py</code> コマンドについて</summary>
|
||||
<summary><code>uvicorn main:app --reload</code>コマンドについて</summary>
|
||||
|
||||
`fastapi dev` コマンドは `main.py` ファイルを読み取り、その中の **FastAPI** アプリを検出し、<a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a> を使用してサーバーを起動します。
|
||||
`uvicorn main:app`コマンドは以下の項目を参照します:
|
||||
|
||||
デフォルトでは、`fastapi dev` はローカル開発向けに自動リロードを有効にして起動します。
|
||||
|
||||
詳しくは <a href="https://fastapi.tiangolo.com/ja/fastapi-cli/" target="_blank">FastAPI CLI docs</a> を参照してください。
|
||||
- `main`: `main.py`ファイル (Python "モジュール")
|
||||
- `app`: `main.py` の`app = FastAPI()`の行で生成されたオブジェクト
|
||||
- `--reload`: コードを変更したらサーバーを再起動します。このオプションは開発環境でのみ使用します
|
||||
|
||||
</details>
|
||||
|
||||
### 動作確認 { #check-it }
|
||||
### 動作確認
|
||||
|
||||
ブラウザで <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a> を開きます。
|
||||
ブラウザから<a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>を開きます。
|
||||
|
||||
以下の JSON のレスポンスが確認できます。
|
||||
以下の JSON のレスポンスが確認できます:
|
||||
|
||||
```JSON
|
||||
{"item_id": 5, "q": "somequery"}
|
||||
```
|
||||
|
||||
すでに以下の API が作成されています。
|
||||
もうすでに以下の API が作成されています:
|
||||
|
||||
* _パス_ `/` と `/items/{item_id}` で HTTP リクエストを受け取ります。
|
||||
* 両方の _パス_ は `GET` <em>操作</em>(HTTP _メソッド_ としても知られています)を取ります。
|
||||
* _パス_ `/items/{item_id}` は `int` であるべき _パスパラメータ_ `item_id` を持ちます。
|
||||
* _パス_ `/items/{item_id}` はオプションの `str` _クエリパラメータ_ `q` を持ちます。
|
||||
- `/` と `/items/{item_id}`のパスで HTTP リクエストを受けます。
|
||||
- どちらのパスも `GET` <em>操作</em> を取ります。(HTTP メソッドとしても知られています。)
|
||||
- `/items/{item_id}` パスのパスパラメータ `item_id` は `int` でなければなりません。
|
||||
- パス `/items/{item_id}` はオプションの `str` クエリパラメータ `q` を持ちます。
|
||||
|
||||
### 自動対話型 API ドキュメント { #interactive-api-docs }
|
||||
### 自動対話型の API ドキュメント
|
||||
|
||||
次に、<a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> にアクセスします。
|
||||
<a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>にアクセスしてみてください。
|
||||
|
||||
自動対話型 API ドキュメントが表示されます(<a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a> が提供しています)。
|
||||
自動対話型の API ドキュメントが表示されます。 (<a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>が提供しています。):
|
||||
|
||||

|
||||
|
||||
### 代替 API ドキュメント { #alternative-api-docs }
|
||||
### 代替の API ドキュメント
|
||||
|
||||
次に、<a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> にアクセスします。
|
||||
<a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>にアクセスしてみてください。
|
||||
|
||||
代替の自動ドキュメントが表示されます(<a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a> が提供しています)。
|
||||
代替の自動ドキュメントが表示されます。(<a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>が提供しています。):
|
||||
|
||||

|
||||
|
||||
## アップグレード例 { #example-upgrade }
|
||||
## アップグレード例
|
||||
|
||||
次に、`PUT` リクエストからボディを受け取るために `main.py` ファイルを修正しましょう。
|
||||
`PUT`リクエストからボディを受け取るために`main.py`を修正しましょう。
|
||||
|
||||
Pydantic によって、標準的な Python の型を使ってボディを宣言します。
|
||||
Pydantic によって、Python の標準的な型を使ってボディを宣言します。
|
||||
|
||||
```Python hl_lines="2 7-10 23-25"
|
||||
```Python hl_lines="2 7 8 9 10 23 24 25"
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -294,7 +272,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: bool | None = None
|
||||
is_offer: bool = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -303,7 +281,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
def read_item(item_id: int, q: str = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
@@ -312,248 +290,173 @@ def update_item(item_id: int, item: Item):
|
||||
return {"item_name": item.name, "item_id": item_id}
|
||||
```
|
||||
|
||||
`fastapi dev` サーバーは自動でリロードされるはずです。
|
||||
サーバーは自動でリロードされます。(上述の`uvicorn`コマンドで`--reload`オプションを追加しているからです。)
|
||||
|
||||
### 自動対話型 API ドキュメントのアップグレード { #interactive-api-docs-upgrade }
|
||||
### 自動対話型の API ドキュメントのアップグレード
|
||||
|
||||
次に、<a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> にアクセスします。
|
||||
<a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>にアクセスしましょう。
|
||||
|
||||
* 自動対話型 API ドキュメントは新しいボディも含めて自動でアップデートされます。
|
||||
- 自動対話型の API ドキュメントが新しいボディも含めて自動でアップデートされます:
|
||||
|
||||

|
||||
|
||||
* 「Try it out」ボタンをクリックします。パラメータを入力して API と直接やりとりできます。
|
||||
- "Try it out"ボタンをクリックしてください。パラメータを入力して API と直接やりとりすることができます:
|
||||
|
||||

|
||||
|
||||
* 次に、「Execute」ボタンをクリックします。ユーザーインターフェースは API と通信し、パラメータを送信し、結果を取得して画面に表示します。
|
||||
- それから、"Execute" ボタンをクリックしてください。 ユーザーインターフェースは API と通信し、パラメータを送信し、結果を取得して画面に表示します:
|
||||
|
||||

|
||||
|
||||
### 代替 API ドキュメントのアップグレード { #alternative-api-docs-upgrade }
|
||||
### 代替の API ドキュメントのアップグレード
|
||||
|
||||
次に、<a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> にアクセスします。
|
||||
<a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>にアクセスしましょう。
|
||||
|
||||
* 代替のドキュメントにも新しいクエリパラメータやボディが反映されます。
|
||||
- 代替の API ドキュメントにも新しいクエリパラメータやボディが反映されます。
|
||||
|
||||

|
||||
|
||||
### まとめ { #recap }
|
||||
### まとめ
|
||||
|
||||
要約すると、関数のパラメータとして、パラメータやボディなどの型を **一度だけ** 宣言します。
|
||||
要約すると、関数のパラメータとして、パラメータやボディ などの型を**一度だけ**宣言します。
|
||||
|
||||
標準的な最新の Python の型を使います。
|
||||
標準的な最新の Python の型を使っています。
|
||||
|
||||
新しい構文や特定のライブラリのメソッドやクラスなどを覚える必要はありません。
|
||||
|
||||
単なる標準的な **Python** です。
|
||||
単なる標準的な**3.8 以降の Python**です。
|
||||
|
||||
例えば、`int` の場合:
|
||||
例えば、`int`の場合:
|
||||
|
||||
```Python
|
||||
item_id: int
|
||||
```
|
||||
|
||||
または、より複雑な `Item` モデルの場合:
|
||||
または、より複雑な`Item`モデルの場合:
|
||||
|
||||
```Python
|
||||
item: Item
|
||||
```
|
||||
|
||||
...そして、この一度の宣言で、以下のようになります。
|
||||
...そして、この一度の宣言で、以下のようになります:
|
||||
|
||||
* 以下を含むエディタサポート:
|
||||
* 補完。
|
||||
* 型チェック。
|
||||
* データの検証:
|
||||
* データが無効な場合に自動で明確なエラーを返します。
|
||||
* 深い入れ子になった JSON オブジェクトでも検証が可能です。
|
||||
* 入力データの <abbr title="also known as: serialization, parsing, marshalling">変換</abbr>: ネットワークから Python のデータや型へ。以下から読み取ります:
|
||||
* JSON。
|
||||
* パスパラメータ。
|
||||
* クエリパラメータ。
|
||||
* Cookie。
|
||||
* ヘッダー。
|
||||
* フォーム。
|
||||
* ファイル。
|
||||
* 出力データの <abbr title="also known as: serialization, parsing, marshalling">変換</abbr>: Python のデータや型からネットワークデータへ(JSON として)変換します:
|
||||
* Python の型(`str`、`int`、`float`、`bool`、`list` など)の変換。
|
||||
* `datetime` オブジェクト。
|
||||
* `UUID` オブジェクト。
|
||||
* データベースモデル。
|
||||
* ...などなど。
|
||||
* 2 つの代替ユーザーインターフェースを含む自動対話型 API ドキュメント:
|
||||
* Swagger UI。
|
||||
* ReDoc。
|
||||
- 以下を含むエディタサポート:
|
||||
- 補完
|
||||
- タイプチェック
|
||||
- データの検証:
|
||||
- データが無効な場合に自動でエラーをクリアします。
|
||||
- 深い入れ子になった JSON オブジェクトでも検証が可能です。
|
||||
- 入力データの<abbr title="also known as: serialization, parsing, marshalling">変換</abbr>: ネットワークから Python のデータや型に変換してから読み取ります:
|
||||
- JSON.
|
||||
- パスパラメータ
|
||||
- クエリパラメータ
|
||||
- クッキー
|
||||
- ヘッダー
|
||||
- フォーム
|
||||
- ファイル
|
||||
- 出力データの<abbr title="also known as: serialization, parsing, marshalling">変換</abbr>: Python のデータや型からネットワークデータへ変換します (JSON として):
|
||||
- Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc).
|
||||
- `datetime` オブジェクト
|
||||
- `UUID` オブジェクト
|
||||
- データベースモデル
|
||||
- ...などなど
|
||||
- 2 つの代替ユーザーインターフェースを含む自動インタラクティブ API ドキュメント:
|
||||
- Swagger UI.
|
||||
- ReDoc.
|
||||
|
||||
---
|
||||
|
||||
前のコード例に戻ると、**FastAPI** は次のように動作します。
|
||||
コード例に戻りましょう、**FastAPI** は次のようになります:
|
||||
|
||||
* `GET` および `PUT` リクエストのパスに `item_id` があることを検証します。
|
||||
* `GET` および `PUT` リクエストに対して `item_id` が `int` 型であることを検証します。
|
||||
* そうでない場合、クライアントは有用で明確なエラーを受け取ります。
|
||||
* `GET` リクエストに対して、`q` という名前のオプションのクエリパラメータ(`http://127.0.0.1:8000/items/foo?q=somequery` のような)が存在するかどうかを調べます。
|
||||
* `q` パラメータは `= None` で宣言されているため、オプションです。
|
||||
* `None` がなければ必須になります(`PUT` の場合のボディと同様です)。
|
||||
* `PUT` リクエストを `/items/{item_id}` に送信する場合、ボディを JSON として読み込みます:
|
||||
* 必須の属性 `name` があり、`str` であるべきことを確認します。
|
||||
* 必須の属性 `price` があり、`float` でなければならないことを確認します。
|
||||
* オプションの属性 `is_offer` があり、存在する場合は `bool` であるべきことを確認します。
|
||||
* これらはすべて、深くネストされた JSON オブジェクトに対しても動作します。
|
||||
* JSON への/からの変換を自動的に行います。
|
||||
* OpenAPI ですべてを文書化し、以下で利用できます:
|
||||
* 対話型ドキュメントシステム。
|
||||
* 多くの言語に対応した自動クライアントコード生成システム。
|
||||
* 2 つの対話型ドキュメント Web インターフェースを直接提供します。
|
||||
- `GET`および`PUT`リクエストのパスに`item_id` があることを検証します。
|
||||
- `item_id`が`GET`および`PUT`リクエストに対して`int` 型であることを検証します。
|
||||
- そうでない場合は、クライアントは有用で明確なエラーが表示されます。
|
||||
- `GET` リクエストに対してオプションのクエリパラメータ `q` (`http://127.0.0.1:8000/items/foo?q=somequery` のように) が存在するかどうかを調べます。
|
||||
- パラメータ `q` は `= None` で宣言されているので、オプションです。
|
||||
- `None`がなければ必須になります(`PUT`の場合のボディと同様です)。
|
||||
- `PUT` リクエストを `/items/{item_id}` に送信する場合は、ボディを JSON として読み込みます:
|
||||
- 必須の属性 `name` を確認してください。 それは `str` であるべきです。
|
||||
- 必須の属性 `price` を確認してください。それは `float` でなければならないです。
|
||||
- オプションの属性 `is_offer` を確認してください。値がある場合は、`bool` であるべきです。
|
||||
- これらはすべて、深くネストされた JSON オブジェクトに対しても動作します。
|
||||
- JSON から JSON に自動的に変換します。
|
||||
- OpenAPIですべてを文書化し、以下を使用することができます:
|
||||
- 対話的なドキュメントシステム。
|
||||
- 多くの言語に対応した自動クライアントコード生成システム。
|
||||
- 2 つの対話的なドキュメントのWebインターフェイスを直接提供します。
|
||||
|
||||
---
|
||||
|
||||
まだ表面的な部分に触れただけですが、仕組みはすでにイメージできているはずです。
|
||||
まだ表面的な部分に触れただけですが、もう全ての仕組みは分かっているはずです。
|
||||
|
||||
以下の行を変更してみてください。
|
||||
以下の行を変更してみてください:
|
||||
|
||||
```Python
|
||||
return {"item_name": item.name, "item_id": item_id}
|
||||
```
|
||||
|
||||
...以下の:
|
||||
...以下を:
|
||||
|
||||
```Python
|
||||
... "item_name": item.name ...
|
||||
```
|
||||
|
||||
...を:
|
||||
...以下のように:
|
||||
|
||||
```Python
|
||||
... "item_price": item.price ...
|
||||
```
|
||||
|
||||
...に変更し、エディタが属性を自動補完し、その型を知ることを確認してください。
|
||||
...そして、エディタが属性を自動補完し、そのタイプを知る方法を確認してください。:
|
||||
|
||||

|
||||
|
||||
より多くの機能を含む、より完全な例については、<a href="https://fastapi.tiangolo.com/ja/tutorial/">Tutorial - User Guide</a> を参照してください。
|
||||
より多くの機能を含む、より完全な例については、<a href="https://fastapi.tiangolo.com/tutorial/">チュートリアル - ユーザーガイド</a>をご覧ください。
|
||||
|
||||
**ネタバレ注意**: tutorial - user guide には以下が含まれます。
|
||||
**ネタバレ注意**: チュートリアル - ユーザーガイドは以下の情報が含まれています:
|
||||
|
||||
* **ヘッダー**、**Cookie**、**フォームフィールド**、**ファイル**など、他のさまざまな場所からの **パラメータ** 宣言。
|
||||
* `maximum_length` や `regex` のような **検証制約** を設定する方法。
|
||||
* 非常に強力で使いやすい **<abbr title="also known as components, resources, providers, services, injectables">依存性注入</abbr>** システム。
|
||||
* **JWT トークン**を用いた **OAuth2** や **HTTP Basic** 認証のサポートを含む、セキュリティと認証。
|
||||
* **深くネストされた JSON モデル**を宣言するための、より高度な(しかし同様に簡単な)手法(Pydantic のおかげです)。
|
||||
* <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> および他のライブラリによる **GraphQL** 統合。
|
||||
* 以下のようなたくさんのおまけ機能(Starlette のおかげです):
|
||||
* **WebSockets**
|
||||
* HTTPX と `pytest` に基づく極めて簡単なテスト
|
||||
* **CORS**
|
||||
* **Cookie Sessions**
|
||||
* ...などなど。
|
||||
- **ヘッダー**、**クッキー**、**フォームフィールド**、**ファイル**などの他の場所からの **パラメータ** 宣言。
|
||||
- `maximum_length`や`regex`のような**検証や制約**を設定する方法。
|
||||
- 非常に強力で使いやすい <abbr title="also known as components, resources, providers, services, injectables">**依存性注入**</abbr>システム。
|
||||
- **JWT トークン**を用いた **OAuth2** や **HTTP Basic 認証** のサポートを含む、セキュリティと認証。
|
||||
- **深くネストされた JSON モデル**を宣言するためのより高度な(しかし同様に簡単な)技術(Pydantic のおかげです)。
|
||||
- 以下のようなたくさんのおまけ機能(Starlette のおかげです):
|
||||
- **WebSockets**
|
||||
- **GraphQL**
|
||||
- `httpx` や `pytest`をもとにした極限に簡単なテスト
|
||||
- **CORS**
|
||||
- **クッキーセッション**
|
||||
- ...などなど。
|
||||
|
||||
### アプリをデプロイ(任意) { #deploy-your-app-optional }
|
||||
## パフォーマンス
|
||||
|
||||
必要に応じて FastAPI アプリを <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a> にデプロイできます。まだの場合はウェイティングリストに参加してください。 🚀
|
||||
独立した TechEmpower のベンチマークでは、Uvicorn で動作する**FastAPI**アプリケーションが、<a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">Python フレームワークの中で最も高速なものの 1 つ</a>であり、Starlette と Uvicorn(FastAPI で内部的に使用されています)にのみ下回っていると示されています。
|
||||
|
||||
すでに **FastAPI Cloud** アカウント(ウェイティングリストから招待されました 😉)がある場合は、1 コマンドでアプリケーションをデプロイできます。
|
||||
詳細は<a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">ベンチマーク</a>セクションをご覧ください。
|
||||
|
||||
デプロイ前に、ログインしていることを確認してください。
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi login
|
||||
|
||||
You are logged in to FastAPI Cloud 🚀
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
次に、アプリをデプロイします。
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi deploy
|
||||
|
||||
Deploying to FastAPI Cloud...
|
||||
|
||||
✅ Deployment successful!
|
||||
|
||||
🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
これで完了です!その URL でアプリにアクセスできます。 ✨
|
||||
|
||||
#### FastAPI Cloud について { #about-fastapi-cloud }
|
||||
|
||||
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>** は **FastAPI** の作者と同じチームによって作られています。
|
||||
|
||||
最小限の労力で API を **構築**、**デプロイ**、**アクセス** するためのプロセスを効率化します。
|
||||
|
||||
FastAPI でアプリを構築するのと同じ **開発者体験** を、クラウドへの **デプロイ** にももたらします。 🎉
|
||||
|
||||
FastAPI Cloud は *FastAPI and friends* オープンソースプロジェクトの主要スポンサーであり、資金提供元です。 ✨
|
||||
|
||||
#### 他のクラウドプロバイダにデプロイ { #deploy-to-other-cloud-providers }
|
||||
|
||||
FastAPI はオープンソースであり、標準に基づいています。選択した任意のクラウドプロバイダに FastAPI アプリをデプロイできます。
|
||||
|
||||
各クラウドプロバイダのガイドに従って、FastAPI アプリをデプロイしてください。 🤓
|
||||
|
||||
## パフォーマンス { #performance }
|
||||
|
||||
独立した TechEmpower のベンチマークでは、Uvicorn で動作する **FastAPI** アプリケーションが、<a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">利用可能な最も高速な Python フレームワークの一つ</a>であり、Starlette と Uvicorn(FastAPI で内部的に使用されています)にのみ下回っていると示されています。(*)
|
||||
|
||||
詳細は <a href="https://fastapi.tiangolo.com/ja/benchmarks/" class="internal-link" target="_blank">Benchmarks</a> セクションをご覧ください。
|
||||
|
||||
## 依存関係 { #dependencies }
|
||||
|
||||
FastAPI は Pydantic と Starlette に依存しています。
|
||||
|
||||
### `standard` 依存関係 { #standard-dependencies }
|
||||
|
||||
FastAPI を `pip install "fastapi[standard]"` でインストールすると、`standard` グループのオプション依存関係が含まれます。
|
||||
## オプションの依存関係
|
||||
|
||||
Pydantic によって使用されるもの:
|
||||
|
||||
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email-validator</code></a> - メール検証のため。
|
||||
- <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email-validator</code></a> - E メールの検証
|
||||
|
||||
Starlette によって使用されるもの:
|
||||
|
||||
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - `TestClient` を使用したい場合に必要です。
|
||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - デフォルトのテンプレート設定を使用したい場合に必要です。
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - `request.form()` とともに、フォームの <abbr title="converting the string that comes from an HTTP request into Python data">「parsing」</abbr> をサポートしたい場合に必要です。
|
||||
- <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - `TestClient`を使用するために必要です。
|
||||
- <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - デフォルトのテンプレート設定を使用する場合は必要です。
|
||||
- <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>`request.form()`からの変換をサポートしたい場合は必要です。
|
||||
- <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - `SessionMiddleware` サポートのためには必要です。
|
||||
- <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Starlette の `SchemaGenerator` サポートのために必要です。 (FastAPI では必要ないでしょう。)
|
||||
- <a href="https://graphene-python.org/" target="_blank"><code>graphene</code></a> - `GraphQLApp` サポートのためには必要です。
|
||||
|
||||
FastAPI によって使用されるもの:
|
||||
FastAPI / Starlette に使用されるもの:
|
||||
|
||||
* <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> - アプリケーションをロードして提供するサーバーのため。これには `uvicorn[standard]` も含まれ、高性能なサービングに必要な依存関係(例: `uvloop`)が含まれます。
|
||||
* `fastapi-cli[standard]` - `fastapi` コマンドを提供します。
|
||||
* これには `fastapi-cloud-cli` が含まれ、FastAPI アプリケーションを <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a> にデプロイできます。
|
||||
- <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> - アプリケーションをロードしてサーブするサーバーのため。
|
||||
- <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - `ORJSONResponse`を使用したい場合は必要です。
|
||||
- <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - `UJSONResponse`を使用する場合は必須です。
|
||||
|
||||
### `standard` 依存関係なし { #without-standard-dependencies }
|
||||
これらは全て `pip install fastapi[all]`でインストールできます。
|
||||
|
||||
`standard` のオプション依存関係を含めたくない場合は、`pip install "fastapi[standard]"` の代わりに `pip install fastapi` でインストールできます。
|
||||
## ライセンス
|
||||
|
||||
### `fastapi-cloud-cli` なし { #without-fastapi-cloud-cli }
|
||||
|
||||
標準の依存関係を含めつつ `fastapi-cloud-cli` を除外して FastAPI をインストールしたい場合は、`pip install "fastapi[standard-no-fastapi-cloud-cli]"` でインストールできます。
|
||||
|
||||
### 追加のオプション依存関係 { #additional-optional-dependencies }
|
||||
|
||||
追加でインストールしたい依存関係があります。
|
||||
|
||||
追加のオプション Pydantic 依存関係:
|
||||
|
||||
* <a href="https://docs.pydantic.dev/latest/usage/pydantic_settings/" target="_blank"><code>pydantic-settings</code></a> - 設定管理のため。
|
||||
* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - Pydantic で使用する追加の型のため。
|
||||
|
||||
追加のオプション FastAPI 依存関係:
|
||||
|
||||
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - `ORJSONResponse` を使用したい場合に必要です。
|
||||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - `UJSONResponse` を使用したい場合に必要です。
|
||||
|
||||
## ライセンス { #license }
|
||||
|
||||
このプロジェクトは MIT ライセンスの条項の下でライセンスされています。
|
||||
このプロジェクトは MIT ライセンスです。
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# 学習 { #learn }
|
||||
# 学習
|
||||
|
||||
ここでは、**FastAPI** を学習するための入門セクションとチュートリアルを紹介します。
|
||||
|
||||
これは、**書籍**や**コース**、FastAPIを学習するための**公式**かつ推奨される方法とみなすことができます。😎
|
||||
これは、FastAPIを学習するにあたっての**書籍**や**コース**であり、**公式**かつ推奨される方法とみなすことができます 😎
|
||||
|
||||
@@ -1,28 +1,84 @@
|
||||
# Full Stack FastAPI テンプレート { #full-stack-fastapi-template }
|
||||
# プロジェクト生成 - テンプレート
|
||||
|
||||
テンプレートは通常、特定のセットアップが含まれていますが、柔軟でカスタマイズできるように設計されています。これにより、プロジェクトの要件に合わせて変更・適応でき、優れた出発点になります。🏁
|
||||
プロジェクトジェネレーターは、初期設定、セキュリティ、データベース、初期APIエンドポイントなどの多くが含まれているため、プロジェクトの開始に利用できます。
|
||||
|
||||
このテンプレートを使って開始できます。初期セットアップ、セキュリティ、データベース、いくつかのAPIエンドポイントがすでに用意されています。
|
||||
プロジェクトジェネレーターは常に非常に意見が分かれる設定がされており、ニーズに合わせて更新および調整する必要があります。しかしきっと、プロジェクトの良い出発点となるでしょう。
|
||||
|
||||
GitHubリポジトリ: <a href="https://github.com/tiangolo/full-stack-fastapi-template" class="external-link" target="_blank">Full Stack FastAPI Template</a>
|
||||
## フルスタック FastAPI PostgreSQL
|
||||
|
||||
## Full Stack FastAPI テンプレート - 技術スタックと機能 { #full-stack-fastapi-template-technology-stack-and-features }
|
||||
GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-postgresql</a>
|
||||
|
||||
- ⚡ PythonバックエンドAPI向けの [**FastAPI**](https://fastapi.tiangolo.com/ja)。
|
||||
- 🧰 PythonのSQLデータベース操作(ORM)向けの [SQLModel](https://sqlmodel.tiangolo.com)。
|
||||
- 🔍 FastAPIで使用される、データバリデーションと設定管理向けの [Pydantic](https://docs.pydantic.dev)。
|
||||
- 💾 SQLデータベースとしての [PostgreSQL](https://www.postgresql.org)。
|
||||
- 🚀 フロントエンド向けの [React](https://react.dev)。
|
||||
- 💃 TypeScript、hooks、Vite、その他のモダンなフロントエンドスタックの各要素を使用。
|
||||
- 🎨 フロントエンドコンポーネント向けの [Tailwind CSS](https://tailwindcss.com) と [shadcn/ui](https://ui.shadcn.com)。
|
||||
- 🤖 自動生成されたフロントエンドクライアント。
|
||||
- 🧪 End-to-Endテスト向けの [Playwright](https://playwright.dev)。
|
||||
- 🦇 ダークモードのサポート。
|
||||
- 🐋 開発および本番向けの [Docker Compose](https://www.docker.com)。
|
||||
- 🔒 デフォルトでの安全なパスワードハッシュ化。
|
||||
- 🔑 JWT(JSON Web Token)認証。
|
||||
- 📫 メールベースのパスワードリカバリ。
|
||||
- ✅ [Pytest](https://pytest.org) によるテスト。
|
||||
- 📞 リバースプロキシ / ロードバランサとしての [Traefik](https://traefik.io)。
|
||||
- 🚢 Docker Composeを使用したデプロイ手順(自動HTTPS証明書を処理するフロントエンドTraefikプロキシのセットアップ方法を含む)。
|
||||
- 🏭 GitHub Actionsに基づくCI(continuous integration)とCD(continuous deployment)。
|
||||
### フルスタック FastAPI PostgreSQL - 機能
|
||||
|
||||
* 完全な**Docker**インテグレーション (Dockerベース)。
|
||||
* Docker Swarm モードデプロイ。
|
||||
* ローカル開発環境向けの**Docker Compose**インテグレーションと最適化。
|
||||
* UvicornとGunicornを使用した**リリース可能な** Python web サーバ。
|
||||
* Python <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">**FastAPI**</a> バックエンド:
|
||||
* **高速**: **NodeJS** や **Go** 並みのとても高いパフォーマンス (Starlette と Pydantic のおかげ)。
|
||||
* **直感的**: 素晴らしいエディタのサポートや <abbr title="自動補完、インテリセンスとも呼ばれる">補完。</abbr> デバッグ時間の短縮。
|
||||
* **簡単**: 簡単に利用、習得できるようなデザイン。ドキュメントを読む時間を削減。
|
||||
* **短い**: コードの重複を最小限に。パラメータ宣言による複数の機能。
|
||||
* **堅牢性**: 自動対話ドキュメントを使用した、本番環境で使用できるコード。
|
||||
* **標準規格準拠**: API のオープンスタンダードに基く、完全な互換性: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a>や <a href="http://json-schema.org/" class="external-link" target="_blank">JSON スキーマ</a>。
|
||||
* 自動バリデーション、シリアライゼーション、対話的なドキュメント、OAuth2 JWTトークンを用いた認証などを含む、<a href="https://fastapi.tiangolo.com/features/" class="external-link" target="_blank">**その他多くの機能**</a>。
|
||||
* **セキュアなパスワード** ハッシュ化 (デフォルトで)。
|
||||
* **JWTトークン** 認証。
|
||||
* **SQLAlchemy** モデル (Flask用の拡張と独立しているので、Celeryワーカーと直接的に併用できます)。
|
||||
* 基本的なユーザーモデル (任意の修正や削除が可能)。
|
||||
* **Alembic** マイグレーション。
|
||||
* **CORS** (Cross Origin Resource Sharing (オリジン間リソース共有))。
|
||||
* **Celery** ワーカー。バックエンドの残りの部分からモデルとコードを選択的にインポートし、使用可能。
|
||||
* Dockerと統合された**Pytest**ベースのRESTバックエンドテスト。データベースに依存せずに、全てのAPIをテスト可能。Docker上で動作するので、毎回ゼロから新たなデータストアを構築可能。(ElasticSearch、MongoDB、CouchDBなどを使用して、APIの動作をテスト可能)
|
||||
* Atom HydrogenやVisual Studio Code Jupyterなどの拡張機能を使用した、リモートまたはDocker開発用の**Jupyterカーネル**との簡単なPython統合。
|
||||
* **Vue** フロントエンド:
|
||||
* Vue CLIにより生成。
|
||||
* **JWT認証**の処理。
|
||||
* ログインビュー。
|
||||
* ログイン後の、メインダッシュボードビュー。
|
||||
* メインダッシュボードでのユーザー作成と編集。
|
||||
* セルフユーザー版
|
||||
* **Vuex**。
|
||||
* **Vue-router**。
|
||||
* 美しいマテリアルデザインコンポーネントのための**Vuetify**。
|
||||
* **TypeScript**。
|
||||
* **Nginx**ベースのDockerサーバ (Vue-routerとうまく協調する構成)。
|
||||
* Dockerマルチステージビルド。コンパイルされたコードの保存やコミットが不要。
|
||||
* ビルド時にフロントエンドテスト実行 (無効化も可能)。
|
||||
* 可能な限りモジュール化されているのでそのまま使用できますが、Vue CLIで再生成したり、必要に応じて作成したりして、必要なものを再利用可能。
|
||||
* PostgreSQLデータベースのための**PGAdmin**。(PHPMyAdminとMySQLを使用できるように簡単に変更可能)
|
||||
* Celeryジョブ監視のための**Flower**。
|
||||
* **Traefik**を使用してフロントエンドとバックエンド間をロードバランシング。同一ドメインに配置しパスで区切る、ただし、異なるコンテナで処理。
|
||||
* Traefik統合。Let's Encrypt **HTTPS**証明書の自動生成を含む。
|
||||
* GitLab **CI** (継続的インテグレーション)。フロントエンドおよびバックエンドテストを含む。
|
||||
|
||||
## フルスタック FastAPI Couchbase
|
||||
|
||||
GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-couchbase" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-couchbase</a>
|
||||
|
||||
⚠️ **警告** ⚠️
|
||||
|
||||
ゼロから新規プロジェクトを始める場合は、ここで代替案を確認してください。
|
||||
|
||||
例えば、<a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" class="external-link" target="_blank">フルスタック FastAPI PostgreSQL</a>のプロジェクトジェネレーターは、積極的にメンテナンスされ、利用されているのでより良い代替案かもしれません。また、すべての新機能と改善点が含まれています。
|
||||
|
||||
Couchbaseベースのジェネレーターは今も無償提供されています。恐らく正常に動作するでしょう。また、すでにそのジェネレーターで生成されたプロジェクトが存在する場合でも (ニーズに合わせてアップデートしているかもしれません)、同様に正常に動作するはずです。
|
||||
|
||||
詳細はレポジトリのドキュメントを参照して下さい。
|
||||
|
||||
## フルスタック FastAPI MongoDB
|
||||
|
||||
...時間の都合等によっては、今後作成されるかもしれません。😅 🎉
|
||||
|
||||
## spaCyとFastAPIを使用した機械学習モデル
|
||||
|
||||
GitHub: <a href="https://github.com/microsoft/cookiecutter-spacy-fastapi" class="external-link" target="_blank">https://github.com/microsoft/cookiecutter-spacy-fastapi</a>
|
||||
|
||||
### spaCyとFastAPIを使用した機械学習モデル - 機能
|
||||
|
||||
* **spaCy** のNERモデルの統合。
|
||||
* **Azure Cognitive Search** のリクエストフォーマットを搭載。
|
||||
* **リリース可能な** UvicornとGunicornを使用したPythonウェブサーバ。
|
||||
* **Azure DevOps** のKubernetes (AKS) CI/CD デプロイを搭載。
|
||||
* **多言語** プロジェクトのために、セットアップ時に言語を容易に選択可能 (spaCyに組み込まれている言語の中から)。
|
||||
* **簡単に拡張可能**。spaCyだけでなく、他のモデルフレームワーク (Pytorch、Tensorflow) へ。
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# Pythonの型の紹介 { #python-types-intro }
|
||||
# Pythonの型の紹介
|
||||
|
||||
Pythonではオプションの「型ヒント」(「型アノテーション」とも呼ばれます)がサポートされています。
|
||||
**Python 3.6以降** では「型ヒント」オプションがサポートされています。
|
||||
|
||||
これらの **「型ヒント」** またはアノテーションは、変数の<abbr title="for example: str, int, float, bool">型</abbr>を宣言できる特別な構文です。
|
||||
これらの **"型ヒント"** は変数の<abbr title="例: str, int, float, bool">型</abbr>を宣言することができる新しい構文です。(Python 3.6以降)
|
||||
|
||||
変数に型を宣言することで、エディターやツールがより良いサポートを提供できます。
|
||||
変数に型を宣言することでエディターやツールがより良いサポートを提供することができます。
|
||||
|
||||
これはPythonの型ヒントについての **クイックチュートリアル/リフレッシュ** にすぎません。**FastAPI** で使用するために必要な最低限のことだけをカバーしています。...実際には本当に少ないです。
|
||||
ここではPythonの型ヒントについての **クイックチュートリアル/リフレッシュ** で、**FastAPI**でそれらを使用するために必要な最低限のことだけをカバーしています。...実際には本当に少ないです。
|
||||
|
||||
**FastAPI** はすべてこれらの型ヒントに基づいており、多くの強みと利点を与えてくれます。
|
||||
|
||||
しかし、たとえ **FastAPI** をまったく使用しない場合でも、それらについて少し学ぶことで利点を得られます。
|
||||
しかしたとえまったく **FastAPI** を使用しない場合でも、それらについて少し学ぶことで利点を得ることができるでしょう。
|
||||
|
||||
/// note | 備考
|
||||
|
||||
@@ -18,13 +18,14 @@ Pythonではオプションの「型ヒント」(「型アノテーション
|
||||
|
||||
///
|
||||
|
||||
## 動機 { #motivation }
|
||||
## 動機
|
||||
|
||||
簡単な例から始めてみましょう:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial001_py39.py *}
|
||||
{* ../../docs_src/python_types/tutorial001.py *}
|
||||
|
||||
このプログラムを呼び出すと、以下が出力されます:
|
||||
|
||||
このプログラムを実行すると以下が出力されます:
|
||||
|
||||
```
|
||||
John Doe
|
||||
@@ -34,11 +35,12 @@ John Doe
|
||||
|
||||
* `first_name`と`last_name`を取得します。
|
||||
* `title()`を用いて、それぞれの最初の文字を大文字に変換します。
|
||||
* 真ん中にスペースを入れて<abbr title="Puts them together, as one. With the contents of one after the other.">連結</abbr>します。
|
||||
* 真ん中にスペースを入れて<abbr title="次から次へと中身を入れて一つにまとめる">連結</abbr>します。
|
||||
|
||||
{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *}
|
||||
{* ../../docs_src/python_types/tutorial001.py hl[2] *}
|
||||
|
||||
### 編集 { #edit-it }
|
||||
|
||||
### 編集
|
||||
|
||||
これはとても簡単なプログラムです。
|
||||
|
||||
@@ -48,7 +50,7 @@ John Doe
|
||||
|
||||
しかし、そうすると「最初の文字を大文字に変換するあのメソッド」を呼び出す必要があります。
|
||||
|
||||
それは`upper`でしたか?`uppercase`でしたか?`first_uppercase`?`capitalize`?
|
||||
それは`upper`でしたか?`uppercase`でしたか?それとも`first_uppercase`?または`capitalize`?
|
||||
|
||||
そして、古くからプログラマーの友人であるエディタで自動補完を試してみます。
|
||||
|
||||
@@ -56,13 +58,13 @@ John Doe
|
||||
|
||||
しかし、悲しいことに、これはなんの役にも立ちません:
|
||||
|
||||
<img src="/img/python-types/image01.png">
|
||||
<img src="https://fastapi.tiangolo.com/img/python-types/image01.png">
|
||||
|
||||
### 型の追加 { #add-types }
|
||||
### 型の追加
|
||||
|
||||
先ほどのコードから一行変更してみましょう。
|
||||
|
||||
関数のパラメータである次の断片を、以下から:
|
||||
以下の関数のパラメータ部分を:
|
||||
|
||||
```Python
|
||||
first_name, last_name
|
||||
@@ -78,7 +80,8 @@ John Doe
|
||||
|
||||
それが「型ヒント」です:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *}
|
||||
{* ../../docs_src/python_types/tutorial002.py hl[1] *}
|
||||
|
||||
|
||||
これは、以下のようにデフォルト値を宣言するのと同じではありません:
|
||||
|
||||
@@ -92,39 +95,41 @@ John Doe
|
||||
|
||||
そして、通常、型ヒントを追加しても、それらがない状態と起こることは何も変わりません。
|
||||
|
||||
しかし今、あなたが再びその関数を作成している最中に、型ヒントを使っていると想像してみてください。
|
||||
しかし今、あなたが再びその関数を作成している最中に、型ヒントを使っていると想像してみて下さい。
|
||||
|
||||
同じタイミングで`Ctrl+Space`で自動補完を実行すると、以下のようになります:
|
||||
|
||||
<img src="/img/python-types/image02.png">
|
||||
<img src="https://fastapi.tiangolo.com/img/python-types/image02.png">
|
||||
|
||||
これであれば、あなたは「ベルを鳴らす」ものを見つけるまで、オプションを見てスクロールできます:
|
||||
これであれば、あなたは「ベルを鳴らす」一つを見つけるまで、オプションを見て、スクロールすることができます:
|
||||
|
||||
<img src="/img/python-types/image03.png">
|
||||
<img src="https://fastapi.tiangolo.com/img/python-types/image03.png">
|
||||
|
||||
## より強い動機 { #more-motivation }
|
||||
## より強い動機
|
||||
|
||||
この関数を見てください。すでに型ヒントを持っています:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *}
|
||||
{* ../../docs_src/python_types/tutorial003.py hl[1] *}
|
||||
|
||||
エディタは変数の型を知っているので、補完だけでなく、エラーチェックをすることもできます:
|
||||
|
||||
<img src="/img/python-types/image04.png">
|
||||
エディタは変数の型を知っているので、補完だけでなく、エラーチェックをすることもできます。
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/python-types/image04.png">
|
||||
|
||||
これで`age`を`str(age)`で文字列に変換して修正する必要があることがわかります:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *}
|
||||
{* ../../docs_src/python_types/tutorial004.py hl[2] *}
|
||||
|
||||
## 型の宣言 { #declaring-types }
|
||||
|
||||
型ヒントを宣言する主な場所を見てきました。関数のパラメータです。
|
||||
## 型の宣言
|
||||
|
||||
関数のパラメータとして、型ヒントを宣言している主な場所を確認しました。
|
||||
|
||||
これは **FastAPI** で使用する主な場所でもあります。
|
||||
|
||||
### 単純な型 { #simple-types }
|
||||
### 単純な型
|
||||
|
||||
`str`だけでなく、Pythonの標準的な型すべてを宣言できます。
|
||||
`str`だけでなく、Pythonの標準的な型すべてを宣言することができます。
|
||||
|
||||
例えば、以下を使用可能です:
|
||||
|
||||
@@ -133,47 +138,40 @@ John Doe
|
||||
* `bool`
|
||||
* `bytes`
|
||||
|
||||
{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *}
|
||||
{* ../../docs_src/python_types/tutorial005.py hl[1] *}
|
||||
|
||||
### 型パラメータを持つジェネリック型 { #generic-types-with-type-parameters }
|
||||
|
||||
データ構造の中には、`dict`、`list`、`set`、`tuple`のように他の値を含むことができるものがあります。また内部の値も独自の型を持つことができます。
|
||||
### 型パラメータを持つジェネリック型
|
||||
|
||||
内部の型を持つこれらの型は「**generic**」型と呼ばれます。そして、内部の型も含めて宣言することが可能です。
|
||||
データ構造の中には、`dict`、`list`、`set`、そして`tuple`のように他の値を含むことができるものがあります。また内部の値も独自の型を持つことができます。
|
||||
|
||||
これらの型や内部の型を宣言するには、Pythonの標準モジュール`typing`を使用できます。これらの型ヒントをサポートするために特別に存在しています。
|
||||
これらの型や内部の型を宣言するには、Pythonの標準モジュール`typing`を使用します。
|
||||
|
||||
#### 新しいPythonバージョン { #newer-versions-of-python }
|
||||
これらの型ヒントをサポートするために特別に存在しています。
|
||||
|
||||
`typing`を使う構文は、Python 3.6から最新バージョンまで(Python 3.9、Python 3.10などを含む)すべてのバージョンと **互換性** があります。
|
||||
|
||||
Pythonが進化するにつれ、**新しいバージョン** ではこれらの型アノテーションへのサポートが改善され、多くの場合、型アノテーションを宣言するために`typing`モジュールをインポートして使う必要すらなくなります。
|
||||
|
||||
プロジェクトでより新しいPythonバージョンを選べるなら、その追加のシンプルさを活用できます。
|
||||
|
||||
ドキュメント全体で、Pythonの各バージョンと互換性のある例(差分がある場合)を示しています。
|
||||
|
||||
例えば「**Python 3.6+**」はPython 3.6以上(3.7、3.8、3.9、3.10などを含む)と互換性があることを意味します。また「**Python 3.9+**」はPython 3.9以上(3.10などを含む)と互換性があることを意味します。
|
||||
|
||||
**最新のPythonバージョン** を使えるなら、最新バージョン向けの例を使ってください。例えば「**Python 3.10+**」のように、それらは **最良かつ最もシンプルな構文** になります。
|
||||
|
||||
#### List { #list }
|
||||
#### `List`
|
||||
|
||||
例えば、`str`の`list`の変数を定義してみましょう。
|
||||
|
||||
同じコロン(`:`)の構文で変数を宣言します。
|
||||
`typing`から`List`をインポートします(大文字の`L`を含む):
|
||||
|
||||
型として、`list`を指定します。
|
||||
{* ../../docs_src/python_types/tutorial006.py hl[1] *}
|
||||
|
||||
リストはいくつかの内部の型を含む型なので、それらを角括弧で囲みます:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *}
|
||||
同じようにコロン(`:`)の構文で変数を宣言します。
|
||||
|
||||
/// info | 情報
|
||||
型として、`List`を入力します。
|
||||
|
||||
リストはいくつかの内部の型を含む型なので、それらを角括弧で囲んでいます。
|
||||
|
||||
{* ../../docs_src/python_types/tutorial006.py hl[4] *}
|
||||
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
角括弧内の内部の型は「型パラメータ」と呼ばれています。
|
||||
|
||||
この場合、`str`は`list`に渡される型パラメータです。
|
||||
この場合、`str`は`List`に渡される型パラメータです。
|
||||
|
||||
///
|
||||
|
||||
@@ -181,203 +179,86 @@ Pythonが進化するにつれ、**新しいバージョン** ではこれらの
|
||||
|
||||
そうすることで、エディタはリストの項目を処理している間にもサポートを提供できます。
|
||||
|
||||
<img src="/img/python-types/image05.png">
|
||||
<img src="https://fastapi.tiangolo.com/img/python-types/image05.png">
|
||||
|
||||
型がなければ、それはほぼ不可能です。
|
||||
タイプがなければ、それはほぼ不可能です。
|
||||
|
||||
変数`item`はリスト`items`の要素の一つであることに注意してください。
|
||||
|
||||
それでも、エディタはそれが`str`であることを知っていて、そのためのサポートを提供しています。
|
||||
|
||||
#### Tuple と Set { #tuple-and-set }
|
||||
#### `Tuple` と `Set`
|
||||
|
||||
`tuple`と`set`の宣言も同様です:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *}
|
||||
{* ../../docs_src/python_types/tutorial007.py hl[1,4] *}
|
||||
|
||||
|
||||
つまり:
|
||||
|
||||
* 変数`items_t`は`int`、別の`int`、`str`の3つの項目を持つ`tuple`です。
|
||||
* 変数`items_s`は`set`であり、その各項目は`bytes`型です。
|
||||
* 変数`items_t`は`int`、`int`、`str`の3つの項目を持つ`tuple`です
|
||||
|
||||
#### Dict { #dict }
|
||||
* 変数`items_s`はそれぞれの項目が`bytes`型である`set`です。
|
||||
|
||||
`dict`を定義するには、カンマ区切りで2つの型パラメータを渡します。
|
||||
#### `Dict`
|
||||
|
||||
`dict`を宣言するためには、カンマ区切りで2つの型パラメータを渡します。
|
||||
|
||||
最初の型パラメータは`dict`のキーです。
|
||||
|
||||
2番目の型パラメータは`dict`の値です:
|
||||
2番目の型パラメータは`dict`の値です。
|
||||
|
||||
{* ../../docs_src/python_types/tutorial008.py hl[1,4] *}
|
||||
|
||||
{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *}
|
||||
|
||||
つまり:
|
||||
|
||||
* 変数`prices`は`dict`です:
|
||||
* この`dict`のキーは`str`型です(例えば、各項目の名前)。
|
||||
* この`dict`の値は`float`型です(例えば、各項目の価格)。
|
||||
* 変数`prices`は`dict`であり:
|
||||
* この`dict`のキーは`str`型です。(つまり、各項目の名前)
|
||||
* この`dict`の値は`float`型です。(つまり、各項目の価格)
|
||||
|
||||
#### Union { #union }
|
||||
#### `Optional`
|
||||
|
||||
変数が**複数の型のいずれか**になり得ることを宣言できます。例えば、`int`または`str`です。
|
||||
また、`Optional`を使用して、変数が`str`のような型を持つことを宣言することもできますが、それは「オプション」であり、`None`にすることもできます。
|
||||
|
||||
Python 3.6以上(Python 3.10を含む)では、`typing`の`Union`型を使い、角括弧の中に受け付ける可能性のある型を入れられます。
|
||||
|
||||
Python 3.10では、受け付ける可能性のある型を<abbr title='also called "bitwise or operator", but that meaning is not relevant here'>縦棒(`|`)</abbr>で区切って書ける **新しい構文** もあります。
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!> ../../docs_src/python_types/tutorial008b_py310.py!}
|
||||
```Python hl_lines="1 4"
|
||||
{!../../docs_src/python_types/tutorial009.py!}
|
||||
```
|
||||
|
||||
////
|
||||
ただの`str`の代わりに`Optional[str]`を使用することで、エディタは値が常に`str`であると仮定している場合に実際には`None`である可能性があるエラーを検出するのに役立ちます。
|
||||
|
||||
//// tab | Python 3.9+
|
||||
#### ジェネリック型
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
{!> ../../docs_src/python_types/tutorial008b_py39.py!}
|
||||
```
|
||||
以下のように角括弧で型パラメータを取る型を:
|
||||
|
||||
////
|
||||
|
||||
どちらの場合も、`item`は`int`または`str`になり得ることを意味します。
|
||||
|
||||
#### `None`の可能性 { #possibly-none }
|
||||
|
||||
値が`str`のような型を持つ可能性がある一方で、`None`にもなり得ることを宣言できます。
|
||||
|
||||
Python 3.6以上(Python 3.10を含む)では、`typing`モジュールから`Optional`をインポートして使うことで宣言できます。
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
{!../../docs_src/python_types/tutorial009_py39.py!}
|
||||
```
|
||||
|
||||
ただの`str`の代わりに`Optional[str]`を使用することで、値が常に`str`であると仮定しているときに、実際には`None`である可能性もあるというエラーをエディタが検出するのに役立ちます。
|
||||
|
||||
`Optional[Something]`は実際には`Union[Something, None]`のショートカットで、両者は等価です。
|
||||
|
||||
これは、Python 3.10では`Something | None`も使えることを意味します:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!> ../../docs_src/python_types/tutorial009_py310.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
{!> ../../docs_src/python_types/tutorial009_py39.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+ alternative
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
{!> ../../docs_src/python_types/tutorial009b_py39.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
#### `Union`または`Optional`の使用 { #using-union-or-optional }
|
||||
|
||||
Python 3.10未満のバージョンを使っている場合、これは私のとても **主観的** な観点からのヒントです:
|
||||
|
||||
* 🚨 `Optional[SomeType]`は避けてください
|
||||
* 代わりに ✨ **`Union[SomeType, None]`を使ってください** ✨
|
||||
|
||||
どちらも等価で、内部的には同じですが、`Optional`より`Union`をおすすめします。というのも「**optional**」という単語は値がオプションであることを示唆するように見えますが、実際には「`None`になり得る」という意味であり、オプションではなく必須である場合でもそうだからです。
|
||||
|
||||
`Union[SomeType, None]`のほうが意味がより明示的だと思います。
|
||||
|
||||
これは言葉や名前の話にすぎません。しかし、その言葉はあなたやチームメイトがコードをどう考えるかに影響し得ます。
|
||||
|
||||
例として、この関数を見てみましょう:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *}
|
||||
|
||||
パラメータ`name`は`Optional[str]`として定義されていますが、**オプションではありません**。そのパラメータなしで関数を呼び出せません:
|
||||
|
||||
```Python
|
||||
say_hi() # Oh, no, this throws an error! 😱
|
||||
```
|
||||
|
||||
`name`パラメータはデフォルト値がないため、**依然として必須**(*optional*ではない)です。それでも、`name`は値として`None`を受け付けます:
|
||||
|
||||
```Python
|
||||
say_hi(name=None) # This works, None is valid 🎉
|
||||
```
|
||||
|
||||
良い知らせとして、Python 3.10になればその心配は不要です。型のユニオンを定義するために`|`を単純に使えるからです:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *}
|
||||
|
||||
そして、`Optional`や`Union`のような名前について心配する必要もなくなります。😎
|
||||
|
||||
#### ジェネリック型 { #generic-types }
|
||||
|
||||
角括弧で型パラメータを取るこれらの型は、例えば次のように **Generic types** または **Generics** と呼ばれます:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
同じ組み込み型をジェネリクスとして(角括弧と内部の型で)使えます:
|
||||
|
||||
* `list`
|
||||
* `tuple`
|
||||
* `set`
|
||||
* `dict`
|
||||
|
||||
また、これまでのPythonバージョンと同様に、`typing`モジュールから:
|
||||
|
||||
* `Union`
|
||||
* `List`
|
||||
* `Tuple`
|
||||
* `Set`
|
||||
* `Dict`
|
||||
* `Optional`
|
||||
* ...and others.
|
||||
* ...など
|
||||
|
||||
Python 3.10では、ジェネリクスの`Union`や`Optional`を使う代替として、型のユニオンを宣言するために<abbr title='also called "bitwise or operator", but that meaning is not relevant here'>縦棒(`|`)</abbr>を使えます。これはずっと良く、よりシンプルです。
|
||||
**ジェネリック型** または **ジェネリクス** と呼びます。
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+
|
||||
|
||||
同じ組み込み型をジェネリクスとして(角括弧と内部の型で)使えます:
|
||||
|
||||
* `list`
|
||||
* `tuple`
|
||||
* `set`
|
||||
* `dict`
|
||||
|
||||
そして`typing`モジュールのジェネリクス:
|
||||
|
||||
* `Union`
|
||||
* `Optional`
|
||||
* ...and others.
|
||||
|
||||
////
|
||||
|
||||
### 型としてのクラス { #classes-as-types }
|
||||
### 型としてのクラス
|
||||
|
||||
変数の型としてクラスを宣言することもできます。
|
||||
|
||||
名前を持つ`Person`クラスがあるとしましょう:
|
||||
例えば、`Person`クラスという名前のクラスがあるとしましょう:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *}
|
||||
{* ../../docs_src/python_types/tutorial010.py hl[1,2,3] *}
|
||||
|
||||
変数を`Person`型として宣言できます:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *}
|
||||
変数の型を`Person`として宣言することができます:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial010.py hl[6] *}
|
||||
|
||||
|
||||
そして、再び、すべてのエディタのサポートを得ることができます:
|
||||
|
||||
<img src="/img/python-types/image06.png">
|
||||
<img src="https://fastapi.tiangolo.com/img/python-types/image06.png">
|
||||
|
||||
これは「`one_person`はクラス`Person`の**インスタンス**である」ことを意味します。
|
||||
|
||||
「`one_person`は`Person`という名前の**クラス**である」という意味ではありません。
|
||||
|
||||
## Pydanticのモデル { #pydantic-models }
|
||||
## Pydanticのモデル
|
||||
|
||||
<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> はデータ検証を行うためのPythonライブラリです。
|
||||
|
||||
@@ -385,17 +266,18 @@ Python 3.10では、ジェネリクスの`Union`や`Optional`を使う代替と
|
||||
|
||||
そして、それぞれの属性は型を持ちます。
|
||||
|
||||
さらに、いくつかの値を持つクラスのインスタンスを作成すると、その値を検証し、適切な型に変換して(もしそうであれば)すべてのデータを持つオブジェクトを提供してくれます。
|
||||
さらに、いくつかの値を持つクラスのインスタンスを作成すると、その値を検証し、適切な型に変換して(もしそうであれば)全てのデータを持つオブジェクトを提供してくれます。
|
||||
|
||||
また、その結果のオブジェクトですべてのエディタのサポートを受けることができます。
|
||||
|
||||
Pydanticの公式ドキュメントからの例:
|
||||
Pydanticの公式ドキュメントから引用:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial011.py *}
|
||||
|
||||
{* ../../docs_src/python_types/tutorial011_py310.py *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydanticの詳細はドキュメントを参照してください</a>。
|
||||
Pydanticについてより学びたい方は<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">ドキュメントを参照してください</a>.
|
||||
|
||||
///
|
||||
|
||||
@@ -403,62 +285,30 @@ Pydanticの公式ドキュメントからの例:
|
||||
|
||||
すべてのことは[チュートリアル - ユーザーガイド](tutorial/index.md){.internal-link target=_blank}で実際に見ることができます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
Pydanticには、デフォルト値なしで`Optional`または`Union[Something, None]`を使った場合の特別な挙動があります。詳細はPydanticドキュメントの<a href="https://docs.pydantic.dev/2.3/usage/models/#required-fields" class="external-link" target="_blank">Required Optional fields</a>を参照してください。
|
||||
|
||||
///
|
||||
|
||||
## メタデータアノテーション付き型ヒント { #type-hints-with-metadata-annotations }
|
||||
|
||||
Pythonには、`Annotated`を使って型ヒントに**追加の<abbr title="Data about the data, in this case, information about the type, e.g. a description.">メタデータ</abbr>**を付与できる機能もあります。
|
||||
|
||||
Python 3.9以降、`Annotated`は標準ライブラリの一部なので、`typing`からインポートできます。
|
||||
|
||||
{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *}
|
||||
|
||||
Python自体は、この`Annotated`で何かをするわけではありません。また、エディタや他のツールにとっても、型は依然として`str`です。
|
||||
|
||||
しかし、`Annotated`内のこのスペースを使って、アプリケーションをどのように動作させたいかについての追加メタデータを **FastAPI** に提供できます。
|
||||
|
||||
覚えておくべき重要な点は、`Annotated`に渡す**最初の*型パラメータ***が**実際の型**であることです。残りは、他のツール向けのメタデータにすぎません。
|
||||
|
||||
今のところは、`Annotated`が存在し、それが標準のPythonであることを知っておけば十分です。😎
|
||||
|
||||
後で、これがどれほど**強力**になり得るかを見ることになります。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
これが **標準のPython** であるという事実は、エディタで、使用しているツール(コードの解析やリファクタリングなど)とともに、**可能な限り最高の開発体験**が得られることを意味します。 ✨
|
||||
|
||||
また、あなたのコードが他の多くのPythonツールやライブラリとも非常に互換性が高いことも意味します。 🚀
|
||||
|
||||
///
|
||||
|
||||
## **FastAPI**での型ヒント { #type-hints-in-fastapi }
|
||||
## **FastAPI**での型ヒント
|
||||
|
||||
**FastAPI** はこれらの型ヒントを利用していくつかのことを行います。
|
||||
|
||||
**FastAPI** では型ヒントを使ってパラメータを宣言すると以下のものが得られます:
|
||||
**FastAPI** では型ヒントを使って型パラメータを宣言すると以下のものが得られます:
|
||||
|
||||
* **エディタサポート**。
|
||||
* **型チェック**。
|
||||
* **エディタサポート**.
|
||||
* **型チェック**.
|
||||
|
||||
...そして **FastAPI** は同じ宣言を使って、以下のことを行います:
|
||||
...そして **FastAPI** は同じように宣言をすると、以下のことを行います:
|
||||
|
||||
* **要件の定義**: リクエストのパスパラメータ、クエリパラメータ、ヘッダー、ボディ、依存関係などから要件を定義します。
|
||||
* **データの変換**: リクエストから必要な型にデータを変換します。
|
||||
* **データの検証**: 各リクエストから来るデータについて:
|
||||
* **要件の定義**: リクエストパスパラメータ、クエリパラメータ、ヘッダー、ボディ、依存関係などから要件を定義します。
|
||||
* **データの変換**: リクエストのデータを必要な型に変換します。
|
||||
* **データの検証**: リクエストごとに:
|
||||
* データが無効な場合にクライアントに返される **自動エラー** を生成します。
|
||||
* OpenAPIを使用してAPIを**ドキュメント化**します:
|
||||
* これは自動の対話型ドキュメントのユーザーインターフェイスで使われます。
|
||||
* **ドキュメント** OpenAPIを使用したAPI:
|
||||
* 自動的に対話型ドキュメントのユーザーインターフェイスで使用されます。
|
||||
|
||||
すべてが抽象的に聞こえるかもしれません。心配しないでください。 この全ての動作は [チュートリアル - ユーザーガイド](tutorial/index.md){.internal-link target=_blank}で見ることができます。
|
||||
|
||||
重要なのは、Pythonの標準的な型を使うことで、(クラスやデコレータなどを追加するのではなく)1つの場所で **FastAPI** が多くの作業を代わりにやってくれているということです。
|
||||
重要なのは、Pythonの標準的な型を使うことで、(クラスやデコレータなどを追加するのではなく)1つの場所で **FastAPI** が多くの作業を代わりにやってくれているということです。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
すでにすべてのチュートリアルを終えて、型についての詳細を見るためにこのページに戻ってきた場合は、良いリソースとして<a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">`mypy`の「チートシート」</a>があります。
|
||||
すでにすべてのチュートリアルを終えて、型についての詳細を見るためにこのページに戻ってきた場合は、<a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">`mypy`のチートシートを参照してください</a>
|
||||
|
||||
///
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# バックグラウンドタスク { #background-tasks }
|
||||
# バックグラウンドタスク
|
||||
|
||||
レスポンスを返した *後に* 実行されるバックグラウンドタスクを定義できます。
|
||||
|
||||
@@ -9,17 +9,17 @@
|
||||
* 作業実行後のメール通知:
|
||||
* メールサーバーへの接続とメールの送信は「遅い」(数秒) 傾向があるため、すぐにレスポンスを返し、バックグラウンドでメール通知ができます。
|
||||
* データ処理:
|
||||
* たとえば、時間のかかる処理を必要とするファイル受信時には、「Accepted」(HTTP 202) のレスポンスを返し、バックグラウンドで処理できます。
|
||||
* たとえば、時間のかかる処理を必要とするファイル受信時には、「受信済み」(HTTP 202) のレスポンスを返し、バックグラウンドで処理できます。
|
||||
|
||||
## `BackgroundTasks` の使用 { #using-backgroundtasks }
|
||||
## `BackgroundTasks` の使用
|
||||
|
||||
まず初めに、`BackgroundTasks` をインポートし、`BackgroundTasks` の型宣言と共に、*path operation function* のパラメーターを定義します:
|
||||
まず初めに、`BackgroundTasks` をインポートし、` BackgroundTasks` の型宣言と共に、*path operation 関数* のパラメーターを定義します:
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *}
|
||||
{* ../../docs_src/background_tasks/tutorial001.py hl[1,13] *}
|
||||
|
||||
**FastAPI** は、`BackgroundTasks` 型のオブジェクトを作成し、そのパラメーターに渡します。
|
||||
|
||||
## タスク関数の作成 { #create-a-task-function }
|
||||
## タスク関数の作成
|
||||
|
||||
バックグラウンドタスクとして実行される関数を作成します。
|
||||
|
||||
@@ -31,13 +31,13 @@
|
||||
|
||||
また、書き込み操作では `async` と `await` を使用しないため、通常の `def` で関数を定義します。
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *}
|
||||
{* ../../docs_src/background_tasks/tutorial001.py hl[6:9] *}
|
||||
|
||||
## バックグラウンドタスクの追加 { #add-the-background-task }
|
||||
## バックグラウンドタスクの追加
|
||||
|
||||
*path operation function* 内で、`.add_task()` メソッドを使用してタスク関数を *background tasks* オブジェクトに渡します。
|
||||
*path operations 関数* 内で、`.add_task()` メソッドを使用してタスク関数を *background tasks* オブジェクトに渡します。
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *}
|
||||
{* ../../docs_src/background_tasks/tutorial001.py hl[14] *}
|
||||
|
||||
`.add_task()` は以下の引数を受け取ります:
|
||||
|
||||
@@ -45,42 +45,40 @@
|
||||
* タスク関数に順番に渡す必要のある引数の列 (`email`)。
|
||||
* タスク関数に渡す必要のあるキーワード引数 (`message="some notification"`)。
|
||||
|
||||
## 依存性注入 { #dependency-injection }
|
||||
## 依存性注入
|
||||
|
||||
`BackgroundTasks` の使用は依存性注入システムでも機能し、様々な階層 (*path operation function*、依存性 (dependable)、サブ依存性など) で `BackgroundTasks` 型のパラメーターを宣言できます。
|
||||
`BackgroundTasks` の使用は依存性注入システムでも機能し、様々な階層 (*path operations 関数*、依存性 (依存可能性)、サブ依存性など) で `BackgroundTasks` 型のパラメーターを宣言できます。
|
||||
|
||||
**FastAPI** は、それぞれの場合の処理方法と同じオブジェクトの再利用方法を知っているため、すべてのバックグラウンドタスクがマージされ、バックグラウンドで後で実行されます:
|
||||
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}
|
||||
**FastAPI** は、それぞれの場合の処理方法と同じオブジェクトの再利用方法を知っているため、すべてのバックグラウンドタスクがマージされ、バックグラウンドで後で実行されます。
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial002.py hl[13,15,22,25] *}
|
||||
|
||||
この例では、レスポンスが送信された *後* にメッセージが `log.txt` ファイルに書き込まれます。
|
||||
|
||||
リクエストにクエリがあった場合、バックグラウンドタスクでログに書き込まれます。
|
||||
|
||||
そして、*path operation function* で生成された別のバックグラウンドタスクは、`email` パスパラメータを使用してメッセージを書き込みます。
|
||||
そして、*path operations 関数* で生成された別のバックグラウンドタスクは、`email` パスパラメータを使用してメッセージを書き込みます。
|
||||
|
||||
## 技術的な詳細 { #technical-details }
|
||||
## 技術的な詳細
|
||||
|
||||
`BackgroundTasks` クラスは、<a href="https://www.starlette.dev/background/" class="external-link" target="_blank">`starlette.background`</a>から直接取得されます。
|
||||
|
||||
これは、FastAPI に直接インポート/インクルードされるため、`fastapi` からインポートできる上に、`starlette.background`から別の `BackgroundTask` (末尾に `s` がない) を誤ってインポートすることを回避できます。
|
||||
|
||||
`BackgroundTasks`のみを使用することで (`BackgroundTask` ではなく)、`Request` オブジェクトを直接使用する場合と同様に、それを *path operation function* パラメーターとして使用し、**FastAPI** に残りの処理を任せることができます。
|
||||
`BackgroundTasks`のみを使用することで (`BackgroundTask` ではなく)、`Request` オブジェクトを直接使用する場合と同様に、それを *path operations 関数* パラメーターとして使用し、**FastAPI** に残りの処理を任せることができます。
|
||||
|
||||
それでも、FastAPI で `BackgroundTask` を単独で使用することは可能ですが、コード内でオブジェクトを作成し、それを含むStarlette `Response` を返す必要があります。
|
||||
|
||||
詳細については、<a href="https://www.starlette.dev/background/" class="external-link" target="_blank">Starlette のバックグラウンドタスクに関する公式ドキュメント</a>を参照して下さい。
|
||||
詳細については、<a href="https://www.starlette.dev/background/" class="external-link" target="_blank">バックグラウンドタスクに関する Starlette の公式ドキュメント</a>を参照して下さい。
|
||||
|
||||
## 注意 { #caveat }
|
||||
## 警告
|
||||
|
||||
大量のバックグラウンド計算が必要であり、必ずしも同じプロセスで実行する必要がない場合 (たとえば、メモリや変数などを共有する必要がない場合)、<a href="https://docs.celeryq.dev" class="external-link" target="_blank">Celery</a> のようなより大きな他のツールを使用するとメリットがあるかもしれません。
|
||||
大量のバックグラウンド計算が必要であり、必ずしも同じプロセスで実行する必要がない場合 (たとえば、メモリや変数などを共有する必要がない場合)、<a href="https://www.celeryproject.org/" class="external-link" target="_blank">Celery</a> のようなより大きな他のツールを使用するとメリットがあるかもしれません。
|
||||
|
||||
これらは、より複雑な構成、RabbitMQ や Redis などのメッセージ/ジョブキューマネージャーを必要とする傾向がありますが、複数のプロセス、特に複数のサーバーでバックグラウンドタスクを実行できます。
|
||||
|
||||
ただし、同じ **FastAPI** アプリから変数とオブジェクトにアクセスする必要がある場合、または小さなバックグラウンドタスク (電子メール通知の送信など) を実行する必要がある場合は、単に `BackgroundTasks` を使用できます。
|
||||
|
||||
## まとめ { #recap }
|
||||
## まとめ
|
||||
|
||||
*path operation functions* と依存性のパラメータで `BackgroundTasks`をインポートして使用し、バックグラウンドタスクを追加して下さい。
|
||||
`BackgroundTasks` をインポートして、*path operations 関数* や依存関係のパラメータに `BackgroundTasks`を使用し、バックグラウンドタスクを追加して下さい。
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
# ボディ - フィールド { #body-fields }
|
||||
# ボディ - フィールド
|
||||
|
||||
`Query`や`Path`、`Body`を使って *path operation関数* のパラメータに追加のバリデーションやメタデータを宣言するのと同じように、Pydanticの`Field`を使ってPydanticモデルの内部でバリデーションやメタデータを宣言することができます。
|
||||
|
||||
## `Field`のインポート { #import-field }
|
||||
## `Field`のインポート
|
||||
|
||||
まず、以下のようにインポートします:
|
||||
|
||||
{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}
|
||||
|
||||
{* ../../docs_src/body_fields/tutorial001.py hl[4] *}
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
@@ -15,11 +14,11 @@
|
||||
|
||||
///
|
||||
|
||||
## モデルの属性の宣言 { #declare-model-attributes }
|
||||
## モデルの属性の宣言
|
||||
|
||||
以下のように`Field`をモデルの属性として使用することができます:
|
||||
|
||||
{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}
|
||||
{* ../../docs_src/body_fields/tutorial001.py hl[11,12,13,14] *}
|
||||
|
||||
`Field`は`Query`や`Path`、`Body`と同じように動作し、全く同様のパラメータなどを持ちます。
|
||||
|
||||
@@ -41,20 +40,13 @@
|
||||
|
||||
///
|
||||
|
||||
## 追加情報の追加 { #add-extra-information }
|
||||
## 追加情報の追加
|
||||
|
||||
追加情報は`Field`や`Query`、`Body`などで宣言することができます。そしてそれは生成されたJSONスキーマに含まれます。
|
||||
|
||||
後に例を用いて宣言を学ぶ際に、追加情報を追加する方法を学べます。
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
`Field`に渡された追加のキーは、結果として生成されるアプリケーションのOpenAPIスキーマにも含まれます。
|
||||
これらのキーは必ずしもOpenAPI仕様の一部であるとは限らないため、例えば[OpenAPI validator](https://validator.swagger.io/)などの一部のOpenAPIツールは、生成されたスキーマでは動作しない場合があります。
|
||||
|
||||
///
|
||||
|
||||
## まとめ { #recap }
|
||||
## まとめ
|
||||
|
||||
Pydanticの`Field`を使用して、モデルの属性に追加のバリデーションやメタデータを宣言することができます。
|
||||
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
# ボディ - 複数のパラメータ { #body-multiple-parameters }
|
||||
# ボディ - 複数のパラメータ
|
||||
|
||||
これまで`Path`と`Query`をどう使うかを見てきましたが、リクエストボディ宣言のより高度な使い方を見てみましょう。
|
||||
これまで`Path`と`Query`をどう使うかを見てきましたが、リクエストボディの宣言のより高度な使い方を見てみましょう。
|
||||
|
||||
## `Path`、`Query`とボディパラメータを混ぜる { #mix-path-query-and-body-parameters }
|
||||
## `Path`、`Query`とボディパラメータを混ぜる
|
||||
|
||||
まず、もちろん、`Path`と`Query`とリクエストボディのパラメータ宣言は自由に混ぜることができ、 **FastAPI** は何をするべきかを知っています。
|
||||
まず、もちろん、`Path`と`Query`とリクエストボディのパラメータの宣言は自由に混ぜることができ、 **FastAPI** は何をするべきかを知っています。
|
||||
|
||||
また、デフォルトを`None`に設定することで、ボディパラメータをオプションとして宣言することもできます:
|
||||
また、デフォルトの`None`を設定することで、ボディパラメータをオプションとして宣言することもできます:
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}
|
||||
{* ../../docs_src/body_multiple_params/tutorial001.py hl[19,20,21] *}
|
||||
|
||||
/// note | 備考
|
||||
|
||||
この場合、ボディから取得する`item`はオプションであることに注意してください。デフォルト値が`None`になっているためです。
|
||||
この場合、ボディから取得する`item`はオプションであることに注意してください。デフォルト値は`None`です。
|
||||
|
||||
///
|
||||
|
||||
## 複数のボディパラメータ { #multiple-body-parameters }
|
||||
## 複数のボディパラメータ
|
||||
|
||||
上述の例では、*path operations*は`Item`の属性を持つ以下のようなJSONボディを期待していました:
|
||||
上述の例では、*path operations*は`item`の属性を持つ以下のようなJSONボディを期待していました:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -31,12 +31,11 @@
|
||||
|
||||
しかし、`item`と`user`のように複数のボディパラメータを宣言することもできます:
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}
|
||||
{* ../../docs_src/body_multiple_params/tutorial002.py hl[22] *}
|
||||
|
||||
この場合、**FastAPI**は関数内に複数のボディパラメータ(Pydanticモデルである2つのパラメータ)があることに気付きます。
|
||||
|
||||
この場合、**FastAPI**は関数内に複数のボディパラメータがあることに気付きます(Pydanticモデルである2つのパラメータがあります)。
|
||||
|
||||
そのため、パラメータ名をボディのキー(フィールド名)として使用し、以下のようなボディを期待します:
|
||||
そのため、パラメータ名をボディのキー(フィールド名)として使用し、以下のようなボディを期待しています:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -63,7 +62,7 @@
|
||||
|
||||
複合データの検証を行い、OpenAPIスキーマや自動ドキュメントのように文書化してくれます。
|
||||
|
||||
## ボディ内の単数値 { #singular-values-in-body }
|
||||
## ボディ内の単数値
|
||||
|
||||
クエリとパスパラメータの追加データを定義するための `Query` と `Path` があるのと同じように、 **FastAPI** は同等の `Body` を提供します。
|
||||
|
||||
@@ -73,11 +72,12 @@
|
||||
|
||||
しかし、`Body`を使用して、**FastAPI** に別のボディキーとして扱うように指示することができます:
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial003.py hl[23] *}
|
||||
|
||||
この場合、**FastAPI** は以下のようなボディを期待します:
|
||||
|
||||
|
||||
```JSON
|
||||
{
|
||||
"item": {
|
||||
@@ -96,48 +96,41 @@
|
||||
|
||||
繰り返しになりますが、データ型の変換、検証、文書化などを行います。
|
||||
|
||||
## 複数のボディパラメータとクエリ { #multiple-body-params-and-query }
|
||||
## 複数のボディパラメータとクエリ
|
||||
|
||||
もちろん、ボディパラメータに加えて、必要に応じて追加のクエリパラメータを宣言することもできます。
|
||||
|
||||
デフォルトでは、単数値はクエリパラメータとして解釈されるので、明示的に `Query` を追加する必要はなく、次のようにできます:
|
||||
デフォルトでは、単数値はクエリパラメータとして解釈されるので、明示的に `Query` を追加する必要はありません。
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
またはPython 3.10以上では:
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
例えば:
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
`Body`もまた、後述する `Query` や `Path` などと同様に、すべての追加検証パラメータとメタデータパラメータを持っています。
|
||||
|
||||
///
|
||||
|
||||
## 単一のボディパラメータの埋め込み { #embed-a-single-body-parameter }
|
||||
|
||||
Pydanticモデル`Item`の単一の`item`ボディパラメータしかないとしましょう。
|
||||
|
||||
デフォルトでは、**FastAPI**はそのボディを直接期待します。
|
||||
|
||||
しかし、追加のボディパラメータを宣言したときのように、キー `item` を持つ JSON と、その中のモデル内容を期待したい場合は、特別な `Body` パラメータ `embed` を使うことができます:
|
||||
|
||||
```Python
|
||||
item: Item = Body(embed=True)
|
||||
q: str = None
|
||||
```
|
||||
|
||||
以下において:
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}
|
||||
{* ../../docs_src/body_multiple_params/tutorial004.py hl[27] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
`Body`もまた、後述する `Query` や `Path` などと同様に、すべての検証パラメータとメタデータパラメータを持っています。
|
||||
|
||||
///
|
||||
|
||||
## 単一のボディパラメータの埋め込み
|
||||
|
||||
Pydanticモデル`Item`のボディパラメータ`item`を1つだけ持っているとしましょう。
|
||||
|
||||
デフォルトでは、**FastAPI**はそのボディを直接期待します。
|
||||
|
||||
しかし、追加のボディパラメータを宣言したときのように、キー `item` を持つ JSON とその中のモデルの内容を期待したい場合は、特別な `Body` パラメータ `embed` を使うことができます:
|
||||
|
||||
```Python
|
||||
item: Item = Body(..., embed=True)
|
||||
```
|
||||
|
||||
以下において:
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial005.py hl[17] *}
|
||||
|
||||
この場合、**FastAPI** は以下のようなボディを期待します:
|
||||
|
||||
@@ -163,9 +156,9 @@ item: Item = Body(embed=True)
|
||||
}
|
||||
```
|
||||
|
||||
## まとめ { #recap }
|
||||
## まとめ
|
||||
|
||||
リクエストが単一のボディしか持てない場合でも、*path operation function*に複数のボディパラメータを追加することができます。
|
||||
リクエストが単一のボディしか持てない場合でも、*path operation関数*に複数のボディパラメータを追加することができます。
|
||||
|
||||
しかし、**FastAPI** はそれを処理し、関数内の正しいデータを与え、*path operation*内の正しいスキーマを検証し、文書化します。
|
||||
|
||||
|
||||
@@ -1,26 +1,36 @@
|
||||
# ボディ - ネストされたモデル { #body-nested-models }
|
||||
# ボディ - ネストされたモデル
|
||||
|
||||
**FastAPI** を使用すると、深くネストされた任意のモデルを定義、検証、文書化、使用することができます(Pydanticのおかげです)。
|
||||
|
||||
## リストのフィールド { #list-fields }
|
||||
## リストのフィールド
|
||||
|
||||
属性をサブタイプとして定義することができます。例えば、Pythonの`list`:
|
||||
属性をサブタイプとして定義することができます。例えば、Pythonの`list`は以下のように定義できます:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial001.py hl[12] *}
|
||||
|
||||
これにより、各項目の型は宣言されていませんが、`tags`はリストになります。
|
||||
これにより、各項目の型は宣言されていませんが、`tags`はある項目のリストになります。
|
||||
|
||||
## タイプパラメータを持つリストのフィールド { #list-fields-with-type-parameter }
|
||||
## タイプパラメータを持つリストのフィールド
|
||||
|
||||
しかし、Pythonには内部の型、または「タイプパラメータ」を使ってリストを宣言するための特定の方法があります:
|
||||
しかし、Pythonには型や「タイプパラメータ」を使ってリストを宣言する方法があります:
|
||||
|
||||
### タイプパラメータを持つ`list`の宣言 { #declare-a-list-with-a-type-parameter }
|
||||
### typingの`List`をインポート
|
||||
|
||||
`list`、`dict`、`tuple`のようにタイプパラメータ(内部の型)を持つ型を宣言するには、
|
||||
角括弧(`[`と`]`)を使って内部の型を「タイプパラメータ」として渡します。
|
||||
まず、Pythonの標準の`typing`モジュールから`List`をインポートします:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial002.py hl[1] *}
|
||||
|
||||
### タイプパラメータを持つ`List`の宣言
|
||||
|
||||
`list`や`dict`、`tuple`のようなタイプパラメータ(内部の型)を持つ型を宣言するには:
|
||||
|
||||
* `typing`モジュールからそれらをインストールします。
|
||||
* 角括弧(`[`と`]`)を使って「タイプパラメータ」として内部の型を渡します:
|
||||
|
||||
```Python
|
||||
my_list: list[str]
|
||||
from typing import List
|
||||
|
||||
my_list: List[str]
|
||||
```
|
||||
|
||||
型宣言の標準的なPythonの構文はこれだけです。
|
||||
@@ -29,17 +39,17 @@ my_list: list[str]
|
||||
|
||||
そのため、以下の例では`tags`を具体的な「文字列のリスト」にすることができます:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial002.py hl[14] *}
|
||||
|
||||
## セット型 { #set-types }
|
||||
## セット型
|
||||
|
||||
しかし、よく考えてみると、タグは繰り返すべきではなく、おそらくユニークな文字列になるのではないかと気付いたとします。
|
||||
|
||||
そして、Pythonにはユニークな項目のセットのための特別なデータ型`set`があります。
|
||||
|
||||
そして、`tags`を文字列のセットとして宣言できます:
|
||||
そのため、以下のように、`Set`をインポートして`str`の`set`として`tags`を宣言することができます:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial003.py hl[1,14] *}
|
||||
|
||||
これを使えば、データが重複しているリクエストを受けた場合でも、ユニークな項目のセットに変換されます。
|
||||
|
||||
@@ -47,27 +57,27 @@ my_list: list[str]
|
||||
|
||||
また、それに応じて注釈をつけたり、文書化したりします。
|
||||
|
||||
## ネストされたモデル { #nested-models }
|
||||
## ネストされたモデル
|
||||
|
||||
Pydanticモデルの各属性には型があります。
|
||||
|
||||
しかし、その型はそれ自体が別のPydanticモデルである可能性があります。
|
||||
|
||||
そのため、特定の属性名、型、バリデーションを指定して、深くネストしたJSON「オブジェクト」を宣言することができます。
|
||||
そのため、特定の属性名、型、バリデーションを指定して、深くネストしたJSON`object`を宣言することができます。
|
||||
|
||||
すべては、任意のネストにされています。
|
||||
|
||||
### サブモデルの定義 { #define-a-submodel }
|
||||
### サブモデルの定義
|
||||
|
||||
例えば、`Image`モデルを定義することができます:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial004.py hl[9,10,11] *}
|
||||
|
||||
### サブモデルを型として使用 { #use-the-submodel-as-a-type }
|
||||
### サブモデルを型として使用
|
||||
|
||||
そして、それを属性の型として使用することができます:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial004.py hl[20] *}
|
||||
|
||||
これは **FastAPI** が以下のようなボディを期待することを意味します:
|
||||
|
||||
@@ -92,23 +102,23 @@ Pydanticモデルの各属性には型があります。
|
||||
* データの検証
|
||||
* 自動文書化
|
||||
|
||||
## 特殊な型とバリデーション { #special-types-and-validation }
|
||||
## 特殊な型とバリデーション
|
||||
|
||||
`str`や`int`、`float`などの通常の単数型の他にも、`str`を継承したより複雑な単数型を使うこともできます。
|
||||
`str`や`int`、`float`のような通常の単数型の他にも、`str`を継承したより複雑な単数型を使うこともできます。
|
||||
|
||||
すべてのオプションをみるには、<a href="https://docs.pydantic.dev/latest/concepts/types/" class="external-link" target="_blank">Pydanticの型の概要</a>を確認してください。次の章でいくつかの例をみることができます。
|
||||
すべてのオプションをみるには、<a href="https://docs.pydantic.dev/latest/concepts/types/" class="external-link" target="_blank">Pydanticのエキゾチック な型</a>のドキュメントを確認してください。次の章でいくつかの例をみることができます。
|
||||
|
||||
例えば、`Image`モデルのように`url`フィールドがある場合、`str`の代わりにPydanticの`HttpUrl`のインスタンスとして宣言することができます:
|
||||
例えば、`Image`モデルのように`url`フィールドがある場合、`str`の代わりにPydanticの`HttpUrl`を指定することができます:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial005.py hl[4,10] *}
|
||||
|
||||
文字列は有効なURLであることが確認され、そのようにJSON Schema / OpenAPIで文書化されます。
|
||||
文字列は有効なURLであることが確認され、そのようにJSONスキーマ・OpenAPIで文書化されます。
|
||||
|
||||
## サブモデルのリストを持つ属性 { #attributes-with-lists-of-submodels }
|
||||
## サブモデルのリストを持つ属性
|
||||
|
||||
Pydanticモデルを`list`や`set`などのサブタイプとして使用することもできます:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial006.py hl[20] *}
|
||||
|
||||
これは、次のようなJSONボディを期待します(変換、検証、ドキュメントなど):
|
||||
|
||||
@@ -142,59 +152,59 @@ Pydanticモデルを`list`や`set`などのサブタイプとして使用する
|
||||
|
||||
///
|
||||
|
||||
## 深くネストされたモデル { #deeply-nested-models }
|
||||
## 深くネストされたモデル
|
||||
|
||||
深くネストされた任意のモデルを定義することができます:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial007.py hl[9,14,20,23,27] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
`Offer`は`Item`のリストであり、それらがさらにオプションの`Image`のリストを持っていることに注目してください。
|
||||
`Offer`は`Item`のリストであり、オプションの`Image`のリストを持っていることに注目してください。
|
||||
|
||||
///
|
||||
|
||||
## 純粋なリストのボディ { #bodies-of-pure-lists }
|
||||
## 純粋なリストのボディ
|
||||
|
||||
期待するJSONボディのトップレベルの値がJSON`array`(Pythonの`list`)であれば、Pydanticモデルと同じように、関数のパラメータで型を宣言することができます:
|
||||
|
||||
```Python
|
||||
images: list[Image]
|
||||
images: List[Image]
|
||||
```
|
||||
|
||||
以下のように:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial008_py39.py hl[13] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial008.py hl[15] *}
|
||||
|
||||
## あらゆる場所でのエディタサポート { #editor-support-everywhere }
|
||||
## あらゆる場所でのエディタサポート
|
||||
|
||||
そして、あらゆる場所でエディタサポートを得られます。
|
||||
エディタのサポートもどこでも受けることができます。
|
||||
|
||||
以下のようにリストの中の項目でも:
|
||||
|
||||
<img src="/img/tutorial/body-nested-models/image01.png">
|
||||
<img src="https://fastapi.tiangolo.com/img/tutorial/body-nested-models/image01.png">
|
||||
|
||||
Pydanticモデルではなく、`dict`を直接使用している場合はこのようなエディタのサポートは得られません。
|
||||
|
||||
しかし、それらについて心配する必要はありません。入力されたdictは自動的に変換され、出力も自動的にJSONに変換されます。
|
||||
しかし、それらについて心配する必要はありません。入力された辞書は自動的に変換され、出力も自動的にJSONに変換されます。
|
||||
|
||||
## 任意の`dict`のボディ { #bodies-of-arbitrary-dicts }
|
||||
## 任意の`dict`のボディ
|
||||
|
||||
また、ある型のキーと別の型の値を持つ`dict`としてボディを宣言することもできます。
|
||||
|
||||
この方法で、有効なフィールド/属性名を事前に知る必要がありません(Pydanticモデルの場合のように)。
|
||||
有効なフィールド・属性名を事前に知る必要がありません(Pydanticモデルの場合のように)。
|
||||
|
||||
これは、まだ知らないキーを受け取りたいときに便利です。
|
||||
これは、まだ知らないキーを受け取りたいときに便利だと思います。
|
||||
|
||||
---
|
||||
|
||||
もうひとつ便利なケースは、別の型(例: `int`)のキーを持ちたい場合です。
|
||||
他にも、`int`のように他の型のキーを持ちたい場合などに便利です。
|
||||
|
||||
それをここで見ていきます。
|
||||
それをここで見ていきましょう。
|
||||
|
||||
この場合、`int`のキーと`float`の値を持つものであれば、どんな`dict`でも受け入れることができます:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial009_py39.py hl[7] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial009.py hl[15] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
@@ -208,14 +218,14 @@ JSONはキーとして`str`しかサポートしていないことに注意し
|
||||
|
||||
///
|
||||
|
||||
## まとめ { #recap }
|
||||
## まとめ
|
||||
|
||||
**FastAPI** を使用すると、Pydanticモデルが提供する最大限の柔軟性を持ちながら、コードをシンプルに短く、エレガントに保つことができます。
|
||||
|
||||
しかし、以下のような利点があります:
|
||||
以下のような利点があります:
|
||||
|
||||
* エディタのサポート(どこでも補完!)
|
||||
* データ変換(別名:構文解析 / シリアライズ)
|
||||
* データ変換(別名:構文解析・シリアライズ)
|
||||
* データの検証
|
||||
* スキーマ文書
|
||||
* 自動ドキュメント
|
||||
* 自動文書化
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ボディ - 更新 { #body-updates }
|
||||
# ボディ - 更新
|
||||
|
||||
## `PUT`による置換での更新 { #update-replacing-with-put }
|
||||
## `PUT`による置換での更新
|
||||
|
||||
項目を更新するには<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT" class="external-link" target="_blank">HTTPの`PUT`</a>操作を使用することができます。
|
||||
|
||||
`jsonable_encoder`を用いて、入力データをJSONとして保存できるデータに変換することができます(例:NoSQLデータベース)。例えば、`datetime`を`str`に変換します。
|
||||
`jsonable_encoder`を用いて、入力データをJSON形式で保存できるデータに変換することができます(例:NoSQLデータベース)。例えば、`datetime`を`str`に変換します。
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}
|
||||
{* ../../docs_src/body_updates/tutorial001.py hl[30,31,32,33,34,35] *}
|
||||
|
||||
`PUT`は、既存のデータを置き換えるべきデータを受け取るために使用されます。
|
||||
既存のデータを置き換えるべきデータを受け取るために`PUT`は使用されます。
|
||||
|
||||
### 置換についての注意 { #warning-about-replacing }
|
||||
### 置換についての注意
|
||||
|
||||
つまり、`PUT`を使用して以下のボディで項目`bar`を更新したい場合は:
|
||||
|
||||
@@ -22,11 +22,11 @@
|
||||
}
|
||||
```
|
||||
|
||||
すでに格納されている属性`"tax": 20.2`を含まないため、入力モデルは`"tax": 10.5`のデフォルト値を取ります。
|
||||
すでに格納されている属性`"tax": 20.2`を含まないため、入力モデルのデフォルト値は`"tax": 10.5`です。
|
||||
|
||||
そして、データはその「新しい」`10.5`の`tax`と共に保存されます。
|
||||
|
||||
## `PATCH`による部分的な更新 { #partial-updates-with-patch }
|
||||
## `PATCH`による部分的な更新
|
||||
|
||||
また、<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH" class="external-link" target="_blank">HTTPの`PATCH`</a>操作でデータを*部分的に*更新することもできます。
|
||||
|
||||
@@ -44,27 +44,27 @@
|
||||
|
||||
///
|
||||
|
||||
### Pydanticの`exclude_unset`パラメータの使用 { #using-pydantics-exclude-unset-parameter }
|
||||
### Pydanticの`exclude_unset`パラメータの使用
|
||||
|
||||
部分的な更新を受け取りたい場合は、Pydanticモデルの`.model_dump()`の`exclude_unset`パラメータを使用すると非常に便利です。
|
||||
部分的な更新を受け取りたい場合は、Pydanticモデルの`.dict()`の`exclude_unset`パラメータを使用すると非常に便利です。
|
||||
|
||||
`item.model_dump(exclude_unset=True)`のように。
|
||||
`item.dict(exclude_unset=True)`のように。
|
||||
|
||||
これにより、`item`モデルの作成時に設定されたデータのみを持つ`dict`が生成され、デフォルト値は除外されます。
|
||||
|
||||
これを使うことで、デフォルト値を省略して、設定された(リクエストで送られた)データのみを含む`dict`を生成することができます:
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}
|
||||
{* ../../docs_src/body_updates/tutorial002.py hl[34] *}
|
||||
|
||||
### Pydanticの`update`パラメータの使用 { #using-pydantics-update-parameter }
|
||||
### Pydanticの`update`パラメータ
|
||||
|
||||
ここで、`.model_copy()`を用いて既存のモデルのコピーを作成し、`update`パラメータに更新するデータを含む`dict`を渡すことができます。
|
||||
ここで、`.copy()`を用いて既存のモデルのコピーを作成し、`update`パラメータに更新するデータを含む`dict`を渡すことができます。
|
||||
|
||||
`stored_item_model.model_copy(update=update_data)`のように:
|
||||
`stored_item_model.copy(update=update_data)`のように:
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}
|
||||
{* ../../docs_src/body_updates/tutorial002.py hl[35] *}
|
||||
|
||||
### 部分的更新のまとめ { #partial-updates-recap }
|
||||
### 部分的更新のまとめ
|
||||
|
||||
まとめると、部分的な更新を適用するには、次のようにします:
|
||||
|
||||
@@ -75,11 +75,11 @@
|
||||
* この方法では、モデル内のデフォルト値ですでに保存されている値を上書きするのではなく、ユーザーが実際に設定した値のみを更新することができます。
|
||||
* 保存されているモデルのコピーを作成し、受け取った部分的な更新で属性を更新します(`update`パラメータを使用します)。
|
||||
* コピーしたモデルをDBに保存できるものに変換します(例えば、`jsonable_encoder`を使用します)。
|
||||
* これはモデルの`.model_dump()`メソッドを再度利用することに匹敵しますが、値をJSONに変換できるデータ型になるようにし(変換し)、例えば`datetime`を`str`に変換します。
|
||||
* これはモデルの`.dict()`メソッドを再度利用することに匹敵しますが、値をJSONに変換できるデータ型、例えば`datetime`を`str`に変換します。
|
||||
* データをDBに保存します。
|
||||
* 更新されたモデルを返します。
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}
|
||||
{* ../../docs_src/body_updates/tutorial002.py hl[30,31,32,33,34,35,36,37] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
|
||||
@@ -1,41 +1,40 @@
|
||||
# リクエストボディ { #request-body }
|
||||
# リクエストボディ
|
||||
|
||||
クライアント(例えばブラウザ)からAPIにデータを送信する必要がある場合、**リクエストボディ**として送信します。
|
||||
クライアント (ブラウザなど) からAPIにデータを送信する必要があるとき、データを **リクエストボディ (request body)** として送ります。
|
||||
|
||||
**リクエスト**ボディは、クライアントからAPIへ送信されるデータです。**レスポンス**ボディは、APIがクライアントに送信するデータです。
|
||||
**リクエスト** ボディはクライアントによってAPIへ送られます。**レスポンス** ボディはAPIがクライアントに送るデータです。
|
||||
|
||||
APIはほとんどの場合 **レスポンス** ボディを送信する必要があります。しかしクライアントは、常に **リクエストボディ** を送信する必要があるとは限りません。場合によっては、クエリパラメータ付きのパスだけをリクエストして、ボディを送信しないこともあります。
|
||||
APIはほとんどの場合 **レスポンス** ボディを送らなければなりません。しかし、クライアントは必ずしも **リクエスト** ボディを送らなければいけないわけではありません。
|
||||
|
||||
**リクエスト**ボディを宣言するには、<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> モデルを使用し、その強力な機能とメリットをすべて利用します。
|
||||
**リクエスト** ボディを宣言するために <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> モデルを使用します。そして、その全てのパワーとメリットを利用します。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
データを送信するには、`POST`(より一般的)、`PUT`、`DELETE`、`PATCH` のいずれかを使用すべきです。
|
||||
データを送るには、`POST` (もっともよく使われる)、`PUT`、`DELETE` または `PATCH` を使うべきです。
|
||||
|
||||
`GET` リクエストでボディを送信することは仕様上は未定義の動作ですが、それでもFastAPIではサポートされています。ただし、非常に複雑/極端なユースケースのためだけです。
|
||||
GET リクエストでボディを送信することは、仕様では未定義の動作ですが、FastAPI でサポートされており、非常に複雑な(極端な)ユースケースにのみ対応しています。
|
||||
|
||||
推奨されないため、Swagger UIによる対話的ドキュメントでは `GET` 使用時のボディのドキュメントは表示されず、途中のプロキシが対応していない可能性もあります。
|
||||
非推奨なので、Swagger UIを使った対話型のドキュメントにはGETのボディ情報は表示されません。さらに、中継するプロキシが対応していない可能性があります。
|
||||
|
||||
///
|
||||
|
||||
## Pydanticの `BaseModel` をインポート { #import-pydantics-basemodel }
|
||||
## Pydanticの `BaseModel` をインポート
|
||||
|
||||
まず、`pydantic` から `BaseModel` をインポートする必要があります:
|
||||
ます初めに、 `pydantic` から `BaseModel` をインポートする必要があります:
|
||||
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[2] *}
|
||||
{* ../../docs_src/body/tutorial001.py hl[4] *}
|
||||
|
||||
## データモデルの作成 { #create-your-data-model }
|
||||
## データモデルの作成
|
||||
|
||||
次に、`BaseModel` を継承するクラスとしてデータモデルを宣言します。
|
||||
そして、`BaseModel` を継承したクラスとしてデータモデルを宣言します。
|
||||
|
||||
すべての属性に標準のPython型を使用します:
|
||||
すべての属性にpython標準の型を使用します:
|
||||
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
|
||||
{* ../../docs_src/body/tutorial001.py hl[7:11] *}
|
||||
|
||||
クエリパラメータの宣言と同様に、モデル属性がデフォルト値をもつとき、必須な属性ではなくなります。それ以外は必須になります。オプショナルな属性にしたい場合は `None` を使用してください。
|
||||
|
||||
クエリパラメータの宣言と同様に、モデル属性がデフォルト値を持つ場合は必須ではありません。そうでなければ必須です。単にオプションにするには `None` を使用してください。
|
||||
|
||||
例えば、上記のモデルは次のようなJSON「`object`」(またはPythonの `dict`)を宣言します:
|
||||
例えば、上記のモデルは以下の様なJSON「`オブジェクト`」(もしくはPythonの `dict` ) を宣言しています:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -46,7 +45,7 @@ APIはほとんどの場合 **レスポンス** ボディを送信する必要
|
||||
}
|
||||
```
|
||||
|
||||
...`description` と `tax` はオプション(デフォルト値が `None`)なので、このJSON「`object`」も有効です:
|
||||
...`description` と `tax` はオプショナル (デフォルト値は `None`) なので、以下のJSON「`オブジェクト`」も有効です:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -55,112 +54,109 @@ APIはほとんどの場合 **レスポンス** ボディを送信する必要
|
||||
}
|
||||
```
|
||||
|
||||
## パラメータとして宣言 { #declare-it-as-a-parameter }
|
||||
## パラメータとして宣言
|
||||
|
||||
*path operation* に追加するには、パスパラメータやクエリパラメータを宣言したのと同じ方法で宣言します:
|
||||
*パスオペレーション* に加えるために、パスパラメータやクエリパラメータと同じ様に宣言します:
|
||||
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[16] *}
|
||||
{* ../../docs_src/body/tutorial001.py hl[18] *}
|
||||
|
||||
...そして、作成したモデル `Item` を型として宣言します。
|
||||
...そして、作成したモデル `Item` で型を宣言します。
|
||||
|
||||
## 結果 { #results }
|
||||
## 結果
|
||||
|
||||
そのPythonの型宣言だけで **FastAPI** は以下を行います:
|
||||
そのPythonの型宣言だけで **FastAPI** は以下のことを行います:
|
||||
|
||||
* リクエストのボディをJSONとして読み取ります。
|
||||
* 対応する型に変換します(必要な場合)。
|
||||
* リクエストボディをJSONとして読み取ります。
|
||||
* 適当な型に変換します(必要な場合)。
|
||||
* データを検証します。
|
||||
* データが無効な場合は、どこで何が不正なデータだったのかを正確に示す、分かりやすい明確なエラーを返します。
|
||||
* 受け取ったデータをパラメータ `item` に渡します。
|
||||
* 関数内で `Item` 型として宣言したため、すべての属性とその型について、エディタサポート(補完など)も利用できます。
|
||||
* モデル向けの <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a> 定義を生成します。プロジェクトにとって意味があるなら、他の場所でも好きなように利用できます。
|
||||
* それらのスキーマは生成されるOpenAPIスキーマの一部となり、自動ドキュメントの <abbr title="User Interfaces">UIs</abbr> で使用されます。
|
||||
* データが無効な場合は、明確なエラーが返され、どこが不正なデータであったかを示します。
|
||||
* 受け取ったデータをパラメータ `item` に変換します。
|
||||
* 関数内で `Item` 型であると宣言したので、すべての属性とその型に対するエディタサポート(補完など)をすべて使用できます。
|
||||
* モデルの<a href="http://json-schema.org" class="external-link" target="_blank">JSONスキーマ</a>定義を生成し、好きな場所で使用することができます。
|
||||
* これらのスキーマは、生成されたOpenAPIスキーマの一部となり、自動ドキュメントの<abbr title = "User Interfaces">UI</abbr>に使用されます。
|
||||
|
||||
## 自動ドキュメント { #automatic-docs }
|
||||
## 自動ドキュメント生成
|
||||
|
||||
モデルのJSON Schemaは、OpenAPIで生成されたスキーマの一部になり、対話的なAPIドキュメントに表示されます:
|
||||
モデルのJSONスキーマはOpenAPIで生成されたスキーマの一部になり、対話的なAPIドキュメントに表示されます:
|
||||
|
||||
<img src="/img/tutorial/body/image01.png">
|
||||
|
||||
また、それらが必要な各 *path operation* 内のAPIドキュメントでも使用されます:
|
||||
そして、それらが使われる *パスオペレーション* のそれぞれのAPIドキュメントにも表示されます:
|
||||
|
||||
<img src="/img/tutorial/body/image02.png">
|
||||
|
||||
## エディタサポート { #editor-support }
|
||||
## エディターサポート
|
||||
|
||||
エディタ上で、関数内のあらゆる場所で型ヒントと補完が得られます(Pydanticモデルの代わりに `dict` を受け取った場合は起きません):
|
||||
エディターによる型ヒントと補完が関数内で利用できます (Pydanticモデルではなく `dict` を受け取ると、同じサポートは受けられません):
|
||||
|
||||
<img src="/img/tutorial/body/image03.png">
|
||||
|
||||
不正な型操作に対するエラーチェックも得られます:
|
||||
型によるエラーチェックも可能です:
|
||||
|
||||
<img src="/img/tutorial/body/image04.png">
|
||||
|
||||
これは偶然ではなく、フレームワーク全体がその設計を中心に構築されています。
|
||||
これは偶然ではなく、このデザインに基づいてフレームワークが作られています。
|
||||
|
||||
そして、すべてのエディタで動作することを確実にするために、実装前の設計フェーズで徹底的にテストされました。
|
||||
全てのエディターで機能することを確認するために、実装前の設計時に徹底的にテストしました。
|
||||
|
||||
これをサポートするために、Pydantic自体にもいくつかの変更が加えられました。
|
||||
これをサポートするためにPydantic自体にもいくつかの変更がありました。
|
||||
|
||||
前述のスクリーンショットは <a href="https://code.visualstudio.com" class="external-link" target="_blank">Visual Studio Code</a> で撮影されたものです。
|
||||
上記のスクリーンショットは<a href="https://code.visualstudio.com" class="external-link" target="_blank">Visual Studio Code</a>を撮ったものです。
|
||||
|
||||
ただし、<a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> や、他のほとんどのPythonエディタでも同じエディタサポートを得られます:
|
||||
しかし、<a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a>やほとんどのPythonエディタでも同様なエディターサポートを受けられます:
|
||||
|
||||
<img src="/img/tutorial/body/image05.png">
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
エディタとして <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> を使用している場合、<a href="https://github.com/koxudaxi/pydantic-pycharm-plugin/" class="external-link" target="_blank">Pydantic PyCharm Plugin</a> を使用できます。
|
||||
<a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a>エディタを使用している場合は、<a href="https://github.com/koxudaxi/pydantic-pycharm-plugin/" class="external-link" target="_blank">Pydantic PyCharm Plugin</a>が使用可能です。
|
||||
|
||||
以下により、Pydanticモデルに対するエディタサポートが改善されます:
|
||||
以下のエディターサポートが強化されます:
|
||||
|
||||
* auto-completion
|
||||
* type checks
|
||||
* refactoring
|
||||
* searching
|
||||
* inspections
|
||||
* 自動補完
|
||||
* 型チェック
|
||||
* リファクタリング
|
||||
* 検索
|
||||
* インスペクション
|
||||
|
||||
///
|
||||
|
||||
## モデルを使用する { #use-the-model }
|
||||
## モデルの使用
|
||||
|
||||
関数内では、モデルオブジェクトのすべての属性に直接アクセスできます:
|
||||
関数内部で、モデルの全ての属性に直接アクセスできます:
|
||||
|
||||
{* ../../docs_src/body/tutorial002_py310.py *}
|
||||
{* ../../docs_src/body/tutorial002.py hl[21] *}
|
||||
|
||||
## リクエストボディ + パスパラメータ { #request-body-path-parameters }
|
||||
## リクエストボディ + パスパラメータ
|
||||
|
||||
パスパラメータとリクエストボディを同時に宣言できます。
|
||||
|
||||
**FastAPI** は、パスパラメータに一致する関数パラメータは **パスから取得** し、Pydanticモデルとして宣言された関数パラメータは **リクエストボディから取得** すべきだと認識します。
|
||||
**FastAPI** はパスパラメータである関数パラメータは**パスから受け取り**、Pydanticモデルによって宣言された関数パラメータは**リクエストボディから受け取る**ということを認識します。
|
||||
|
||||
{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
|
||||
{* ../../docs_src/body/tutorial003.py hl[17:18] *}
|
||||
|
||||
## リクエストボディ + パスパラメータ + クエリパラメータ
|
||||
|
||||
## リクエストボディ + パス + クエリパラメータ { #request-body-path-query-parameters }
|
||||
また、**ボディ**と**パス**と**クエリ**のパラメータも同時に宣言できます。
|
||||
|
||||
**body**、**path**、**query** パラメータもすべて同時に宣言できます。
|
||||
**FastAPI** はそれぞれを認識し、適切な場所からデータを取得します。
|
||||
|
||||
**FastAPI** はそれぞれを認識し、正しい場所からデータを取得します。
|
||||
{* ../../docs_src/body/tutorial004.py hl[18] *}
|
||||
|
||||
{* ../../docs_src/body/tutorial004_py310.py hl[16] *}
|
||||
関数パラメータは以下の様に認識されます:
|
||||
|
||||
関数パラメータは以下のように認識されます:
|
||||
|
||||
* パラメータが **path** でも宣言されている場合、パスパラメータとして使用されます。
|
||||
* パラメータが **単数型**(`int`、`float`、`str`、`bool` など)の場合、**query** パラメータとして解釈されます。
|
||||
* パラメータが **Pydanticモデル** の型として宣言されている場合、リクエスト **body** として解釈されます。
|
||||
* パラメータが**パス**で宣言されている場合は、優先的にパスパラメータとして扱われます。
|
||||
* パラメータが**単数型** (`int`、`float`、`str`、`bool` など)の場合は**クエリ**パラメータとして解釈されます。
|
||||
* パラメータが **Pydantic モデル**型で宣言された場合、リクエスト**ボディ**として解釈されます。
|
||||
|
||||
/// note | 備考
|
||||
|
||||
FastAPIは、デフォルト値 `= None` があるため、`q` の値が必須ではないことを認識します。
|
||||
FastAPIは、`= None`があるおかげで、`q`がオプショナルだとわかります。
|
||||
|
||||
`str | None`(Python 3.10+)や `Union[str, None]`(Python 3.9+)の `Union` は、値が必須ではないことを判断するためにFastAPIでは使用されません。`= None` というデフォルト値があるため、必須ではないことを認識します。
|
||||
|
||||
しかし、型アノテーションを追加すると、エディタがより良いサポートを提供し、エラーを検出できるようになります。
|
||||
`Optional[str]` の`Optional` はFastAPIでは使用されていません(FastAPIは`str`の部分のみ使用します)。しかし、`Optional[str]` はエディタがコードのエラーを見つけるのを助けてくれます。
|
||||
|
||||
///
|
||||
|
||||
## Pydanticを使わない方法 { #without-pydantic }
|
||||
## Pydanticを使わない方法
|
||||
|
||||
Pydanticモデルを使いたくない場合は、**Body** パラメータも使用できます。[Body - Multiple Parameters: Singular values in body](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank} のドキュメントを参照してください。
|
||||
もしPydanticモデルを使用したくない場合は、**Body**パラメータが利用できます。[Body - Multiple Parameters: Singular values in body](body-multiple-params.md#_2){.internal-link target=_blank}を確認してください。
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# クッキーパラメータモデル { #cookie-parameter-models }
|
||||
# クッキーパラメータモデル
|
||||
|
||||
もし関連する**複数のクッキー**から成るグループがあるなら、それらを宣言するために、**Pydanticモデル**を作成できます。🍪
|
||||
|
||||
こうすることで、**複数の場所**で**そのPydanticモデルを再利用**でき、バリデーションやメタデータを、すべてのパラメータに対して一度に宣言できます。😎
|
||||
こうすることで、**複数の場所**で**そのPydanticモデルを再利用**でき、バリデーションやメタデータを、すべてのクッキーパラメータに対して一度に宣言できます。😎
|
||||
|
||||
/// note | 備考
|
||||
|
||||
@@ -16,15 +16,15 @@
|
||||
|
||||
///
|
||||
|
||||
## Pydanticモデルを使用したクッキー { #cookies-with-a-pydantic-model }
|
||||
## クッキーにPydanticモデルを使用する
|
||||
|
||||
必要な複数の**クッキー**パラメータを**Pydanticモデル**で宣言し、さらに、パラメータを `Cookie` として宣言しましょう:
|
||||
必要な複数の**クッキー**パラメータを**Pydanticモデル**で宣言し、さらに、それを `Cookie` として宣言しましょう:
|
||||
|
||||
{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}
|
||||
|
||||
**FastAPI**は、リクエストで受け取った**クッキー**から**それぞれのフィールド**のデータを**抽出**し、定義したPydanticモデルを提供します。
|
||||
**FastAPI**は、リクエストの**クッキー**から**それぞれのフィールド**のデータを**抽出**し、定義された**Pydanticモデル**を提供します。
|
||||
|
||||
## ドキュメントの確認 { #check-the-docs }
|
||||
## ドキュメントの確認
|
||||
|
||||
対話的APIドキュメントUI `/docs` で、定義されているクッキーを確認できます:
|
||||
|
||||
@@ -32,17 +32,18 @@
|
||||
<img src="/img/tutorial/cookie-param-models/image01.png">
|
||||
</div>
|
||||
|
||||
/// info | 情報
|
||||
/// info | 備考
|
||||
|
||||
|
||||
**ブラウザがクッキーを処理し**ていますが、特別な方法で内部的に処理を行っているために、**JavaScript**からは簡単に操作**できない**ことに留意してください。
|
||||
|
||||
**APIドキュメントUI** `/docs` にアクセスすれば、*path operation*に関するクッキーの**ドキュメンテーション**を確認できます。
|
||||
**対話的APIドキュメントUI** `/docs` にアクセスすれば、*パスオペレーション*に関するクッキーの**ドキュメンテーション**を確認できます。
|
||||
|
||||
しかし、たとえ**データを入力して**「Execute」をクリックしても、ドキュメントUIは**JavaScript**で動作しているためクッキーは送信されず、まるで値を入力しなかったかのような**エラー**メッセージが表示されます。
|
||||
しかし、たとえ**クッキーデータを入力して**「Execute」をクリックしても、対話的APIドキュメントUIは**JavaScript**で動作しているためクッキーは送信されず、まるで値を入力しなかったかのような**エラー**メッセージが表示されます。
|
||||
|
||||
///
|
||||
|
||||
## 余分なクッキーを禁止する { #forbid-extra-cookies }
|
||||
## 余分なクッキーを禁止する
|
||||
|
||||
特定の(あまり一般的ではないかもしれない)ケースで、受け付けるクッキーを**制限**する必要があるかもしれません。
|
||||
|
||||
@@ -50,7 +51,7 @@
|
||||
|
||||
Pydanticのモデルの Configuration を利用して、 `extra` フィールドを `forbid` とすることができます。
|
||||
|
||||
{* ../../docs_src/cookie_param_models/tutorial002_an_py310.py hl[10] *}
|
||||
{* ../../docs_src/cookie_param_models/tutorial002_an_py39.py hl[10] *}
|
||||
|
||||
もしクライアントが**余分なクッキー**を送ろうとすると、**エラー**レスポンスが返されます。
|
||||
|
||||
@@ -71,6 +72,6 @@ Pydanticのモデルの Configuration を利用して、 `extra` フィールド
|
||||
}
|
||||
```
|
||||
|
||||
## まとめ { #summary }
|
||||
## まとめ
|
||||
|
||||
**FastAPI**では、<abbr title="帰ってしまう前に最後のクッキーをどうぞ。🍪 (原文: Have a last cookie before you go. 🍪)">**クッキー**</abbr>を宣言するために、**Pydanticモデル**を使用できます。😎
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
# クッキーのパラメータ { #cookie-parameters }
|
||||
# クッキーのパラメータ
|
||||
|
||||
クッキーのパラメータは、`Query`や`Path`のパラメータを定義するのと同じ方法で定義できます。
|
||||
|
||||
## `Cookie`をインポート { #import-cookie }
|
||||
## `Cookie`をインポート
|
||||
|
||||
まず、`Cookie`をインポートします:
|
||||
|
||||
{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}
|
||||
{* ../../docs_src/cookie_params/tutorial001.py hl[3] *}
|
||||
|
||||
## `Cookie`のパラメータを宣言 { #declare-cookie-parameters }
|
||||
## `Cookie`のパラメータを宣言
|
||||
|
||||
次に、`Path`や`Query`と同じ構造を使ってクッキーのパラメータを宣言します。
|
||||
|
||||
最初の値がデフォルト値で、追加の検証パラメータや注釈パラメータをすべて渡すことができます:
|
||||
|
||||
{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}
|
||||
{* ../../docs_src/cookie_params/tutorial001.py hl[9] *}
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
@@ -30,16 +30,6 @@
|
||||
|
||||
///
|
||||
|
||||
/// info | 情報
|
||||
## まとめ
|
||||
|
||||
**ブラウザがクッキーを**特殊な方法で裏側で扱うため、**JavaScript** から簡単には触れられないことを念頭に置いてください。
|
||||
|
||||
`/docs` の **API docs UI** に移動すると、*path operation* のクッキーに関する **documentation** を確認できます。
|
||||
|
||||
しかし、データを **入力** して「Execute」をクリックしても、docs UI は **JavaScript** で動作するためクッキーは送信されず、値を何も書かなかったかのような **error** メッセージが表示されます。
|
||||
|
||||
///
|
||||
|
||||
## まとめ { #recap }
|
||||
|
||||
クッキーは`Cookie`を使って宣言し、`Query`や`Path`と同じ共通のパターンを使用する。
|
||||
クッキーは`Cookie`を使って宣言し、`Query`や`Path`と同じパターンを使用する。
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# CORS (Cross-Origin Resource Sharing) { #cors-cross-origin-resource-sharing }
|
||||
# CORS (オリジン間リソース共有)
|
||||
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">CORSまたは「Cross-Origin Resource Sharing」</a> は、ブラウザで実行されているフロントエンドにバックエンドと通信するJavaScriptコードがあり、そのバックエンドがフロントエンドとは異なる「オリジン」にある状況を指します。
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">CORSまたは「オリジン間リソース共有」</a> は、ブラウザで実行されているフロントエンドにバックエンドと通信するJavaScriptコードがあり、そのバックエンドがフロントエンドとは異なる「オリジン」にある状況を指します。
|
||||
|
||||
## オリジン { #origin }
|
||||
## オリジン
|
||||
|
||||
オリジンはプロトコル (`http`、`https`) とドメイン (`myapp.com`、`localhost`、`localhost.tiangolo.com`) とポート (`80`、`443`、`8080`) の組み合わせです。
|
||||
|
||||
@@ -14,25 +14,25 @@
|
||||
|
||||
すべて `localhost` であっても、異なるプロトコルやポートを使用するので、異なる「オリジン」です。
|
||||
|
||||
## ステップ { #steps }
|
||||
## ステップ
|
||||
|
||||
そして、ブラウザ上で実行されているフロントエンド (`http://localhost:8080`) があり、そのJavaScriptが `http://localhost` で実行されているバックエンドと通信するとします。(ポートを指定していないので、ブラウザはデフォルトの`80`ポートを使用します)
|
||||
|
||||
次に、ブラウザはHTTPの `OPTIONS` リクエストを `:80` のバックエンドに送信します。そして、バックエンドがこの異なるオリジン (`http://localhost:8080`) からの通信を許可する適切なヘッダーを送信すると、`:8080` のブラウザはフロントエンドのJavaScriptに `:80` のバックエンドへのリクエストを送信させます。
|
||||
次に、ブラウザはHTTPの `OPTIONS` リクエストをバックエンドに送信します。そして、バックエンドがこの異なるオリジン (`http://localhost:8080`) からの通信を許可する適切なヘッダーを送信すると、ブラウザはフロントエンドのJavaScriptにバックエンドへのリクエストを送信させます。
|
||||
|
||||
これを実現するには、`:80` のバックエンドに「許可されたオリジン」のリストがなければなりません。
|
||||
これを実現するには、バックエンドに「許可されたオリジン」のリストがなければなりません。
|
||||
|
||||
この場合、`:8080` のフロントエンドを正しく機能させるには、そのリストに `http://localhost:8080` を含める必要があります。
|
||||
この場合、フロントエンドを正しく機能させるには、そのリストに `http://localhost:8080` を含める必要があります。
|
||||
|
||||
## ワイルドカード { #wildcards }
|
||||
## ワイルドカード
|
||||
|
||||
リストを `"*"` (「ワイルドカード」) と宣言して、すべてを許可することもできます。
|
||||
リストを `"*"` (ワイルドカード) と宣言して、すべてを許可することもできます。
|
||||
|
||||
ただし、クレデンシャル情報に関するもの、つまりCookie、Bearer Tokenで使用されるようなAuthorizationヘッダーなどを含むものは除外され、特定の種類の通信のみが許可されます。
|
||||
ただし、Bearer Tokenで使用されるような認証ヘッダーやCookieなどのクレデンシャル情報に関するものを除いて、特定の種類の通信のみが許可されます。
|
||||
|
||||
したがって、すべてを正しく機能させるために、許可されたオリジンの明示的な指定をお勧めします。
|
||||
|
||||
## `CORSMiddleware` の使用 { #use-corsmiddleware }
|
||||
## `CORSMiddleware` の使用
|
||||
|
||||
**FastAPI** アプリケーションでは `CORSMiddleware` を使用して、CORSに関する設定ができます。
|
||||
|
||||
@@ -42,43 +42,39 @@
|
||||
|
||||
以下も、バックエンドに許可させるかどうか指定できます:
|
||||
|
||||
* クレデンシャル情報 (Authorizationヘッダー、Cookieなど) 。
|
||||
* クレデンシャル情報 (認証ヘッダー、Cookieなど) 。
|
||||
* 特定のHTTPメソッド (`POST`、`PUT`) またはワイルドカード `"*"` を使用してすべて許可。
|
||||
* 特定のHTTPヘッダー、またはワイルドカード `"*"`を使用してすべて許可。
|
||||
|
||||
{* ../../docs_src/cors/tutorial001_py39.py hl[2,6:11,13:19] *}
|
||||
{* ../../docs_src/cors/tutorial001.py hl[2,6:11,13:19] *}
|
||||
|
||||
|
||||
`CORSMiddleware` 実装で使用されるデフォルトのパラメータはデフォルトで制限が厳しいため、ブラウザがクロスドメインのコンテキストでそれらを使用できるようにするには、特定のオリジン、メソッド、またはヘッダーを明示的に有効にする必要があります。
|
||||
`CORSMiddleware` 実装のデフォルトのパラメータはCORSに関して制限を与えるものになっているので、ブラウザにドメインを跨いで特定のオリジン、メソッド、またはヘッダーを使用可能にするためには、それらを明示的に有効にする必要があります
|
||||
|
||||
以下の引数がサポートされています:
|
||||
|
||||
* `allow_origins` - オリジン間リクエストを許可するオリジンのリスト。例えば、`['https://example.org', 'https://www.example.org']`。`['*']`を使用して任意のオリジンを許可できます。
|
||||
* `allow_origin_regex` - オリジン間リクエストを許可するオリジンの正規表現文字列。例えば、`'https://.*\.example\.org'`。
|
||||
* `allow_methods` - オリジン間リクエストで許可するHTTPメソッドのリスト。デフォルトは `['GET']` です。`['*']`を使用してすべての標準メソッドを許可できます。
|
||||
* `allow_headers` - オリジン間リクエストでサポートするHTTPリクエストヘッダーのリスト。デフォルトは `[]` です。`['*']`を使用して、すべてのヘッダーを許可できます。<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests" class="external-link" rel="noopener" target="_blank">シンプルなCORSリクエスト</a>では、 `Accept` 、 `Accept-Language` 、 `Content-Language` 、 `Content-Type` ヘッダーが常に許可されます。
|
||||
* `allow_headers` - オリジン間リクエストでサポートするHTTPリクエストヘッダーのリスト。デフォルトは `[]` です。`['*']`を使用して、すべてのヘッダーを許可できます。CORSリクエストでは、 `Accept` 、 `Accept-Language` 、 `Content-Language` 、 `Content-Type` ヘッダーが常に許可されます。
|
||||
* `allow_credentials` - オリジン間リクエストでCookieをサポートする必要があることを示します。デフォルトは `False` です。
|
||||
|
||||
`allow_credentials` が `True` に設定されている場合、`allow_origins`、`allow_methods`、`allow_headers` のいずれも `['*']` に設定できません。これらはすべて<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards" class="external-link" rel="noopener" target="_blank">明示的に指定</a>する必要があります。
|
||||
|
||||
* `expose_headers` - ブラウザからアクセスできるようにするレスポンスヘッダーを示します。デフォルトは `[]` です。
|
||||
* `max_age` - ブラウザがCORSレスポンスをキャッシュする最大時間を秒単位で設定します。デフォルトは `600` です。
|
||||
|
||||
このミドルウェアは2種類のHTTPリクエストに応答します...
|
||||
|
||||
### CORSプリフライトリクエスト { #cors-preflight-requests }
|
||||
### CORSプリフライトリクエスト
|
||||
|
||||
これらは、 `Origin` ヘッダーと `Access-Control-Request-Method` ヘッダーを持つ `OPTIONS` リクエストです。
|
||||
|
||||
この場合、ミドルウェアはリクエストを横取りし、適切なCORSヘッダーと共に情報提供のために `200` または `400` のレスポンスを返します。
|
||||
|
||||
### シンプルなリクエスト { #simple-requests }
|
||||
### シンプルなリクエスト
|
||||
|
||||
`Origin` ヘッダーのあるリクエスト。この場合、ミドルウェアは通常どおりリクエストに何もしないですが、レスポンスに適切なCORSヘッダーを加えます。
|
||||
|
||||
## より詳しい情報 { #more-info }
|
||||
## より詳しい情報
|
||||
|
||||
<abbr title="Cross-Origin Resource Sharing – オリジン間リソース共有">CORS</abbr>についてより詳しい情報は、<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">Mozilla CORS documentation</a> を参照して下さい。
|
||||
<abbr title="Cross-Origin Resource Sharing (オリジン間リソース共有)">CORS</abbr>についてより詳しい情報は、<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">Mozilla CORS documentation</a> を参照して下さい。
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# デバッグ { #debugging }
|
||||
# デバッグ
|
||||
|
||||
Visual Studio CodeやPyCharmなどを使用して、エディター上でデバッガーと連携できます。
|
||||
|
||||
## `uvicorn` を呼び出す { #call-uvicorn }
|
||||
## `uvicorn` の実行
|
||||
|
||||
FastAPIアプリケーション上で、`uvicorn` を直接インポートして実行します:
|
||||
|
||||
{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *}
|
||||
{* ../../docs_src/debugging/tutorial001.py hl[1,15] *}
|
||||
|
||||
### `__name__ == "__main__"` について { #about-name-main }
|
||||
### `__name__ == "__main__"` について
|
||||
|
||||
`__name__ == "__main__"` の主な目的は、ファイルが次のコマンドで呼び出されたときに実行されるコードを用意することです:
|
||||
|
||||
@@ -26,7 +26,7 @@ $ python myapp.py
|
||||
from myapp import app
|
||||
```
|
||||
|
||||
#### より詳しい説明 { #more-details }
|
||||
#### より詳しい説明
|
||||
|
||||
ファイルの名前が `myapp.py` だとします。
|
||||
|
||||
@@ -62,7 +62,7 @@ from myapp import app
|
||||
# Some more code
|
||||
```
|
||||
|
||||
その場合、`myapp.py` 内の自動的に作成された変数 `__name__` は、値として `"__main__"` を持ちません。
|
||||
`myapp.py` 内の自動変数には、値が `"__main __"` の変数 `__name__` はありません。
|
||||
|
||||
したがって、以下の行:
|
||||
|
||||
@@ -78,7 +78,7 @@ from myapp import app
|
||||
|
||||
///
|
||||
|
||||
## デバッガーでコードを実行 { #run-your-code-with-your-debugger }
|
||||
## デバッガーでコードを実行
|
||||
|
||||
コードから直接Uvicornサーバーを実行しているため、デバッガーから直接Pythonプログラム (FastAPIアプリケーション) を呼び出せます。
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# 依存関係としてのクラス { #classes-as-dependencies }
|
||||
# 依存関係としてのクラス
|
||||
|
||||
**依存性注入** システムを深く掘り下げる前に、先ほどの例をアップグレードしてみましょう。
|
||||
|
||||
## 前の例の`dict` { #a-dict-from-the-previous-example }
|
||||
## 前の例の`dict`
|
||||
|
||||
前の例では、依存関係("dependable")から`dict`を返していました:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}
|
||||
{* ../../docs_src/dependencies/tutorial001.py hl[9] *}
|
||||
|
||||
しかし、*path operation関数*のパラメータ`commons`に`dict`が含まれています。
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
もっとうまくやれるはずです...。
|
||||
|
||||
## 依存関係を作るもの { #what-makes-a-dependency }
|
||||
## 依存関係を作るもの
|
||||
|
||||
これまでは、依存関係が関数として宣言されているのを見てきました。
|
||||
|
||||
@@ -38,7 +38,7 @@ something(some_argument, some_keyword_argument="foo")
|
||||
|
||||
これを「呼び出し可能」なものと呼びます。
|
||||
|
||||
## 依存関係としてのクラス { #classes-as-dependencies_1 }
|
||||
## 依存関係としてのクラス
|
||||
|
||||
Pythonのクラスのインスタンスを作成する際に、同じ構文を使用していることに気づくかもしれません。
|
||||
|
||||
@@ -67,66 +67,48 @@ FastAPIが実際にチェックしているのは、それが「呼び出し可
|
||||
|
||||
それは、パラメータが全くない呼び出し可能なものにも適用されます。パラメータのない*path operation関数*と同じように。
|
||||
|
||||
そこで、上で紹介した依存関係の"dependable" `common_parameters`を`CommonQueryParams`クラスに変更します:
|
||||
そこで、上で紹介した依存関係の`common_parameters`を`CommonQueryParams`クラスに変更します:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}
|
||||
{* ../../docs_src/dependencies/tutorial002.py hl[11,12,13,14,15] *}
|
||||
|
||||
クラスのインスタンスを作成するために使用される`__init__`メソッドに注目してください:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}
|
||||
{* ../../docs_src/dependencies/tutorial002.py hl[12] *}
|
||||
|
||||
...以前の`common_parameters`と同じパラメータを持っています:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}
|
||||
{* ../../docs_src/dependencies/tutorial001.py hl[8] *}
|
||||
|
||||
これらのパラメータは **FastAPI** が依存関係を「解決」するために使用するものです。
|
||||
|
||||
どちらの場合も以下を持っています:
|
||||
|
||||
* `str`であるオプショナルの`q`クエリパラメータ。
|
||||
* デフォルトが`0`である`int`の`skip`クエリパラメータ。
|
||||
* デフォルトが`100`である`int`の`limit`クエリパラメータ。
|
||||
* オプショナルの`q`クエリパラメータ。
|
||||
* `skip`クエリパラメータ、デフォルトは`0`。
|
||||
* `limit`クエリパラメータ、デフォルトは`100`。
|
||||
|
||||
どちらの場合も、データは変換され、検証され、OpenAPIスキーマなどで文書化されます。
|
||||
|
||||
## 使用 { #use-it }
|
||||
## 使用
|
||||
|
||||
これで、このクラスを使用して依存関係を宣言することができます。
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}
|
||||
{* ../../docs_src/dependencies/tutorial002.py hl[19] *}
|
||||
|
||||
**FastAPI** は`CommonQueryParams`クラスを呼び出します。これにより、そのクラスの「インスタンス」が作成され、インスタンスはパラメータ`commons`として関数に渡されます。
|
||||
|
||||
## 型注釈と`Depends` { #type-annotation-vs-depends }
|
||||
## 型注釈と`Depends`
|
||||
|
||||
上のコードでは`CommonQueryParams`を2回書いていることに注目してください:
|
||||
|
||||
//// tab | Python 3.9+
|
||||
|
||||
```Python
|
||||
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+ 注釈なし
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
可能であれば`Annotated`バージョンを使用することを推奨します。
|
||||
|
||||
///
|
||||
|
||||
```Python
|
||||
commons: CommonQueryParams = Depends(CommonQueryParams)
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
以下にある最後の`CommonQueryParams`:
|
||||
|
||||
```Python
|
||||
... Depends(CommonQueryParams)
|
||||
... = Depends(CommonQueryParams)
|
||||
```
|
||||
|
||||
...は、**FastAPI** が依存関係を知るために実際に使用するものです。
|
||||
@@ -137,145 +119,55 @@ commons: CommonQueryParams = Depends(CommonQueryParams)
|
||||
|
||||
この場合、以下にある最初の`CommonQueryParams`:
|
||||
|
||||
//// tab | Python 3.9+
|
||||
|
||||
```Python
|
||||
commons: Annotated[CommonQueryParams, ...
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+ 注釈なし
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
可能であれば`Annotated`バージョンを使用することを推奨します。
|
||||
|
||||
///
|
||||
|
||||
```Python
|
||||
commons: CommonQueryParams ...
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
...は **FastAPI** に対して特別な意味をもちません。FastAPIはデータ変換や検証などには使用しません(それらのためには`Depends(CommonQueryParams)`を使用しています)。
|
||||
...は **FastAPI** に対して特別な意味をもちません。FastAPIはデータ変換や検証などには使用しません(それらのためには`= Depends(CommonQueryParams)`を使用しています)。
|
||||
|
||||
実際には以下のように書けばいいだけです:
|
||||
|
||||
//// tab | Python 3.9+
|
||||
|
||||
```Python
|
||||
commons: Annotated[Any, Depends(CommonQueryParams)]
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+ 注釈なし
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
可能であれば`Annotated`バージョンを使用することを推奨します。
|
||||
|
||||
///
|
||||
|
||||
```Python
|
||||
commons = Depends(CommonQueryParams)
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
以下にあるように:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}
|
||||
{* ../../docs_src/dependencies/tutorial003.py hl[19] *}
|
||||
|
||||
しかし、型を宣言することは推奨されています。そうすれば、エディタは`commons`のパラメータとして何が渡されるかを知ることができ、コードの補完や型チェックなどを行うのに役立ちます:
|
||||
|
||||
<img src="/img/tutorial/dependencies/image02.png">
|
||||
<img src="https://fastapi.tiangolo.com/img/tutorial/dependencies/image02.png">
|
||||
|
||||
## ショートカット { #shortcut }
|
||||
## ショートカット
|
||||
|
||||
しかし、ここでは`CommonQueryParams`を2回書くというコードの繰り返しが発生していることがわかります:
|
||||
|
||||
//// tab | Python 3.9+
|
||||
|
||||
```Python
|
||||
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+ 注釈なし
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
可能であれば`Annotated`バージョンを使用することを推奨します。
|
||||
|
||||
///
|
||||
|
||||
```Python
|
||||
commons: CommonQueryParams = Depends(CommonQueryParams)
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
依存関係が、クラス自体のインスタンスを作成するために**FastAPI**が「呼び出す」*特定の*クラスである場合、**FastAPI** はこれらのケースのショートカットを提供しています。
|
||||
|
||||
それらの具体的なケースについては以下のようにします:
|
||||
|
||||
以下のように書く代わりに:
|
||||
|
||||
//// tab | Python 3.9+
|
||||
|
||||
```Python
|
||||
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+ 注釈なし
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
可能であれば`Annotated`バージョンを使用することを推奨します。
|
||||
|
||||
///
|
||||
|
||||
```Python
|
||||
commons: CommonQueryParams = Depends(CommonQueryParams)
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
...以下のように書きます:
|
||||
|
||||
//// tab | Python 3.9+
|
||||
|
||||
```Python
|
||||
commons: Annotated[CommonQueryParams, Depends()]
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+ 注釈なし
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
可能であれば`Annotated`バージョンを使用することを推奨します。
|
||||
|
||||
///
|
||||
|
||||
```Python
|
||||
commons: CommonQueryParams = Depends()
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
パラメータの型として依存関係を宣言し、`Depends()`の中でパラメータを指定せず、`Depends()`をその関数のパラメータの「デフォルト」値(`=`のあとの値)として使用することで、`Depends(CommonQueryParams)`の中でクラス全体を*もう一度*書かなくてもよくなります。
|
||||
|
||||
同じ例では以下のようになります:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *}
|
||||
{* ../../docs_src/dependencies/tutorial004.py hl[19] *}
|
||||
|
||||
...そして **FastAPI** は何をすべきか知っています。
|
||||
|
||||
|
||||
@@ -1,69 +1,57 @@
|
||||
# path operation デコレータの依存関係 { #dependencies-in-path-operation-decorators }
|
||||
# path operationデコレータの依存関係
|
||||
|
||||
場合によっては、*path operation 関数*の中で依存関係の戻り値を実際には必要としないことがあります。
|
||||
場合によっては*path operation関数*の中で依存関係の戻り値を本当に必要としないこともあります。
|
||||
|
||||
または、依存関係が値を返さない場合もあります。
|
||||
もしくは、依存関係が値を返さない場合もあります。
|
||||
|
||||
しかし、それでも実行・解決される必要があります。
|
||||
しかし、それでも実行・解決する必要があります。
|
||||
|
||||
そのような場合、`Depends` で *path operation 関数* のパラメータを宣言する代わりに、*path operation デコレータ*に `dependencies` の `list` を追加できます。
|
||||
このような場合、*path operation関数*のパラメータを`Depends`で宣言する代わりに、*path operation decorator*に`dependencies`の`list`を追加することができます。
|
||||
|
||||
## *path operation デコレータ*に`dependencies`を追加 { #add-dependencies-to-the-path-operation-decorator }
|
||||
## *path operationデコレータ*への`dependencies`の追加
|
||||
|
||||
*path operation デコレータ*はオプション引数`dependencies`を受け取ります。
|
||||
*path operationデコレータ*はオプショナルの引数`dependencies`を受け取ります。
|
||||
|
||||
それは`Depends()`の`list`であるべきです:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[19] *}
|
||||
{* ../../docs_src/dependencies/tutorial006.py hl[17] *}
|
||||
|
||||
これらの依存関係は、通常の依存関係と同様に実行・解決されます。しかし、それらの値(何かを返す場合)は*path operation 関数*には渡されません。
|
||||
これらの依存関係は、通常の依存関係と同様に実行・解決されます。しかし、それらの値(何かを返す場合)は*path operation関数*には渡されません。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
一部のエディタは、未使用の関数パラメータをチェックしてエラーとして表示します。
|
||||
エディタによっては、未使用の関数パラメータをチェックしてエラーとして表示するものもあります。
|
||||
|
||||
これらの`dependencies`を*path operation デコレータ*で使用することで、エディタ/ツールのエラーを回避しつつ、確実に実行されるようにできます。
|
||||
`dependencies`を`path operationデコレータ`で使用することで、エディタやツールのエラーを回避しながら確実に実行することができます。
|
||||
|
||||
また、コード内の未使用のパラメータを見た新しい開発者が、それを不要だと思って混乱するのを避ける助けにもなるかもしれません。
|
||||
また、コードの未使用のパラメータがあるのを見て、それが不要だと思ってしまうような新しい開発者の混乱を避けるのにも役立つかもしれません。
|
||||
|
||||
///
|
||||
|
||||
/// info | 情報
|
||||
## 依存関係のエラーと戻り値
|
||||
|
||||
この例では、架空のカスタムヘッダー `X-Key` と `X-Token` を使用しています。
|
||||
通常使用している依存関係の*関数*と同じものを使用することができます。
|
||||
|
||||
しかし実際のケースでセキュリティを実装する際は、統合された[Security utilities(次の章)](../security/index.md){.internal-link target=_blank}を使うことで、より多くの利点を得られます。
|
||||
### 依存関係の要件
|
||||
|
||||
///
|
||||
これらはリクエストの要件(ヘッダのようなもの)やその他のサブ依存関係を宣言することができます:
|
||||
|
||||
## 依存関係のエラーと戻り値 { #dependencies-errors-and-return-values }
|
||||
{* ../../docs_src/dependencies/tutorial006.py hl[6,11] *}
|
||||
|
||||
通常使用している依存関係の*関数*と同じものを使用できます。
|
||||
### 例外の発生
|
||||
|
||||
### 依存関係の要件 { #dependency-requirements }
|
||||
これらの依存関係は通常の依存関係と同じように、例外を`raise`発生させることができます:
|
||||
|
||||
これらはリクエストの要件(ヘッダーのようなもの)やその他のサブ依存関係を宣言できます:
|
||||
{* ../../docs_src/dependencies/tutorial006.py hl[8,13] *}
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[8,13] *}
|
||||
|
||||
### 例外の発生 { #raise-exceptions }
|
||||
|
||||
これらの依存関係は、通常の依存関係と同じように例外を`raise`できます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[10,15] *}
|
||||
|
||||
### 戻り値 { #return-values }
|
||||
### 戻り値
|
||||
|
||||
そして、値を返すことも返さないこともできますが、値は使われません。
|
||||
|
||||
つまり、すでにどこかで使っている通常の依存関係(値を返すもの)を再利用でき、値は使われなくても依存関係は実行されます:
|
||||
つまり、すでにどこかで使っている通常の依存関係(値を返すもの)を再利用することができ、値は使われなくても依存関係は実行されます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[11,16] *}
|
||||
{* ../../docs_src/dependencies/tutorial006.py hl[9,14] *}
|
||||
|
||||
## *path operation*のグループに対する依存関係 { #dependencies-for-a-group-of-path-operations }
|
||||
## *path operations*のグループに対する依存関係
|
||||
|
||||
後で、より大きなアプリケーションを(おそらく複数ファイルで)構造化する方法([Bigger Applications - Multiple Files](../../tutorial/bigger-applications.md){.internal-link target=_blank})について読むときに、*path operation*のグループに対して単一の`dependencies`パラメータを宣言する方法を学びます。
|
||||
|
||||
## グローバル依存関係 { #global-dependencies }
|
||||
|
||||
次に、`FastAPI`アプリケーション全体に依存関係を追加して、各*path operation*に適用する方法を見ていきます。
|
||||
後で、より大きなアプリケーションの構造([Bigger Applications - Multiple Files](../../tutorial/bigger-applications.md){.internal-link target=_blank})について読む時に、おそらく複数のファイルを使用して、*path operations*のグループに対して単一の`dependencies`パラメータを宣言する方法を学ぶでしょう。
|
||||
|
||||
@@ -1,12 +1,24 @@
|
||||
# `yield`を持つ依存関係 { #dependencies-with-yield }
|
||||
# yieldを持つ依存関係
|
||||
|
||||
FastAPIは、いくつかの<abbr title='sometimes also called "exit code", "cleanup code", "teardown code", "closing code", "context manager exit code", etc. – 「exit code」「cleanup code」「teardown code」「closing code」「context manager exit code」などと呼ばれることもあります。'>終了後の追加のステップ</abbr>を行う依存関係をサポートしています。
|
||||
FastAPIは、いくつかの<abbr title='時々"exit"、"cleanup"、"teardown"、"close"、"context managers"、 ...のように呼ばれる'>終了後の追加のステップ</abbr>を行う依存関係をサポートしています。
|
||||
|
||||
これを行うには、`return`の代わりに`yield`を使い、その後に追加のステップ(コード)を書きます。
|
||||
これを行うには、`return`の代わりに`yield`を使い、その後に追加のステップを書きます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`yield`は必ず依存関係ごとに1回だけ使用するようにしてください。
|
||||
`yield`は必ず一度だけ使用するようにしてください。
|
||||
|
||||
///
|
||||
|
||||
/// info | 情報
|
||||
|
||||
これを動作させるには、**Python 3.7** 以上を使用するか、**Python 3.6** では"backports"をインストールする必要があります:
|
||||
|
||||
```
|
||||
pip install async-exit-stack async-generator
|
||||
```
|
||||
|
||||
これにより<a href="https://github.com/sorcio/async_exit_stack" class="external-link" target="_blank">async-exit-stack</a>と<a href="https://github.com/python-trio/async_generator" class="external-link" target="_blank">async-generator</a>がインストールされます。
|
||||
|
||||
///
|
||||
|
||||
@@ -23,21 +35,21 @@ FastAPIは、いくつかの<abbr title='sometimes also called "exit code", "cle
|
||||
|
||||
///
|
||||
|
||||
## `yield`を持つデータベースの依存関係 { #a-database-dependency-with-yield }
|
||||
## `yield`を持つデータベースの依存関係
|
||||
|
||||
例えば、これを使ってデータベースセッションを作成し、終了後にそれを閉じることができます。
|
||||
|
||||
レスポンスを作成する前に、`yield`文より前のコード(および`yield`文を含む)が実行されます:
|
||||
レスポンスを送信する前に`yield`文を含む前のコードのみが実行されます。
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial007_py39.py hl[2:4] *}
|
||||
{* ../../docs_src/dependencies/tutorial007.py hl[2,3,4] *}
|
||||
|
||||
生成された値は、*path operations*や他の依存関係に注入されるものです:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial007_py39.py hl[4] *}
|
||||
{* ../../docs_src/dependencies/tutorial007.py hl[4] *}
|
||||
|
||||
`yield`文に続くコードは、レスポンスの後に実行されます:
|
||||
`yield`文に続くコードは、レスポンスが送信された後に実行されます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial007_py39.py hl[5:6] *}
|
||||
{* ../../docs_src/dependencies/tutorial007.py hl[5,6] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
@@ -47,27 +59,27 @@ FastAPIは、いくつかの<abbr title='sometimes also called "exit code", "cle
|
||||
|
||||
///
|
||||
|
||||
## `yield`と`try`を持つ依存関係 { #a-dependency-with-yield-and-try }
|
||||
## `yield`と`try`を持つ依存関係
|
||||
|
||||
`yield`を持つ依存関係で`try`ブロックを使用した場合、その依存関係を使用した際にスローされたあらゆる例外を受け取ることになります。
|
||||
`yield`を持つ依存関係で`try`ブロックを使用した場合、その依存関係を使用した際に発生した例外を受け取ることになります。
|
||||
|
||||
例えば、途中のどこかの時点で、別の依存関係や*path operation*の中で、データベーストランザクションを「ロールバック」したり、その他の例外を作成したりするコードがあった場合、依存関係の中で例外を受け取ることになります。
|
||||
例えば、途中のどこかの時点で、別の依存関係や*path operation*の中で、データベーストランザクションを「ロールバック」したり、その他のエラーを作成したりするコードがあった場合、依存関係の中で例外を受け取ることになります。
|
||||
|
||||
そのため、依存関係の中にある特定の例外を`except SomeException`で探すことができます。
|
||||
|
||||
同様に、`finally`を用いて例外があったかどうかにかかわらず、終了ステップを確実に実行することができます。
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial007_py39.py hl[3,5] *}
|
||||
{* ../../docs_src/dependencies/tutorial007.py hl[3,5] *}
|
||||
|
||||
## `yield`を持つサブ依存関係 { #sub-dependencies-with-yield }
|
||||
## `yield`を持つサブ依存関係
|
||||
|
||||
任意の大きさや形のサブ依存関係やサブ依存関係の「ツリー」を持つことができ、その中で`yield`を使用することができます。
|
||||
|
||||
**FastAPI** は、`yield`を持つ各依存関係の「終了コード」が正しい順番で実行されていることを確認します。
|
||||
|
||||
例えば、`dependency_c`は`dependency_b`に、そして`dependency_b`は`dependency_a`に依存することができます:
|
||||
例えば、`dependency_c`は`dependency_b`と`dependency_b`に依存する`dependency_a`に、依存することができます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[6,14,22] *}
|
||||
{* ../../docs_src/dependencies/tutorial008.py hl[4,12,20] *}
|
||||
|
||||
そして、それらはすべて`yield`を使用することができます。
|
||||
|
||||
@@ -75,11 +87,11 @@ FastAPIは、いくつかの<abbr title='sometimes also called "exit code", "cle
|
||||
|
||||
そして、`dependency_b`は`dependency_a`(ここでは`dep_a`という名前)の値を終了コードで利用できるようにする必要があります。
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[18:19,26:27] *}
|
||||
{* ../../docs_src/dependencies/tutorial008.py hl[16,17,24,25] *}
|
||||
|
||||
同様に、`yield`を持つ依存関係と`return`を持つ他の依存関係をいくつか持ち、それらの一部が他の一部に依存するようにもできます。
|
||||
同様に、`yield`と`return`が混在した依存関係を持つこともできます。
|
||||
|
||||
また、単一の依存関係を持っていて、`yield`を持つ他の依存関係をいくつか必要とすることもできます。
|
||||
また、単一の依存関係を持っていて、`yield`などの他の依存関係をいくつか必要とすることもできます。
|
||||
|
||||
依存関係の組み合わせは自由です。
|
||||
|
||||
@@ -93,46 +105,32 @@ FastAPIは、いくつかの<abbr title='sometimes also called "exit code", "cle
|
||||
|
||||
///
|
||||
|
||||
## `yield`と`HTTPException`を持つ依存関係 { #dependencies-with-yield-and-httpexception }
|
||||
## `yield`と`HTTPException`を持つ依存関係
|
||||
|
||||
`yield`を持つ依存関係を使い、何らかのコードを実行し、その後に`finally`の後で終了コードを実行しようとする`try`ブロックを持てることが分かりました。
|
||||
`yield`と例外をキャッチする`try`ブロックを持つことができる依存関係を使用することができることがわかりました。
|
||||
|
||||
また、`except`を使って発生した例外をキャッチし、それに対して何かをすることもできます。
|
||||
`yield`の後の終了コードで`HTTPException`などを発生させたくなるかもしれません。しかし**それはうまくいきません**
|
||||
|
||||
例えば、`HTTPException`のように別の例外を発生させることができます。
|
||||
`yield`を持つ依存関係の終了コードは[例外ハンドラ](../handling-errors.md#_4){.internal-link target=_blank}の*後に*実行されます。依存関係によって投げられた例外を終了コード(`yield`の後)でキャッチするものはなにもありません。
|
||||
|
||||
つまり、`yield`の後に`HTTPException`を発生させた場合、`HTTTPException`をキャッチしてHTTP 400のレスポンスを返すデフォルトの(あるいは任意のカスタムの)例外ハンドラは、その例外をキャッチすることができなくなります。
|
||||
|
||||
これは、依存関係に設定されているもの(例えば、DBセッション)を、例えば、バックグラウンドタスクで使用できるようにするものです。
|
||||
|
||||
バックグラウンドタスクはレスポンスが送信された*後*に実行されます。そのため、*すでに送信されている*レスポンスを変更する方法すらないので、`HTTPException`を発生させる方法はありません。
|
||||
|
||||
しかし、バックグラウンドタスクがDBエラーを発生させた場合、少なくとも`yield`で依存関係のセッションをロールバックしたり、きれいに閉じたりすることができ、エラーをログに記録したり、リモートのトラッキングシステムに報告したりすることができます。
|
||||
|
||||
例外が発生する可能性があるコードがある場合は、最も普通の「Python流」なことをして、コードのその部分に`try`ブロックを追加してください。
|
||||
|
||||
レスポンスを返したり、レスポンスを変更したり、`HTTPException`を発生させたりする*前に*処理したいカスタム例外がある場合は、[カスタム例外ハンドラ](../handling-errors.md#_4){.internal-link target=_blank}を作成してください。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
これはやや高度なテクニックで、ほとんどの場合は本当に必要にはなりません。例えば、*path operation 関数*など、アプリケーションコードの他の場所から(`HTTPException`を含む)例外を発生させられるためです。
|
||||
|
||||
ただし必要であれば使えます。 🤓
|
||||
`HTTPException`を含む例外は、`yield`の*前*でも発生させることができます。ただし、後ではできません。
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008b_an_py39.py hl[18:22,31] *}
|
||||
|
||||
例外をキャッチして、それに基づいてカスタムレスポンスを作成したい場合は、[カスタム例外ハンドラ](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}を作成してください。
|
||||
|
||||
## `yield`と`except`を持つ依存関係 { #dependencies-with-yield-and-except }
|
||||
|
||||
`yield`を持つ依存関係で`except`を使って例外をキャッチし、それを再度raiseしない(または新しい例外をraiseしない)場合、通常のPythonと同じように、FastAPIは例外があったことに気づけません:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008c_an_py39.py hl[15:16] *}
|
||||
|
||||
この場合、(`HTTPException`やそれに類するものをraiseしていないため)クライアントには適切に*HTTP 500 Internal Server Error*レスポンスが返りますが、サーバーには**ログが一切残らず**、何がエラーだったのかを示す他の手がかりもありません。 😱
|
||||
|
||||
### `yield`と`except`を持つ依存関係では常に`raise`する { #always-raise-in-dependencies-with-yield-and-except }
|
||||
|
||||
`yield`を持つ依存関係で例外をキャッチした場合、別の`HTTPException`などをraiseするのでない限り、**元の例外を再raiseすべきです**。
|
||||
|
||||
`raise`を使うと同じ例外を再raiseできます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008d_an_py39.py hl[17] *}
|
||||
|
||||
これでクライアントは同じ*HTTP 500 Internal Server Error*レスポンスを受け取りますが、サーバーのログにはカスタムの`InternalError`が残ります。 😎
|
||||
|
||||
## `yield`を持つ依存関係の実行 { #execution-of-dependencies-with-yield }
|
||||
|
||||
実行の順序は多かれ少なかれ以下の図のようになります。時間は上から下へと流れていきます。そして、各列はコードを相互作用させたり、実行したりしている部分の一つです。
|
||||
|
||||
```mermaid
|
||||
@@ -144,29 +142,32 @@ participant dep as Dep with yield
|
||||
participant operation as Path Operation
|
||||
participant tasks as Background tasks
|
||||
|
||||
Note over client,operation: Can raise exceptions, including HTTPException
|
||||
Note over client,tasks: Can raise exception for dependency, handled after response is sent
|
||||
Note over client,operation: Can raise HTTPException and can change the response
|
||||
client ->> dep: Start request
|
||||
Note over dep: Run code up to yield
|
||||
opt raise Exception
|
||||
dep -->> handler: Raise Exception
|
||||
opt raise
|
||||
dep -->> handler: Raise HTTPException
|
||||
handler -->> client: HTTP error response
|
||||
dep -->> dep: Raise other exception
|
||||
end
|
||||
dep ->> operation: Run dependency, e.g. DB session
|
||||
opt raise
|
||||
operation -->> dep: Raise Exception (e.g. HTTPException)
|
||||
opt handle
|
||||
dep -->> dep: Can catch exception, raise a new HTTPException, raise other exception
|
||||
end
|
||||
operation -->> handler: Raise HTTPException
|
||||
handler -->> client: HTTP error response
|
||||
operation -->> dep: Raise other exception
|
||||
end
|
||||
|
||||
operation ->> client: Return response to client
|
||||
Note over client,operation: Response is already sent, can't change it anymore
|
||||
opt Tasks
|
||||
operation -->> tasks: Send background tasks
|
||||
end
|
||||
opt Raise other exception
|
||||
tasks -->> tasks: Handle exceptions in the background task code
|
||||
tasks -->> dep: Raise other exception
|
||||
end
|
||||
Note over dep: After yield
|
||||
opt Handle other exception
|
||||
dep -->> dep: Handle exception, can't change response. E.g. close DB session.
|
||||
end
|
||||
```
|
||||
|
||||
@@ -180,63 +181,15 @@ participant tasks as Background tasks
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
*path operation 関数*のコードで例外をraiseした場合、`HTTPException`を含め、それはyieldを持つ依存関係に渡されます。ほとんどの場合、その例外が正しく処理されるように、`yield`を持つ依存関係から同じ例外、または新しい例外を再raiseしたくなるでしょう。
|
||||
この図は`HTTPException`を示していますが、[カスタム例外ハンドラ](../handling-errors.md#_4){.internal-link target=_blank}を作成することで、他の例外を発生させることもできます。そして、その例外は依存関係の終了コードではなく、そのカスタム例外ハンドラによって処理されます。
|
||||
|
||||
しかし例外ハンドラで処理されない例外を発生させた場合は、依存関係の終了コードで処理されます。
|
||||
|
||||
///
|
||||
|
||||
## 早期終了と`scope` { #early-exit-and-scope }
|
||||
## コンテキストマネージャ
|
||||
|
||||
通常、`yield`を持つ依存関係の終了コードは、クライアントに**レスポンスが送信された後**に実行されます。
|
||||
|
||||
しかし、*path operation 関数*からreturnした後に依存関係を使う必要がないと分かっている場合は、`Depends(scope="function")`を使って、**レスポンスが送信される前**に、*path operation 関数*のreturn後に依存関係を閉じるべきだとFastAPIに伝えられます。
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008e_an_py39.py hl[12,16] *}
|
||||
|
||||
`Depends()`は、以下のいずれかを取る`scope`パラメータを受け取ります:
|
||||
|
||||
* `"function"`: リクエストを処理する*path operation 関数*の前に依存関係を開始し、*path operation 関数*の終了後に依存関係を終了しますが、クライアントにレスポンスが返される**前**に終了します。つまり、依存関係関数は*path operation 関数*の**周囲**で実行されます。
|
||||
* `"request"`: リクエストを処理する*path operation 関数*の前に依存関係を開始し(`"function"`を使用する場合と同様)、クライアントにレスポンスが返された**後**に終了します。つまり、依存関係関数は**リクエスト**とレスポンスのサイクルの**周囲**で実行されます。
|
||||
|
||||
指定されておらず、依存関係に`yield`がある場合、デフォルトで`scope`は`"request"`になります。
|
||||
|
||||
### サブ依存関係の`scope` { #scope-for-sub-dependencies }
|
||||
|
||||
`scope="request"`(デフォルト)を持つ依存関係を宣言する場合、どのサブ依存関係も`"request"`の`scope`を持つ必要があります。
|
||||
|
||||
しかし、`"function"`の`scope`を持つ依存関係は、`"function"`と`"request"`の`scope`を持つ依存関係を持てます。
|
||||
|
||||
これは、いずれの依存関係も、サブ依存関係より前に終了コードを実行できる必要があるためです(終了コードの実行中にサブ依存関係をまだ使う必要がある可能性があるためです)。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
|
||||
participant client as Client
|
||||
participant dep_req as Dep scope="request"
|
||||
participant dep_func as Dep scope="function"
|
||||
participant operation as Path Operation
|
||||
|
||||
client ->> dep_req: Start request
|
||||
Note over dep_req: Run code up to yield
|
||||
dep_req ->> dep_func: Pass dependency
|
||||
Note over dep_func: Run code up to yield
|
||||
dep_func ->> operation: Run path operation with dependency
|
||||
operation ->> dep_func: Return from path operation
|
||||
Note over dep_func: Run code after yield
|
||||
Note over dep_func: ✅ Dependency closed
|
||||
dep_func ->> client: Send response to client
|
||||
Note over client: Response sent
|
||||
Note over dep_req: Run code after yield
|
||||
Note over dep_req: ✅ Dependency closed
|
||||
```
|
||||
|
||||
## `yield`、`HTTPException`、`except`、バックグラウンドタスクを持つ依存関係 { #dependencies-with-yield-httpexception-except-and-background-tasks }
|
||||
|
||||
`yield`を持つ依存関係は、さまざまなユースケースをカバーし、いくつかの問題を修正するために、時間とともに進化してきました。
|
||||
|
||||
FastAPIの異なるバージョンで何が変わったのかを知りたい場合は、上級ガイドの[上級の依存関係 - `yield`、`HTTPException`、`except`、バックグラウンドタスクを持つ依存関係](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks){.internal-link target=_blank}で詳しく読めます。
|
||||
## コンテキストマネージャ { #context-managers }
|
||||
|
||||
### 「コンテキストマネージャ」とは { #what-are-context-managers }
|
||||
### 「コンテキストマネージャ」とは
|
||||
|
||||
「コンテキストマネージャ」とは、`with`文の中で使用できるPythonオブジェクトのことです。
|
||||
|
||||
@@ -252,9 +205,9 @@ with open("./somefile.txt") as f:
|
||||
|
||||
`with`ブロックが終了すると、例外があったとしてもファイルを確かに閉じます。
|
||||
|
||||
`yield`を持つ依存関係を作成すると、**FastAPI** は内部的にそれをコンテキストマネージャに変換し、他の関連ツールと組み合わせます。
|
||||
`yield`を依存関係を作成すると、**FastAPI** は内部的にそれをコンテキストマネージャに変換し、他の関連ツールと組み合わせます。
|
||||
|
||||
### `yield`を持つ依存関係でのコンテキストマネージャの使用 { #using-context-managers-in-dependencies-with-yield }
|
||||
### `yield`を持つ依存関係でのコンテキストマネージャの使用
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
@@ -268,7 +221,7 @@ Pythonでは、<a href="https://docs.python.org/3/reference/datamodel.html#conte
|
||||
|
||||
また、依存関数の中で`with`や`async with`文を使用することによって`yield`を持つ **FastAPI** の依存関係の中でそれらを使用することができます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial010_py39.py hl[1:9,13] *}
|
||||
{* ../../docs_src/dependencies/tutorial010.py hl[1,2,3,4,5,6,7,8,9,13] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# 依存関係 { #dependencies }
|
||||
# 依存関係 - 最初のステップ
|
||||
|
||||
**FastAPI** は非常に強力でありながら直感的な **<abbr title="also known as components, resources, providers, services, injectables">Dependency Injection</abbr>** システムを持っています。
|
||||
** FastAPI** は非常に強力でありながら直感的な **<abbr title="コンポーネント、リソース、プロバイダ、サービス、インジェクタブルとしても知られている">依存性注入</abbr>** システムを持っています。
|
||||
|
||||
それは非常にシンプルに使用できるように設計されており、開発者が他のコンポーネント **FastAPI** と統合するのが非常に簡単になるように設計されています。
|
||||
|
||||
## 「Dependency Injection」とは { #what-is-dependency-injection }
|
||||
## 「依存性注入」とは
|
||||
|
||||
**「Dependency Injection」** とは、プログラミングにおいて、コード(この場合は、*path operation 関数*)が動作したり使用したりするために必要なもの(「依存関係」)を宣言する方法があることを意味します:
|
||||
**「依存性注入」** とは、プログラミングにおいて、コード(この場合は、*path operation関数*)が動作したり使用したりするために必要なもの(「依存関係」)を宣言する方法があることを意味します:
|
||||
|
||||
そして、そのシステム(この場合は、**FastAPI**)は、必要な依存関係をコードに提供するために必要なことは何でも行います(依存関係を「注入」します)。
|
||||
|
||||
@@ -19,27 +19,27 @@
|
||||
|
||||
これらすべてを、コードの繰り返しを最小限に抑えながら行います。
|
||||
|
||||
## 最初のステップ { #first-steps }
|
||||
## 最初のステップ
|
||||
|
||||
非常にシンプルな例を見てみましょう。あまりにもシンプルなので、今のところはあまり参考にならないでしょう。
|
||||
|
||||
しかし、この方法では **Dependency Injection** システムがどのように機能するかに焦点を当てることができます。
|
||||
しかし、この方法では **依存性注入** システムがどのように機能するかに焦点を当てることができます。
|
||||
|
||||
### 依存関係(「dependable」)の作成 { #create-a-dependency-or-dependable }
|
||||
### 依存関係の作成
|
||||
|
||||
まずは依存関係に注目してみましょう。
|
||||
|
||||
以下のように、*path operation 関数*と同じパラメータを全て取ることができる関数にすぎません:
|
||||
以下のように、*path operation関数*と同じパラメータを全て取ることができる関数にすぎません:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}
|
||||
{* ../../docs_src/dependencies/tutorial001.py hl[8,9] *}
|
||||
|
||||
これだけです。
|
||||
|
||||
**2行**。
|
||||
|
||||
そして、それはすべての*path operation 関数*が持っているのと同じ形と構造を持っています。
|
||||
そして、それはすべての*path operation関数*が持っているのと同じ形と構造を持っています。
|
||||
|
||||
「デコレータ」を含まない(`@app.get("/some-path")`を含まない)*path operation 関数*と考えることもできます。
|
||||
「デコレータ」を含まない(`@app.get("/some-path")`を含まない)*path operation関数*と考えることもできます。
|
||||
|
||||
そして何でも返すことができます。
|
||||
|
||||
@@ -51,25 +51,15 @@
|
||||
|
||||
そして、これらの値を含む`dict`を返します。
|
||||
|
||||
/// info | 情報
|
||||
### `Depends`のインポート
|
||||
|
||||
FastAPI はバージョン 0.95.0 で `Annotated` のサポートを追加し(そして推奨し始めました)。
|
||||
{* ../../docs_src/dependencies/tutorial001.py hl[3] *}
|
||||
|
||||
古いバージョンを使用している場合、`Annotated` を使おうとするとエラーになります。
|
||||
### "dependant"での依存関係の宣言
|
||||
|
||||
`Annotated` を使用する前に、少なくとも 0.95.1 まで [FastAPI のバージョンをアップグレード](../../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} してください。
|
||||
*path operation関数*のパラメータに`Body`や`Query`などを使用するのと同じように、新しいパラメータに`Depends`を使用することができます:
|
||||
|
||||
///
|
||||
|
||||
### `Depends`のインポート { #import-depends }
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}
|
||||
|
||||
### 「dependant」での依存関係の宣言 { #declare-the-dependency-in-the-dependant }
|
||||
|
||||
*path operation 関数*のパラメータに`Body`や`Query`などを使用するのと同じように、新しいパラメータに`Depends`を使用することができます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}
|
||||
{* ../../docs_src/dependencies/tutorial001.py hl[13,18] *}
|
||||
|
||||
関数のパラメータに`Depends`を使用するのは`Body`や`Query`などと同じですが、`Depends`の動作は少し異なります。
|
||||
|
||||
@@ -77,9 +67,7 @@ FastAPI はバージョン 0.95.0 で `Annotated` のサポートを追加し(
|
||||
|
||||
このパラメータは関数のようなものである必要があります。
|
||||
|
||||
直接**呼び出しません**(末尾に括弧を付けません)。`Depends()` のパラメータとして渡すだけです。
|
||||
|
||||
そして、その関数は、*path operation 関数*が行うのと同じ方法でパラメータを取ります。
|
||||
そして、その関数は、*path operation関数*が行うのと同じ方法でパラメータを取ります。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
@@ -91,7 +79,7 @@ FastAPI はバージョン 0.95.0 で `Annotated` のサポートを追加し(
|
||||
|
||||
* 依存関係("dependable")関数を正しいパラメータで呼び出します。
|
||||
* 関数の結果を取得します。
|
||||
* *path operation 関数*のパラメータにその結果を代入してください。
|
||||
* *path operation関数*のパラメータにその結果を代入してください。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
@@ -104,7 +92,7 @@ common_parameters --> read_items
|
||||
common_parameters --> read_users
|
||||
```
|
||||
|
||||
この方法では、共有されるコードを一度書き、**FastAPI** が*path operation*のための呼び出しを行います。
|
||||
この方法では、共有されるコードを一度書き、**FastAPI** が*path operations*のための呼び出しを行います。
|
||||
|
||||
/// check | 確認
|
||||
|
||||
@@ -114,85 +102,59 @@ common_parameters --> read_users
|
||||
|
||||
///
|
||||
|
||||
## `Annotated` 依存関係の共有 { #share-annotated-dependencies }
|
||||
## `async`にするかどうか
|
||||
|
||||
上の例では、ほんの少し **コードの重複** があることがわかります。
|
||||
|
||||
`common_parameters()` 依存関係を使う必要があるときは、型アノテーションと `Depends()` を含むパラメータ全体を書く必要があります:
|
||||
|
||||
```Python
|
||||
commons: Annotated[dict, Depends(common_parameters)]
|
||||
```
|
||||
|
||||
しかし、`Annotated` を使用しているので、その `Annotated` 値を変数に格納して複数箇所で使えます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
これはただの標準 Python で、「type alias」と呼ばれ、**FastAPI** 固有のものではありません。
|
||||
|
||||
しかし **FastAPI** は `Annotated` を含む Python 標準に基づいているため、このテクニックをコードで使えます。 😎
|
||||
|
||||
///
|
||||
|
||||
依存関係は期待どおりに動作し続け、**一番良い点** は **型情報が保持される** ことです。つまり、エディタは **自動補完**、**インラインエラー** などを提供し続けられます。`mypy` のような他のツールでも同様です。
|
||||
|
||||
これは **大規模なコードベース** で、**同じ依存関係** を **多くの *path operation*** で何度も使う場合に特に役立ちます。
|
||||
|
||||
## `async`にするかどうか { #to-async-or-not-to-async }
|
||||
|
||||
依存関係は **FastAPI**(*path operation 関数*と同じ)からも呼び出されるため、関数を定義する際にも同じルールが適用されます。
|
||||
依存関係は **FastAPI**(*path operation関数*と同じ)からも呼び出されるため、関数を定義する際にも同じルールが適用されます。
|
||||
|
||||
`async def`や通常の`def`を使用することができます。
|
||||
|
||||
また、通常の`def`*path operation 関数*の中に`async def`を入れて依存関係を宣言したり、`async def`*path operation 関数*の中に`def`を入れて依存関係を宣言したりすることなどができます。
|
||||
また、通常の`def`*path operation関数*の中に`async def`を入れて依存関係を宣言したり、`async def`*path operation関数*の中に`def`を入れて依存関係を宣言したりすることなどができます。
|
||||
|
||||
それは重要ではありません。**FastAPI** は何をすべきかを知っています。
|
||||
|
||||
/// note | 備考
|
||||
|
||||
わからない場合は、ドキュメントの[Async: *"In a hurry?"*](../../async.md#in-a-hurry){.internal-link target=_blank}の中の`async`と`await`についてのセクションを確認してください。
|
||||
わからない場合は、ドキュメントの[Async: *"In a hurry?"*](../../async.md){.internal-link target=_blank}の中の`async`と`await`についてのセクションを確認してください。
|
||||
|
||||
///
|
||||
|
||||
## OpenAPIとの統合 { #integrated-with-openapi }
|
||||
## OpenAPIとの統合
|
||||
|
||||
依存関係(およびサブ依存関係)のすべてのリクエスト宣言、検証、および要件は、同じOpenAPIスキーマに統合されます。
|
||||
|
||||
つまり、対話型ドキュメントにはこれらの依存関係から得られる全ての情報も含まれているということです:
|
||||
|
||||
<img src="/img/tutorial/dependencies/image01.png">
|
||||
<img src="https://fastapi.tiangolo.com/img/tutorial/dependencies/image01.png">
|
||||
|
||||
## 簡単な使い方 { #simple-usage }
|
||||
## 簡単な使い方
|
||||
|
||||
見てみると、*path*と*operation*が一致した時に*path operation 関数*が宣言されていて、**FastAPI** が正しいパラメータで関数を呼び出してリクエストからデータを抽出する処理をしています。
|
||||
見てみると、*path*と*operation*が一致した時に*path operation関数*が宣言されていて、**FastAPI** が正しいパラメータで関数を呼び出してリクエストからデータを抽出する処理をしています。
|
||||
|
||||
実は、すべての(あるいはほとんどの)Webフレームワークは、このように動作します。
|
||||
|
||||
これらの関数を直接呼び出すことはありません。これらの関数はフレームワーク(この場合は、**FastAPI**)によって呼び出されます。
|
||||
|
||||
Dependency Injection システムでは、**FastAPI** に*path operation 関数*もまた、*path operation 関数*の前に実行されるべき他の何かに「依存」していることを伝えることができ、**FastAPI** がそれを実行し、結果を「注入」することを引き受けます。
|
||||
依存性注入システムでは、**FastAPI** に*path operation*もまた、*path operation関数*の前に実行されるべき他の何かに「依存」していることを伝えることができ、**FastAPI** がそれを実行し、結果を「注入」することを引き受けます。
|
||||
|
||||
他にも、「dependency injection」と同じような考えの一般的な用語があります:
|
||||
他にも、「依存性注入」と同じような考えの一般的な用語があります:
|
||||
|
||||
* resources
|
||||
* providers
|
||||
* services
|
||||
* injectables
|
||||
* components
|
||||
* リソース
|
||||
* プロバイダ
|
||||
* サービス
|
||||
* インジェクタブル
|
||||
* コンポーネント
|
||||
|
||||
## **FastAPI** プラグイン { #fastapi-plug-ins }
|
||||
## **FastAPI** プラグイン
|
||||
|
||||
統合や「プラグイン」は **Dependency Injection** システムを使って構築することができます。しかし、実際には、**「プラグイン」を作成する必要はありません**。依存関係を使用することで、無限の数の統合やインタラクションを宣言することができ、それが*path operation 関数*で利用可能になるからです。
|
||||
統合や「プラグイン」は **依存性注入** システムを使って構築することができます。しかし、実際には、**「プラグイン」を作成する必要はありません**。依存関係を使用することで、無限の数の統合やインタラクションを宣言することができ、それが**path operation関数*で利用可能になるからです。
|
||||
|
||||
依存関係は非常にシンプルで直感的な方法で作成することができ、必要なPythonパッケージをインポートするだけで、*文字通り*数行のコードでAPI関数と統合することができます。
|
||||
|
||||
次の章では、リレーショナルデータベースやNoSQLデータベース、セキュリティなどについて、その例を見ていきます。
|
||||
|
||||
## **FastAPI** 互換性 { #fastapi-compatibility }
|
||||
## **FastAPI** 互換性
|
||||
|
||||
dependency injection システムがシンプルなので、**FastAPI** は以下のようなものと互換性があります:
|
||||
依存性注入システムがシンプルなので、**FastAPI** は以下のようなものと互換性があります:
|
||||
|
||||
* すべてのリレーショナルデータベース
|
||||
* NoSQLデータベース
|
||||
@@ -203,15 +165,15 @@ dependency injection システムがシンプルなので、**FastAPI** は以
|
||||
* レスポンスデータ注入システム
|
||||
* など。
|
||||
|
||||
## シンプルでパワフル { #simple-and-powerful }
|
||||
## シンプルでパワフル
|
||||
|
||||
階層的な dependency injection システムは、定義や使用方法が非常にシンプルであるにもかかわらず、非常に強力なものとなっています。
|
||||
階層依存性注入システムは、定義や使用方法が非常にシンプルであるにもかかわらず、非常に強力なものとなっています。
|
||||
|
||||
依存関係が、さらに依存関係を定義することもできます。
|
||||
依存関係事態を定義する依存関係を定義することができます。
|
||||
|
||||
最終的には、依存関係の階層ツリーが構築され、**Dependency Injection**システムが、これらの依存関係(およびそのサブ依存関係)をすべて解決し、各ステップで結果を提供(注入)します。
|
||||
最終的には、依存関係の階層ツリーが構築され、**依存性注入**システムが、これらの依存関係(およびそのサブ依存関係)をすべて解決し、各ステップで結果を提供(注入)します。
|
||||
|
||||
例えば、4つのAPIエンドポイント(*path operation*)があるとします:
|
||||
例えば、4つのAPIエンドポイント(*path operations*)があるとします:
|
||||
|
||||
* `/items/public/`
|
||||
* `/items/private/`
|
||||
@@ -243,8 +205,8 @@ admin_user --> activate_user
|
||||
paying_user --> pro_items
|
||||
```
|
||||
|
||||
## **OpenAPI** との統合 { #integrated-with-openapi_1 }
|
||||
## **OpenAPI** との統合
|
||||
|
||||
これら全ての依存関係は、要件を宣言すると同時に、*path operation*にパラメータやバリデーションを追加します。
|
||||
これら全ての依存関係は、要件を宣言すると同時に、*path operations*にパラメータやバリデーションを追加します。
|
||||
|
||||
**FastAPI** はそれをすべてOpenAPIスキーマに追加して、対話型のドキュメントシステムに表示されるようにします。
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# サブ依存関係 { #sub-dependencies }
|
||||
# サブ依存関係
|
||||
|
||||
**サブ依存関係** を持つ依存関係を作成することができます。
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
|
||||
**FastAPI** はそれらを解決してくれます。
|
||||
|
||||
## 最初の依存関係「依存可能なもの」 { #first-dependency-dependable }
|
||||
### 最初の依存関係「依存可能なもの」
|
||||
|
||||
以下のような最初の依存関係(「依存可能なもの」)を作成することができます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *}
|
||||
{* ../../docs_src/dependencies/tutorial005.py hl[8,9] *}
|
||||
|
||||
これはオプショナルのクエリパラメータ`q`を`str`として宣言し、それを返すだけです。
|
||||
|
||||
これは非常にシンプルです(あまり便利ではありません)が、サブ依存関係がどのように機能するかに焦点を当てるのに役立ちます。
|
||||
|
||||
## 第二の依存関係 「依存可能なもの」と「依存」 { #second-dependency-dependable-and-dependant }
|
||||
### 第二の依存関係 「依存可能なもの」と「依存」
|
||||
|
||||
そして、別の依存関数(「依存可能なもの」)を作成して、同時にそれ自身の依存関係を宣言することができます(つまりそれ自身も「依存」です):
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *}
|
||||
{* ../../docs_src/dependencies/tutorial005.py hl[13] *}
|
||||
|
||||
宣言されたパラメータに注目してみましょう:
|
||||
|
||||
@@ -29,15 +29,15 @@
|
||||
* また、オプショナルの`last_query`クッキーを`str`として宣言します。
|
||||
* ユーザーがクエリ`q`を提供しなかった場合、クッキーに保存していた最後に使用したクエリを使用します。
|
||||
|
||||
## 依存関係の使用 { #use-the-dependency }
|
||||
### 依存関係の使用
|
||||
|
||||
以下のように依存関係を使用することができます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}
|
||||
{* ../../docs_src/dependencies/tutorial005.py hl[21] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
*path operation 関数*の中で宣言している依存関係は`query_or_cookie_extractor`の1つだけであることに注意してください。
|
||||
*path operation関数*の中で宣言している依存関係は`query_or_cookie_extractor`の1つだけであることに注意してください。
|
||||
|
||||
しかし、**FastAPI** は`query_extractor`を最初に解決し、その結果を`query_or_cookie_extractor`を呼び出す時に渡す必要があることを知っています。
|
||||
|
||||
@@ -54,43 +54,24 @@ read_query["/items/"]
|
||||
query_extractor --> query_or_cookie_extractor --> read_query
|
||||
```
|
||||
|
||||
## 同じ依存関係の複数回の使用 { #using-the-same-dependency-multiple-times }
|
||||
## 同じ依存関係の複数回の使用
|
||||
|
||||
依存関係の1つが同じ*path operation*に対して複数回宣言されている場合、例えば、複数の依存関係が共通のサブ依存関係を持っている場合、**FastAPI** はリクエストごとに1回だけそのサブ依存関係を呼び出します。
|
||||
依存関係の1つが同じ*path operation*に対して複数回宣言されている場合、例えば、複数の依存関係が共通のサブ依存関係を持っている場合、**FastAPI** はリクエストごとに1回だけそのサブ依存関係を呼び出します。
|
||||
|
||||
そして、返された値を<abbr title="A utility/system to store computed/generated values, to reuse them instead of computing them again. – 計算/生成された値を保存し、再計算する代わりに再利用するためのユーティリティ/システム。">「キャッシュ」</abbr>に保存し、同じリクエストに対して依存関係を何度も呼び出す代わりに、その特定のリクエストでそれを必要とする全ての「依存」に渡すことになります。
|
||||
そして、返された値を<abbr title="計算された値・生成された値を保存するユーティリティまたはシステム、再計算する代わりに再利用するためのもの">「キャッシュ」</abbr>に保存し、同じリクエストに対して依存関係を何度も呼び出す代わりに、特定のリクエストでそれを必要とする全ての「依存関係」に渡すことになります。
|
||||
|
||||
高度なシナリオでは、「キャッシュされた」値を使うのではなく、同じリクエストの各ステップ(おそらく複数回)で依存関係を呼び出す必要があることがわかっている場合、`Depends`を使用する際に、`use_cache=False`というパラメータを設定することができます:
|
||||
|
||||
//// tab | Python 3.9+
|
||||
|
||||
```Python hl_lines="1"
|
||||
async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):
|
||||
return {"fresh_value": fresh_value}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+ 非Annotated
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
可能であれば`Annotated`版を使うことを推奨します。
|
||||
|
||||
///
|
||||
高度なシナリオでは、「キャッシュされた」値を使うのではなく、同じリクエストの各ステップ(おそらく複数回)で依存関係を呼び出す必要があることがわかっている場合、`Depens`を使用する際に、`use_cache=False`というパラメータを設定することができます。
|
||||
|
||||
```Python hl_lines="1"
|
||||
async def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):
|
||||
return {"fresh_value": fresh_value}
|
||||
```
|
||||
|
||||
////
|
||||
## まとめ
|
||||
|
||||
## まとめ { #recap }
|
||||
ここで使われている派手な言葉は別にして、**依存性注入** システムは非常にシンプルです。
|
||||
|
||||
ここで使われている派手な言葉は別にして、**Dependency Injection** システムは非常にシンプルです。
|
||||
|
||||
*path operation 関数*と同じように見えるただの関数です。
|
||||
*path operation関数*と同じように見えるただの関数です。
|
||||
|
||||
しかし、それでも非常に強力で、任意の深くネストされた依存関係「グラフ」(ツリー)を宣言することができます。
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# JSON互換エンコーダ { #json-compatible-encoder }
|
||||
# JSON互換エンコーダ
|
||||
|
||||
データ型(Pydanticモデルのような)をJSONと互換性のあるもの(`dict`や`list`など)に変換する必要があるケースがあります。
|
||||
データ型(Pydanticモデルのような)をJSONと互換性のあるもの(`dict`や`list`など)に変更する必要がある場合があります。
|
||||
|
||||
例えば、データベースに保存する必要がある場合です。
|
||||
|
||||
そのために、**FastAPI** は`jsonable_encoder()`関数を提供しています。
|
||||
|
||||
## `jsonable_encoder`の使用 { #using-the-jsonable-encoder }
|
||||
## `jsonable_encoder`の使用
|
||||
|
||||
JSON互換のデータのみを受信するデータベース`fake_db`があるとしましょう。
|
||||
|
||||
例えば、`datetime`オブジェクトはJSONと互換性がないので、受け取られません。
|
||||
例えば、`datetime`オブジェクトはJSONと互換性がないので、このデーターベースには受け取られません。
|
||||
|
||||
そのため、`datetime`オブジェクトは<a href="https://en.wikipedia.org/wiki/ISO_8601" class="external-link" target="_blank">ISO形式</a>のデータを含む`str`に変換されなければなりません。
|
||||
|
||||
@@ -20,7 +20,7 @@ JSON互換のデータのみを受信するデータベース`fake_db`がある
|
||||
|
||||
Pydanticモデルのようなオブジェクトを受け取り、JSON互換版を返します:
|
||||
|
||||
{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}
|
||||
{* ../../docs_src/encoder/tutorial001.py hl[5,22] *}
|
||||
|
||||
この例では、Pydanticモデルを`dict`に、`datetime`を`str`に変換します。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 追加データ型 { #extra-data-types }
|
||||
# 追加データ型
|
||||
|
||||
今まで、以下のような一般的なデータ型を使用してきました:
|
||||
今までは、以下のような一般的なデータ型を使用してきました:
|
||||
|
||||
* `int`
|
||||
* `float`
|
||||
@@ -11,13 +11,13 @@
|
||||
|
||||
そして、今まで見てきたのと同じ機能を持つことになります:
|
||||
|
||||
* 素晴らしいエディタのサポート。
|
||||
* 受信したリクエストからのデータ変換。
|
||||
* レスポンスデータのデータ変換。
|
||||
* データの検証。
|
||||
* 自動注釈と文書化。
|
||||
* 素晴らしいエディタのサポート
|
||||
* 受信したリクエストからのデータ変換
|
||||
* レスポンスデータのデータ変換
|
||||
* データの検証
|
||||
* 自動注釈と文書化
|
||||
|
||||
## 他のデータ型 { #other-data-types }
|
||||
## 他のデータ型
|
||||
|
||||
ここでは、使用できる追加のデータ型のいくつかを紹介します:
|
||||
|
||||
@@ -26,17 +26,17 @@
|
||||
* リクエストとレスポンスでは`str`として表現されます。
|
||||
* `datetime.datetime`:
|
||||
* Pythonの`datetime.datetime`です。
|
||||
* リクエストとレスポンスはISO 8601形式の`str`で表現されます(例: `2008-09-15T15:53:00+05:00`)。
|
||||
* リクエストとレスポンスはISO 8601形式の`str`で表現されます: `2008-09-15T15:53:00+05:00`
|
||||
* `datetime.date`:
|
||||
* Python `datetime.date`。
|
||||
* リクエストとレスポンスはISO 8601形式の`str`で表現されます(例: `2008-09-15`)。
|
||||
* Pythonの`datetime.date`です。
|
||||
* リクエストとレスポンスはISO 8601形式の`str`で表現されます: `2008-09-15`
|
||||
* `datetime.time`:
|
||||
* Pythonの`datetime.time`。
|
||||
* リクエストとレスポンスはISO 8601形式の`str`で表現されます(例: `14:23:55.003`)。
|
||||
* Pythonの`datetime.time`.
|
||||
* リクエストとレスポンスはISO 8601形式の`str`で表現されます: `14:23:55.003`
|
||||
* `datetime.timedelta`:
|
||||
* Pythonの`datetime.timedelta`です。
|
||||
* リクエストとレスポンスでは合計秒数の`float`で表現されます。
|
||||
* Pydanticでは「ISO 8601 time diff encoding」として表現することも可能です。<a href="https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers" class="external-link" target="_blank">詳細はドキュメントを参照してください</a>。
|
||||
* Pydanticでは「ISO 8601 time diff encoding」として表現することも可能です。<a href="https://docs.pydantic.dev/latest/concepts/serialization/" class="external-link" target="_blank">詳細はドキュメントを参照してください</a>。
|
||||
* `frozenset`:
|
||||
* リクエストとレスポンスでは`set`と同じように扱われます:
|
||||
* リクエストでは、リストが読み込まれ、重複を排除して`set`に変換されます。
|
||||
@@ -45,18 +45,18 @@
|
||||
* `bytes`:
|
||||
* Pythonの標準的な`bytes`です。
|
||||
* リクエストとレスポンスでは`str`として扱われます。
|
||||
* 生成されたスキーマは`str`で`binary`の「フォーマット」を持つことを指定します。
|
||||
* 生成されたスキーマは`str`で`binary`の「フォーマット」持つことを指定します。
|
||||
* `Decimal`:
|
||||
* Pythonの標準的な`Decimal`です。
|
||||
* リクエストとレスポンスでは`float`と同じように扱われます。
|
||||
* Pydanticの全ての有効な型はこちらで確認できます: <a href="https://docs.pydantic.dev/latest/usage/types/types/" class="external-link" target="_blank">Pydantic data types</a>。
|
||||
* リクエストやレスポンスでは`float`と同じように扱います。
|
||||
|
||||
## 例 { #example }
|
||||
* Pydanticの全ての有効な型はこちらで確認できます: <a href="https://docs.pydantic.dev/latest/concepts/types/" class="external-link" target="_blank">Pydantic data types</a>。
|
||||
## 例
|
||||
|
||||
ここでは、上記の型のいくつかを使用したパラメータを持つ*path operation*の例を示します。
|
||||
|
||||
{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}
|
||||
{* ../../docs_src/extra_data_types/tutorial001.py hl[1,2,12:16] *}
|
||||
|
||||
関数内のパラメータは自然なデータ型を持っていることに注意してください。そして、例えば、以下のように通常の日付操作を行うことができます:
|
||||
関数内のパラメータは自然なデータ型を持っていることに注意してください。そして、以下のように通常の日付操作を行うことができます:
|
||||
|
||||
{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *}
|
||||
{* ../../docs_src/extra_data_types/tutorial001.py hl[18,19] *}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Extra Models { #extra-models }
|
||||
# モデル - より詳しく
|
||||
|
||||
先ほどの例に続き、複数の関連モデルを持つことは一般的です。
|
||||
先ほどの例に続き、複数の関連モデルを持つことが一般的です。
|
||||
|
||||
これはユーザーモデルの場合は特にそうです。なぜなら:
|
||||
|
||||
@@ -8,27 +8,27 @@
|
||||
* **出力モデル**はパスワードをもつべきではありません。
|
||||
* **データベースモデル**はおそらくハッシュ化されたパスワードが必要になるでしょう。
|
||||
|
||||
/// danger
|
||||
/// danger | 危険
|
||||
|
||||
ユーザーの平文のパスワードは絶対に保存しないでください。常に検証できる「安全なハッシュ」を保存してください。
|
||||
ユーザーの平文のパスワードは絶対に保存しないでください。常に認証に利用可能な「安全なハッシュ」を保存してください。
|
||||
|
||||
知らない方は、[セキュリティの章](security/simple-oauth2.md#password-hashing){.internal-link target=_blank}で「パスワードハッシュ」とは何かを学ぶことができます。
|
||||
|
||||
///
|
||||
|
||||
## Multiple models { #multiple-models }
|
||||
## 複数のモデル
|
||||
|
||||
ここでは、パスワードフィールドをもつモデルがどのように見えるのか、また、どこで使われるのか、大まかなイメージを紹介します:
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}
|
||||
{* ../../docs_src/extra_models/tutorial001.py hl[9,11,16,22,24,29:30,33:35,40:41] *}
|
||||
|
||||
### About `**user_in.model_dump()` { #about-user-in-model-dump }
|
||||
### `**user_in.dict()`について
|
||||
|
||||
#### Pydanticの`.model_dump()` { #pydantics-model-dump }
|
||||
#### Pydanticの`.dict()`
|
||||
|
||||
`user_in`は`UserIn`クラスのPydanticモデルです。
|
||||
|
||||
Pydanticモデルには、モデルのデータを含む`dict`を返す`.model_dump()`メソッドがあります。
|
||||
Pydanticモデルには、モデルのデータを含む`dict`を返す`.dict()`メソッドがあります。
|
||||
|
||||
そこで、以下のようなPydanticオブジェクト`user_in`を作成すると:
|
||||
|
||||
@@ -39,7 +39,7 @@ user_in = UserIn(username="john", password="secret", email="john.doe@example.com
|
||||
そして呼び出すと:
|
||||
|
||||
```Python
|
||||
user_dict = user_in.model_dump()
|
||||
user_dict = user_in.dict()
|
||||
```
|
||||
|
||||
これで変数`user_dict`のデータを持つ`dict`ができました。(これはPydanticモデルのオブジェクトの代わりに`dict`です)。
|
||||
@@ -61,7 +61,7 @@ print(user_dict)
|
||||
}
|
||||
```
|
||||
|
||||
#### `dict`の展開 { #unpacking-a-dict }
|
||||
#### `dict`の展開
|
||||
|
||||
`user_dict`のような`dict`を受け取り、それを`**user_dict`を持つ関数(またはクラス)に渡すと、Pythonはそれを「展開」します。これは`user_dict`のキーと値を直接キー・バリューの引数として渡します。
|
||||
|
||||
@@ -93,31 +93,31 @@ UserInDB(
|
||||
)
|
||||
```
|
||||
|
||||
#### 別のモデルの内容からつくるPydanticモデル { #a-pydantic-model-from-the-contents-of-another }
|
||||
#### 別のモデルからつくるPydanticモデル
|
||||
|
||||
上述の例では`user_in.model_dump()`から`user_dict`をこのコードのように取得していますが:
|
||||
上述の例では`user_in.dict()`から`user_dict`をこのコードのように取得していますが:
|
||||
|
||||
```Python
|
||||
user_dict = user_in.model_dump()
|
||||
user_dict = user_in.dict()
|
||||
UserInDB(**user_dict)
|
||||
```
|
||||
|
||||
これは以下と同等です:
|
||||
|
||||
```Python
|
||||
UserInDB(**user_in.model_dump())
|
||||
UserInDB(**user_in.dict())
|
||||
```
|
||||
|
||||
...なぜなら`user_in.model_dump()`は`dict`であり、`**`を付与して`UserInDB`を渡してPythonに「展開」させているからです。
|
||||
...なぜなら`user_in.dict()`は`dict`であり、`**`を付与して`UserInDB`を渡してPythonに「展開」させているからです。
|
||||
|
||||
そこで、別のPydanticモデルのデータからPydanticモデルを取得します。
|
||||
|
||||
#### `dict`の展開と追加キーワード { #unpacking-a-dict-and-extra-keywords }
|
||||
#### `dict`の展開と追加引数
|
||||
|
||||
そして、追加のキーワード引数`hashed_password=hashed_password`を以下のように追加すると:
|
||||
|
||||
```Python
|
||||
UserInDB(**user_in.model_dump(), hashed_password=hashed_password)
|
||||
UserInDB(**user_in.dict(), hashed_password=hashed_password)
|
||||
```
|
||||
|
||||
...以下のようになります:
|
||||
@@ -132,13 +132,13 @@ UserInDB(
|
||||
)
|
||||
```
|
||||
|
||||
/// warning
|
||||
/// warning | 注意
|
||||
|
||||
追加のサポート関数`fake_password_hasher`と`fake_save_user`は、データの可能な流れをデモするだけであり、もちろん本当のセキュリティを提供しているわけではありません。
|
||||
サポートしている追加機能は、データの可能な流れをデモするだけであり、もちろん本当のセキュリティを提供しているわけではありません。
|
||||
|
||||
///
|
||||
|
||||
## Reduce duplication { #reduce-duplication }
|
||||
## 重複の削減
|
||||
|
||||
コードの重複を減らすことは、**FastAPI**の中核的なアイデアの1つです。
|
||||
|
||||
@@ -152,60 +152,40 @@ UserInDB(
|
||||
|
||||
データの変換、検証、文書化などはすべて通常通りに動作します。
|
||||
|
||||
このようにして、モデル間の違いだけを宣言することができます(平文の`password`、`hashed_password`、パスワードなし):
|
||||
このようにして、モデル間の違いだけを宣言することができます:
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}
|
||||
{* ../../docs_src/extra_models/tutorial002.py hl[9,15,16,19,20,23,24] *}
|
||||
|
||||
## `Union` or `anyOf` { #union-or-anyof }
|
||||
## `Union`または`anyOf`
|
||||
|
||||
レスポンスを2つ以上の型の`Union`として宣言できます。つまり、そのレスポンスはそれらのいずれかになります。
|
||||
レスポンスを2つの型の`Union`として宣言することができます。
|
||||
|
||||
OpenAPIでは`anyOf`で定義されます。
|
||||
|
||||
そのためには、標準的なPythonの型ヒント<a href="https://docs.python.org/3/library/typing.html#typing.Union" class="external-link" target="_blank">`typing.Union`</a>を使用します:
|
||||
|
||||
/// note | 備考
|
||||
{* ../../docs_src/extra_models/tutorial003.py hl[1,14,15,18,19,20,33] *}
|
||||
|
||||
<a href="https://docs.pydantic.dev/latest/concepts/types/#unions" class="external-link" target="_blank">`Union`</a>を定義する場合は、最も具体的な型を先に、その後により具体性の低い型を含めてください。以下の例では、より具体的な`PlaneItem`が`Union[PlaneItem, CarItem]`内で`CarItem`より前に来ています。
|
||||
## モデルのリスト
|
||||
|
||||
///
|
||||
同じように、オブジェクトのリストのレスポンスを宣言することができます。
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}
|
||||
そのためには、標準のPythonの`typing.List`を使用する:
|
||||
|
||||
### Python 3.10の`Union` { #union-in-python-3-10 }
|
||||
{* ../../docs_src/extra_models/tutorial004.py hl[1,20] *}
|
||||
|
||||
この例では、引数`response_model`の値として`Union[PlaneItem, CarItem]`を渡しています。
|
||||
|
||||
**型アノテーション**に書くのではなく、**引数の値**として渡しているため、Python 3.10でも`Union`を使う必要があります。
|
||||
|
||||
型アノテーションであれば、次のように縦棒を使用できました:
|
||||
|
||||
```Python
|
||||
some_variable: PlaneItem | CarItem
|
||||
```
|
||||
|
||||
しかし、これを代入で`response_model=PlaneItem | CarItem`のように書くと、Pythonはそれを型アノテーションとして解釈するのではなく、`PlaneItem`と`CarItem`の間で**無効な操作**を行おうとしてしまうため、エラーになります。
|
||||
|
||||
## List of models { #list-of-models }
|
||||
|
||||
同じように、オブジェクトのリストのレスポンスを宣言できます。
|
||||
|
||||
そのためには、標準のPythonの`typing.List`(またはPython 3.9以降では単に`list`)を使用します:
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *}
|
||||
|
||||
## Response with arbitrary `dict` { #response-with-arbitrary-dict }
|
||||
## 任意の`dict`を持つレスポンス
|
||||
|
||||
また、Pydanticモデルを使用せずに、キーと値の型だけを定義した任意の`dict`を使ってレスポンスを宣言することもできます。
|
||||
|
||||
これは、有効なフィールド・属性名(Pydanticモデルに必要なもの)を事前に知らない場合に便利です。
|
||||
|
||||
この場合、`typing.Dict`(またはPython 3.9以降では単に`dict`)を使用できます:
|
||||
この場合、`typing.Dict`を使用することができます:
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *}
|
||||
{* ../../docs_src/extra_models/tutorial005.py hl[1,8] *}
|
||||
|
||||
## Recap { #recap }
|
||||
## まとめ
|
||||
|
||||
複数のPydanticモデルを使用し、ケースごとに自由に継承します。
|
||||
|
||||
エンティティが異なる「状態」を持たなければならない場合は、エンティティごとに単一のデータモデルを持つ必要はありません。`password`、`password_hash`、パスワードなしを含む状態を持つユーザー「エンティティ」の場合と同様です。
|
||||
エンティティが異なる「状態」を持たなければならない場合は、エンティティごとに単一のデータモデルを持つ必要はありません。`password` や `password_hash` やパスワードなしなどのいくつかの「状態」をもつユーザー「エンティティ」の場合の様にすれば良いです。
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# 最初のステップ { #first-steps }
|
||||
# 最初のステップ
|
||||
|
||||
最もシンプルなFastAPIファイルは以下のようになります:
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py *}
|
||||
{* ../../docs_src/first_steps/tutorial001.py *}
|
||||
|
||||
これを`main.py`にコピーします。
|
||||
|
||||
@@ -11,43 +11,27 @@
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting development server 🚀
|
||||
|
||||
Searching for package file structure from directories
|
||||
with <font color="#3465A4">__init__.py</font> files
|
||||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with
|
||||
the following code:
|
||||
|
||||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000/docs</u></font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> tip </font></span> Running in development mode, for production use:
|
||||
<b>fastapi run</b>
|
||||
|
||||
Logs:
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Will watch for changes in these directories:
|
||||
<b>[</b><font color="#4E9A06">'/home/user/code/awesomeapp'</font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C
|
||||
to quit<b>)</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started reloader process <b>[</b><font color="#34E2E2"><b>383138</b></font><b>]</b> using WatchFiles
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>383153</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
<span style="color: green;">INFO</span>: Started reloader process [28720]
|
||||
<span style="color: green;">INFO</span>: Started server process [28722]
|
||||
<span style="color: green;">INFO</span>: Waiting for application startup.
|
||||
<span style="color: green;">INFO</span>: Application startup complete.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
/// note | 備考
|
||||
|
||||
`uvicorn main:app`は以下を示します:
|
||||
|
||||
* `main`: `main.py`ファイル (Python "module")。
|
||||
* `app`: `main.py`内部で作られるobject(`app = FastAPI()`のように記述される)。
|
||||
* `--reload`: コードの変更時にサーバーを再起動させる。開発用。
|
||||
|
||||
///
|
||||
|
||||
出力には次のような行があります:
|
||||
|
||||
```hl_lines="4"
|
||||
@@ -56,7 +40,7 @@ INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
|
||||
この行はローカルマシンでアプリが提供されているURLを示しています。
|
||||
|
||||
### チェック { #check-it }
|
||||
### チェック
|
||||
|
||||
ブラウザで<a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>を開きます。
|
||||
|
||||
@@ -66,7 +50,7 @@ INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
{"message": "Hello World"}
|
||||
```
|
||||
|
||||
### 対話的APIドキュメント { #interactive-api-docs }
|
||||
### 対話的APIドキュメント
|
||||
|
||||
次に、<a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>にアクセスします。
|
||||
|
||||
@@ -74,7 +58,7 @@ INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
|
||||

|
||||
|
||||
### 代替APIドキュメント { #alternative-api-docs }
|
||||
### 他のAPIドキュメント
|
||||
|
||||
次に、<a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>にアクセスします。
|
||||
|
||||
@@ -82,31 +66,31 @@ INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
|
||||

|
||||
|
||||
### OpenAPI { #openapi }
|
||||
### OpenAPI
|
||||
|
||||
**FastAPI**は、APIを定義するための**OpenAPI**標準規格を使用して、すべてのAPIの「スキーマ」を生成します。
|
||||
|
||||
#### 「スキーマ」 { #schema }
|
||||
#### 「スキーマ」
|
||||
|
||||
「スキーマ」は定義または説明です。実装コードではなく、単なる抽象的な説明です。
|
||||
|
||||
#### API「スキーマ」 { #api-schema }
|
||||
#### API「スキーマ」
|
||||
|
||||
ここでは、<a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a>はAPIのスキーマ定義の方法を規定する仕様です。
|
||||
|
||||
このスキーマ定義はAPIパス、受け取り可能なパラメータなどが含まれます。
|
||||
|
||||
#### データ「スキーマ」 { #data-schema }
|
||||
#### データ「スキーマ」
|
||||
|
||||
「スキーマ」という用語は、JSONコンテンツなどの一部のデータの形状を指す場合もあります。
|
||||
|
||||
そのような場合、スキーマはJSON属性とそれらが持つデータ型などを意味します。
|
||||
|
||||
#### OpenAPIおよびJSONスキーマ { #openapi-and-json-schema }
|
||||
#### OpenAPIおよびJSONスキーマ
|
||||
|
||||
OpenAPIはAPIのためのAPIスキーマを定義します。そして、そのスキーマは**JSONデータスキーマ**の標準規格に準拠したJSONスキーマを利用するAPIによって送受されるデータの定義(または「スキーマ」)を含んでいます。
|
||||
|
||||
#### `openapi.json`を確認 { #check-the-openapi-json }
|
||||
#### `openapi.json`を確認
|
||||
|
||||
素のOpenAPIスキーマがどのようなものか興味がある場合、FastAPIはすべてのAPIの説明を含むJSON(スキーマ)を自動的に生成します。
|
||||
|
||||
@@ -116,7 +100,7 @@ OpenAPIはAPIのためのAPIスキーマを定義します。そして、その
|
||||
|
||||
```JSON
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"openapi": "3.0.2",
|
||||
"info": {
|
||||
"title": "FastAPI",
|
||||
"version": "0.1.0"
|
||||
@@ -135,7 +119,7 @@ OpenAPIはAPIのためのAPIスキーマを定義します。そして、その
|
||||
...
|
||||
```
|
||||
|
||||
#### OpenAPIの目的 { #what-is-openapi-for }
|
||||
#### OpenAPIの目的
|
||||
|
||||
OpenAPIスキーマは、FastAPIに含まれている2つのインタラクティブなドキュメントシステムの動力源です。
|
||||
|
||||
@@ -143,47 +127,11 @@ OpenAPIスキーマは、FastAPIに含まれている2つのインタラクテ
|
||||
|
||||
また、APIと通信するクライアント用のコードを自動的に生成するために使用することもできます。たとえば、フロントエンド、モバイル、またはIoTアプリケーションです。
|
||||
|
||||
### アプリをデプロイ(任意) { #deploy-your-app-optional }
|
||||
## ステップ毎の要約
|
||||
|
||||
任意でFastAPIアプリを<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>にデプロイできます。まだなら、待機リストに登録してください。 🚀
|
||||
### Step 1: `FastAPI`をインポート
|
||||
|
||||
すでに**FastAPI Cloud**アカウントがある場合(待機リストから招待済みの場合😉)、1コマンドでアプリケーションをデプロイできます。
|
||||
|
||||
デプロイする前に、ログインしていることを確認してください:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi login
|
||||
|
||||
You are logged in to FastAPI Cloud 🚀
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
その後、アプリをデプロイします:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi deploy
|
||||
|
||||
Deploying to FastAPI Cloud...
|
||||
|
||||
✅ Deployment successful!
|
||||
|
||||
🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
以上です!これで、そのURLでアプリにアクセスできます。 ✨
|
||||
|
||||
## ステップ毎の要約 { #recap-step-by-step }
|
||||
|
||||
### Step 1: `FastAPI`をインポート { #step-1-import-fastapi }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[1] *}
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[1] *}
|
||||
|
||||
`FastAPI`は、APIのすべての機能を提供するPythonクラスです。
|
||||
|
||||
@@ -195,16 +143,44 @@ Deploying to FastAPI Cloud...
|
||||
|
||||
///
|
||||
|
||||
### Step 2: `FastAPI`の「インスタンス」を生成 { #step-2-create-a-fastapi-instance }
|
||||
### Step 2: `FastAPI`の「インスタンス」を生成
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[3] *}
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[3] *}
|
||||
ここで、`app`変数が`FastAPI`クラスの「インスタンス」になります。
|
||||
|
||||
これが、すべてのAPIを作成するための主要なポイントになります。
|
||||
|
||||
### Step 3: *path operation*を作成 { #step-3-create-a-path-operation }
|
||||
この`app`はコマンドで`uvicorn`が参照するものと同じです:
|
||||
|
||||
#### パス { #path }
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
以下のようなアプリを作成したとき:
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial002.py hl[3] *}
|
||||
|
||||
そして、それを`main.py`ファイルに置き、次のように`uvicorn`を呼び出します:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:my_awesome_api --reload
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### Step 3: *path operation*を作成
|
||||
|
||||
#### パス
|
||||
|
||||
ここでの「パス」とは、最初の`/`から始まるURLの最後の部分を指します。
|
||||
|
||||
@@ -228,7 +204,7 @@ https://example.com/items/foo
|
||||
|
||||
APIを構築する際、「パス」は「関心事」と「リソース」を分離するための主要な方法です。
|
||||
|
||||
#### Operation { #operation }
|
||||
#### Operation
|
||||
|
||||
ここでの「オペレーション」とは、HTTPの「メソッド」の1つを指します。
|
||||
|
||||
@@ -263,16 +239,15 @@ APIを構築するときは、通常、これらの特定のHTTPメソッドを
|
||||
|
||||
「**オペレーションズ**」とも呼ぶことにします。
|
||||
|
||||
#### *path operation デコレータ*を定義 { #define-a-path-operation-decorator }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[6] *}
|
||||
#### *パスオペレーションデコレータ*を定義
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[6] *}
|
||||
`@app.get("/")`は直下の関数が下記のリクエストの処理を担当することを**FastAPI**に伝えます:
|
||||
|
||||
* パス `/`
|
||||
* <abbr title="an HTTP GET method"><code>get</code> オペレーション</abbr>
|
||||
|
||||
/// info | `@decorator` Info
|
||||
/// info | `@decorator` について
|
||||
|
||||
Pythonにおける`@something`シンタックスはデコレータと呼ばれます。
|
||||
|
||||
@@ -280,9 +255,9 @@ Pythonにおける`@something`シンタックスはデコレータと呼ばれ
|
||||
|
||||
「デコレータ」は直下の関数を受け取り、それを使って何かを行います。
|
||||
|
||||
私たちの場合、このデコレーターは直下の関数が**オペレーション** `get`を使用した**パス** `/`に対応することを**FastAPI** に通知します。
|
||||
私たちの場合、このデコレーターは直下の関数が**オペレーション** `get`を使用した**パス**` / `に対応することを**FastAPI** に通知します。
|
||||
|
||||
これが「*path operation デコレータ*」です。
|
||||
これが「*パスオペレーションデコレータ*」です。
|
||||
|
||||
///
|
||||
|
||||
@@ -311,15 +286,15 @@ Pythonにおける`@something`シンタックスはデコレータと呼ばれ
|
||||
|
||||
///
|
||||
|
||||
### Step 4: **path operation 関数**を定義 { #step-4-define-the-path-operation-function }
|
||||
### Step 4: **パスオペレーション**を定義
|
||||
|
||||
以下は「**path operation 関数**」です:
|
||||
以下は「**パスオペレーション関数**」です:
|
||||
|
||||
* **パス**: は`/`です。
|
||||
* **オペレーション**: は`get`です。
|
||||
* **関数**: 「デコレータ」の直下にある関数 (`@app.get("/")`の直下) です。
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[7] *}
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[7] *}
|
||||
|
||||
これは、Pythonの関数です。
|
||||
|
||||
@@ -331,49 +306,28 @@ Pythonにおける`@something`シンタックスはデコレータと呼ばれ
|
||||
|
||||
`async def`の代わりに通常の関数として定義することもできます:
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *}
|
||||
{* ../../docs_src/first_steps/tutorial003.py hl[7] *}
|
||||
|
||||
/// note | 備考
|
||||
|
||||
違いが分からない場合は、[Async: *"急いでいますか?"*](../async.md#in-a-hurry){.internal-link target=_blank}を確認してください。
|
||||
違いが分からない場合は、[Async: *"急いでいますか?"*](../async.md#_1){.internal-link target=_blank}を確認してください。
|
||||
|
||||
///
|
||||
|
||||
### Step 5: コンテンツの返信 { #step-5-return-the-content }
|
||||
### Step 5: コンテンツの返信
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *}
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[8] *}
|
||||
|
||||
`dict`、`list`、`str`、`int`などの単一の値を返すことができます。
|
||||
`dict`、`list`、`str`、`int`などを返すことができます。
|
||||
|
||||
Pydanticモデルを返すこともできます(後で詳しく説明します)。
|
||||
|
||||
JSONに自動的に変換されるオブジェクトやモデルは他にもたくさんあります(ORMなど)。 お気に入りのものを使ってみてください。すでにサポートされている可能性が高いです。
|
||||
|
||||
### Step 6: デプロイする { #step-6-deploy-it }
|
||||
## まとめ
|
||||
|
||||
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>**に1コマンドでアプリをデプロイします: `fastapi deploy`. 🎉
|
||||
|
||||
#### FastAPI Cloudについて { #about-fastapi-cloud }
|
||||
|
||||
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>**は、**FastAPI**の作者とそのチームによって開発されています。
|
||||
|
||||
最小限の労力でAPIの**構築**、**デプロイ**、**アクセス**を行うプロセスを合理化します。
|
||||
|
||||
FastAPIでアプリを構築するのと同じ**開発体験**を、クラウドへの**デプロイ**にもたらします。 🎉
|
||||
|
||||
FastAPI Cloudは、*FastAPI and friends*のオープンソースプロジェクトに対する主要スポンサーであり、資金提供元です。 ✨
|
||||
|
||||
#### 他のクラウドプロバイダにデプロイする { #deploy-to-other-cloud-providers }
|
||||
|
||||
FastAPIはオープンソースで、標準に基づいています。選択した任意のクラウドプロバイダにFastAPIアプリをデプロイできます。
|
||||
|
||||
クラウドプロバイダのガイドに従って、FastAPIアプリをデプロイしてください。 🤓
|
||||
|
||||
## まとめ { #recap }
|
||||
|
||||
* `FastAPI`をインポートします。
|
||||
* `app`インスタンスを生成します。
|
||||
* `@app.get("/")`のようなデコレータを使用して、**path operation デコレータ**を記述します。
|
||||
* **path operation 関数**を定義します。例: `def root(): ...`。
|
||||
* `fastapi dev`コマンドで開発サーバーを起動します。
|
||||
* 任意で`fastapi deploy`を使ってアプリをデプロイします。
|
||||
* `FastAPI`をインポート
|
||||
* `app`インスタンスを生成
|
||||
* **パスオペレーションデコレータ**を記述 (`@app.get("/")`)
|
||||
* **パスオペレーション関数**を定義 (上記の`def root(): ...`のように)
|
||||
* 開発サーバーを起動 (`uvicorn main:app --reload`)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# エラーハンドリング { #handling-errors }
|
||||
# エラーハンドリング
|
||||
|
||||
APIを使用しているクライアントにエラーを通知する必要がある状況はたくさんあります。
|
||||
|
||||
@@ -19,15 +19,15 @@ APIを使用しているクライアントにエラーを通知する必要が
|
||||
|
||||
**"404 Not Found"** のエラー(およびジョーク)を覚えていますか?
|
||||
|
||||
## `HTTPException`の使用 { #use-httpexception }
|
||||
## `HTTPException`の使用
|
||||
|
||||
HTTPレスポンスをエラーでクライアントに返すには、`HTTPException`を使用します。
|
||||
|
||||
### `HTTPException`のインポート { #import-httpexception }
|
||||
### `HTTPException`のインポート
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial001_py39.py hl[1] *}
|
||||
{* ../../docs_src/handling_errors/tutorial001.py hl[1] *}
|
||||
|
||||
### コード内での`HTTPException`の発生 { #raise-an-httpexception-in-your-code }
|
||||
### コード内での`HTTPException`の発生
|
||||
|
||||
`HTTPException`は通常のPythonの例外であり、APIに関連するデータを追加したものです。
|
||||
|
||||
@@ -39,9 +39,9 @@ Pythonの例外なので、`return`ではなく、`raise`です。
|
||||
|
||||
この例では、クライアントが存在しないIDでアイテムを要求した場合、`404`のステータスコードを持つ例外を発生させます:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial001_py39.py hl[11] *}
|
||||
{* ../../docs_src/handling_errors/tutorial001.py hl[11] *}
|
||||
|
||||
### レスポンス結果 { #the-resulting-response }
|
||||
### レスポンス結果
|
||||
|
||||
クライアントが`http://example.com/items/foo`(`item_id` `"foo"`)をリクエストすると、HTTPステータスコードが200で、以下のJSONレスポンスが返されます:
|
||||
|
||||
@@ -69,7 +69,7 @@ Pythonの例外なので、`return`ではなく、`raise`です。
|
||||
|
||||
///
|
||||
|
||||
## カスタムヘッダーの追加 { #add-custom-headers }
|
||||
## カスタムヘッダーの追加
|
||||
|
||||
例えば、いくつかのタイプのセキュリティのために、HTTPエラーにカスタムヘッダを追加できると便利な状況がいくつかあります。
|
||||
|
||||
@@ -77,9 +77,9 @@ Pythonの例外なので、`return`ではなく、`raise`です。
|
||||
|
||||
しかし、高度なシナリオのために必要な場合には、カスタムヘッダーを追加することができます:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial002_py39.py hl[14] *}
|
||||
{* ../../docs_src/handling_errors/tutorial002.py hl[14] *}
|
||||
|
||||
## カスタム例外ハンドラのインストール { #install-custom-exception-handlers }
|
||||
## カスタム例外ハンドラのインストール
|
||||
|
||||
カスタム例外ハンドラは<a href="https://www.starlette.dev/exceptions/" class="external-link" target="_blank">Starletteと同じ例外ユーティリティ</a>を使用して追加することができます。
|
||||
|
||||
@@ -89,7 +89,7 @@ Pythonの例外なので、`return`ではなく、`raise`です。
|
||||
|
||||
カスタム例外ハンドラを`@app.exception_handler()`で追加することができます:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial003_py39.py hl[5:7,13:18,24] *}
|
||||
{* ../../docs_src/handling_errors/tutorial003.py hl[5,6,7,13,14,15,16,17,18,24] *}
|
||||
|
||||
ここで、`/unicorns/yolo`をリクエストすると、*path operation*は`UnicornException`を`raise`します。
|
||||
|
||||
@@ -109,7 +109,7 @@ Pythonの例外なので、`return`ではなく、`raise`です。
|
||||
|
||||
///
|
||||
|
||||
## デフォルトの例外ハンドラのオーバーライド { #override-the-default-exception-handlers }
|
||||
## デフォルトの例外ハンドラのオーバーライド
|
||||
|
||||
**FastAPI** にはいくつかのデフォルトの例外ハンドラがあります。
|
||||
|
||||
@@ -117,7 +117,7 @@ Pythonの例外なので、`return`ではなく、`raise`です。
|
||||
|
||||
これらの例外ハンドラを独自のものでオーバーライドすることができます。
|
||||
|
||||
### リクエスト検証の例外のオーバーライド { #override-request-validation-exceptions }
|
||||
### リクエスト検証の例外のオーバーライド
|
||||
|
||||
リクエストに無効なデータが含まれている場合、**FastAPI** は内部的に`RequestValidationError`を発生させます。
|
||||
|
||||
@@ -125,11 +125,11 @@ Pythonの例外なので、`return`ではなく、`raise`です。
|
||||
|
||||
これをオーバーライドするには`RequestValidationError`をインポートして`@app.exception_handler(RequestValidationError)`と一緒に使用して例外ハンドラをデコレートします。
|
||||
|
||||
この例外ハンドラは`Request`と例外を受け取ります。
|
||||
この例外ハンドラは`Requset`と例外を受け取ります。
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial004_py39.py hl[2,14:19] *}
|
||||
{* ../../docs_src/handling_errors/tutorial004.py hl[2,14,15,16] *}
|
||||
|
||||
これで、`/items/foo`にアクセスすると、以下のデフォルトのJSONエラーの代わりに:
|
||||
これで、`/items/foo`にアクセスすると、デフォルトのJSONエラーの代わりに以下が返されます:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -146,20 +146,39 @@ Pythonの例外なので、`return`ではなく、`raise`です。
|
||||
}
|
||||
```
|
||||
|
||||
以下のテキスト版を取得します:
|
||||
以下のようなテキスト版を取得します:
|
||||
|
||||
```
|
||||
Validation errors:
|
||||
Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer
|
||||
1 validation error
|
||||
path -> item_id
|
||||
value is not a valid integer (type=type_error.integer)
|
||||
```
|
||||
|
||||
### `HTTPException`エラーハンドラのオーバーライド { #override-the-httpexception-error-handler }
|
||||
#### `RequestValidationError`と`ValidationError`
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
これらは今のあなたにとって重要でない場合は省略しても良い技術的な詳細です。
|
||||
|
||||
///
|
||||
|
||||
`RequestValidationError`はPydanticの<a href="https://docs.pydantic.dev/latest/concepts/models/#error-handling" class="external-link" target="_blank">`ValidationError`</a>のサブクラスです。
|
||||
|
||||
**FastAPI** は`response_model`でPydanticモデルを使用していて、データにエラーがあった場合、ログにエラーが表示されるようにこれを使用しています。
|
||||
|
||||
しかし、クライアントやユーザーはそれを見ることはありません。その代わりに、クライアントはHTTPステータスコード`500`の「Internal Server Error」を受け取ります。
|
||||
|
||||
*レスポンス*やコードのどこか(クライアントの*リクエスト*ではなく)にPydanticの`ValidationError`がある場合、それは実際にはコードのバグなのでこのようにすべきです。
|
||||
|
||||
また、あなたがそれを修正している間は、セキュリティの脆弱性が露呈する場合があるため、クライアントやユーザーがエラーに関する内部情報にアクセスできないようにしてください。
|
||||
|
||||
### エラーハンドラ`HTTPException`のオーバーライド
|
||||
|
||||
同様に、`HTTPException`ハンドラをオーバーライドすることもできます。
|
||||
|
||||
例えば、これらのエラーに対しては、JSONではなくプレーンテキストを返すようにすることができます:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial004_py39.py hl[3:4,9:11,25] *}
|
||||
{* ../../docs_src/handling_errors/tutorial004.py hl[3,4,9,10,11,22] *}
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
@@ -169,21 +188,13 @@ Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to pa
|
||||
|
||||
///
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
`RequestValidationError`には、検証エラーが発生したファイル名と行番号の情報が含まれているため、必要であれば関連情報と一緒にログに表示できます。
|
||||
|
||||
しかし、そのまま文字列に変換して直接その情報を返すと、システムに関する情報が多少漏えいする可能性があります。そのため、ここではコードが各エラーを個別に抽出して表示します。
|
||||
|
||||
///
|
||||
|
||||
### `RequestValidationError`のボディの使用 { #use-the-requestvalidationerror-body }
|
||||
### `RequestValidationError`のボディの使用
|
||||
|
||||
`RequestValidationError`には無効なデータを含む`body`が含まれています。
|
||||
|
||||
アプリ開発中にボディのログを取ってデバッグしたり、ユーザーに返したりなどに使用することができます。
|
||||
アプリ開発中に本体のログを取ってデバッグしたり、ユーザーに返したりなどに使用することができます。
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial005_py39.py hl[14] *}
|
||||
{* ../../docs_src/handling_errors/tutorial005.py hl[14] *}
|
||||
|
||||
ここで、以下のような無効な項目を送信してみてください:
|
||||
|
||||
@@ -196,7 +207,7 @@ Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to pa
|
||||
|
||||
受信したボディを含むデータが無効であることを示すレスポンスが表示されます:
|
||||
|
||||
```JSON hl_lines="12-15"
|
||||
```JSON hl_lines="12 13 14 15"
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
@@ -215,30 +226,36 @@ Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to pa
|
||||
}
|
||||
```
|
||||
|
||||
#### FastAPIの`HTTPException`とStarletteの`HTTPException` { #fastapis-httpexception-vs-starlettes-httpexception }
|
||||
#### FastAPIの`HTTPException`とStarletteの`HTTPException`
|
||||
|
||||
**FastAPI**は独自の`HTTPException`を持っています。
|
||||
|
||||
また、 **FastAPI**の`HTTPException`エラークラスはStarletteの`HTTPException`エラークラスを継承しています。
|
||||
また、 **FastAPI**のエラークラス`HTTPException`はStarletteのエラークラス`HTTPException`を継承しています。
|
||||
|
||||
唯一の違いは、**FastAPI** の`HTTPException`は`detail`フィールドにJSONに変換可能な任意のデータを受け付けるのに対し、Starletteの`HTTPException`は文字列のみを受け付けることです。
|
||||
唯一の違いは、**FastAPI** の`HTTPException`はレスポンスに含まれるヘッダを追加できることです。
|
||||
|
||||
これはOAuth 2.0といくつかのセキュリティユーティリティのために内部的に必要とされ、使用されています。
|
||||
|
||||
そのため、コード内では通常通り **FastAPI** の`HTTPException`を発生させ続けることができます。
|
||||
|
||||
しかし、例外ハンドラを登録する際には、Starletteの`HTTPException`に対して登録しておく必要があります。
|
||||
しかし、例外ハンドラを登録する際には、Starletteの`HTTPException`を登録しておく必要があります。
|
||||
|
||||
これにより、Starletteの内部コードやStarletteの拡張機能やプラグインの一部がStarletteの`HTTPException`を発生させた場合、ハンドラがそれをキャッチして処理できるようになります。
|
||||
これにより、Starletteの内部コードやStarletteの拡張機能やプラグインの一部が`HTTPException`を発生させた場合、ハンドラがそれをキャッチして処理することができるようになります。
|
||||
|
||||
この例では、同じコード内で両方の`HTTPException`を使用できるようにするために、Starletteの例外を`StarletteHTTPException`にリネームしています:
|
||||
以下の例では、同じコード内で両方の`HTTPException`を使用できるようにするために、Starletteの例外の名前を`StarletteHTTPException`に変更しています:
|
||||
|
||||
```Python
|
||||
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
```
|
||||
|
||||
### **FastAPI** の例外ハンドラの再利用 { #reuse-fastapis-exception-handlers }
|
||||
### **FastAPI** の例外ハンドラの再利用
|
||||
|
||||
**FastAPI** から同じデフォルトの例外ハンドラと一緒に例外を使用したい場合は、`fastapi.exception_handlers`からデフォルトの例外ハンドラをインポートして再利用できます:
|
||||
また、何らかの方法で例外を使用することもできますが、**FastAPI** から同じデフォルトの例外ハンドラを使用することもできます。
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial006_py39.py hl[2:5,15,21] *}
|
||||
デフォルトの例外ハンドラを`fastapi.exception_handlers`からインポートして再利用することができます:
|
||||
|
||||
この例では、非常に表現力のあるメッセージでエラーを`print`しているだけですが、要点は理解できるはずです。例外を使用し、その後デフォルトの例外ハンドラを再利用できます。
|
||||
{* ../../docs_src/handling_errors/tutorial006.py hl[2,3,4,5,15,21] *}
|
||||
|
||||
この例では、非常に表現力のあるメッセージでエラーを`print`しています。
|
||||
|
||||
しかし、例外を使用して、デフォルトの例外ハンドラを再利用することができるということが理解できます。
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
# ヘッダーのパラメータ { #header-parameters }
|
||||
# ヘッダーのパラメータ
|
||||
|
||||
ヘッダーのパラメータは、`Query`や`Path`、`Cookie`のパラメータを定義するのと同じように定義できます。
|
||||
|
||||
## `Header`をインポート { #import-header }
|
||||
## `Header`をインポート
|
||||
|
||||
まず、`Header`をインポートします:
|
||||
|
||||
{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}
|
||||
{* ../../docs_src/header_params/tutorial001.py hl[3] *}
|
||||
|
||||
## `Header`のパラメータの宣言 { #declare-header-parameters }
|
||||
## `Header`のパラメータの宣言
|
||||
|
||||
次に、`Path`や`Query`、`Cookie`と同じ構造を用いてヘッダーのパラメータを宣言します。
|
||||
|
||||
デフォルト値に加えて、追加の検証パラメータや注釈パラメータをすべて定義できます:
|
||||
最初の値がデフォルト値で、追加の検証パラメータや注釈パラメータをすべて渡すことができます。
|
||||
|
||||
{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}
|
||||
{* ../../docs_src/header_params/tutorial001.py hl[9] *}
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
@@ -30,23 +30,23 @@
|
||||
|
||||
///
|
||||
|
||||
## 自動変換 { #automatic-conversion }
|
||||
## 自動変換
|
||||
|
||||
`Header`は`Path`や`Query`、`Cookie`が提供する機能に加え、少しだけ追加の機能を持っています。
|
||||
|
||||
ほとんどの標準ヘッダーは、「マイナス記号」(`-`)としても知られる「ハイフン」文字で区切られています。
|
||||
ほとんどの標準ヘッダーは、「マイナス記号」(`-`)としても知られる「ハイフン」で区切られています。
|
||||
|
||||
しかし、`user-agent`のような変数はPythonでは無効です。
|
||||
|
||||
そのため、デフォルトでは、`Header`はパラメータ名の文字をアンダースコア(`_`)からハイフン(`-`)に変換して、ヘッダーを抽出して文書化します。
|
||||
そのため、デフォルトでは、`Header`はパラメータの文字をアンダースコア(`_`)からハイフン(`-`)に変換して、ヘッダーを抽出して文書化します。
|
||||
|
||||
また、HTTPヘッダは大文字小文字を区別しないので、Pythonの標準スタイル(別名「スネークケース」)で宣言することができます。
|
||||
|
||||
そのため、`User_Agent`などのように最初の文字を大文字にする必要はなく、通常のPythonコードと同じように`user_agent`を使用することができます。
|
||||
|
||||
もしなんらかの理由でアンダースコアからハイフンへの自動変換を無効にする必要がある場合は、`Header`のパラメータ`convert_underscores`を`False`に設定してください:
|
||||
もしなんらかの理由でアンダースコアからハイフンへの自動変換を無効にする必要がある場合は、`Header`の`convert_underscores`に`False`を設定してください:
|
||||
|
||||
{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *}
|
||||
{* ../../docs_src/header_params/tutorial002.py hl[9] *}
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
@@ -54,26 +54,26 @@
|
||||
|
||||
///
|
||||
|
||||
## ヘッダーの重複 { #duplicate-headers }
|
||||
## ヘッダーの重複
|
||||
|
||||
受信したヘッダーが重複することがあります。つまり、同じヘッダーで複数の値を持つということです。
|
||||
|
||||
これらの場合、型宣言でリストを使用して定義することができます。
|
||||
これらの場合、リストの型宣言を使用して定義することができます。
|
||||
|
||||
重複したヘッダーのすべての値をPythonの`list`として受け取ることができます。
|
||||
|
||||
例えば、複数回出現する可能性のある`X-Token`のヘッダを定義するには、以下のように書くことができます:
|
||||
|
||||
{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *}
|
||||
{* ../../docs_src/header_params/tutorial003.py hl[9] *}
|
||||
|
||||
その*path operation*と通信する際に、次のように2つのHTTPヘッダーを送信する場合:
|
||||
もし、その*path operation*で通信する場合は、次のように2つのHTTPヘッダーを送信します:
|
||||
|
||||
```
|
||||
X-Token: foo
|
||||
X-Token: bar
|
||||
```
|
||||
|
||||
レスポンスは以下のようになります:
|
||||
このレスポンスは以下のようになります:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -84,8 +84,8 @@ X-Token: bar
|
||||
}
|
||||
```
|
||||
|
||||
## まとめ { #recap }
|
||||
## まとめ
|
||||
|
||||
ヘッダーは`Header`で宣言し、`Query`や`Path`、`Cookie`と同じ共通パターンを使用します。
|
||||
ヘッダーは`Header`で宣言し、`Query`や`Path`、`Cookie`と同じパターンを使用する。
|
||||
|
||||
また、変数のアンダースコアを気にする必要はありません。**FastAPI** がそれらの変換をすべて取り持ってくれます。
|
||||
|
||||
@@ -1,95 +1,83 @@
|
||||
# チュートリアル - ユーザーガイド { #tutorial-user-guide }
|
||||
# チュートリアル - ユーザーガイド
|
||||
|
||||
このチュートリアルでは、**FastAPI**のほとんどの機能を使う方法を段階的に紹介します。
|
||||
このチュートリアルは**FastAPI**のほぼすべての機能の使い方を段階的に紹介します。
|
||||
|
||||
各セクションは前のセクションを踏まえた内容になっています。しかし、トピックごとに分割されているので、特定のAPIのニーズを満たすために、任意の特定のトピックに直接進めるようになっています。
|
||||
各セクションは前のセクションを踏まえた内容になっています。しかし、トピックごとに分割されているので、特定のAPIの要求を満たすようなトピックに直接たどり着けるようになっています。
|
||||
|
||||
また、将来的にリファレンスとして機能するように構築されているので、後で戻ってきて必要なものを正確に確認できます。
|
||||
また、将来的にリファレンスとして機能するように構築されています。
|
||||
|
||||
## コードを実行する { #run-the-code }
|
||||
従って、後でこのチュートリアルに戻ってきて必要なものを確認できます。
|
||||
|
||||
## コードを実行する
|
||||
|
||||
すべてのコードブロックをコピーして直接使用できます(実際にテストされたPythonファイルです)。
|
||||
|
||||
いずれかの例を実行するには、コードを `main.py`ファイルにコピーし、次のように `fastapi dev` を起動します:
|
||||
いずれかの例を実行するには、コードを `main.py`ファイルにコピーし、` uvicorn`を次のように起動します:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting development server 🚀
|
||||
|
||||
Searching for package file structure from directories
|
||||
with <font color="#3465A4">__init__.py</font> files
|
||||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with
|
||||
the following code:
|
||||
|
||||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000/docs</u></font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> tip </font></span> Running in development mode, for production use:
|
||||
<b>fastapi run</b>
|
||||
|
||||
Logs:
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Will watch for changes in these directories:
|
||||
<b>[</b><font color="#4E9A06">'/home/user/code/awesomeapp'</font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C
|
||||
to quit<b>)</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started reloader process <b>[</b><font color="#34E2E2"><b>383138</b></font><b>]</b> using WatchFiles
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>383153</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
<span style="color: green;">INFO</span>: Started reloader process [28720]
|
||||
<span style="color: green;">INFO</span>: Started server process [28722]
|
||||
<span style="color: green;">INFO</span>: Waiting for application startup.
|
||||
<span style="color: green;">INFO</span>: Application startup complete.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
コードを記述またはコピーし、編集してローカルで実行することを**強く推奨します**。
|
||||
コードを記述またはコピーし、編集してローカルで実行することを**強くお勧めします**。
|
||||
|
||||
エディターで使用することで、書く必要のあるコードの少なさ、すべての型チェック、自動補完など、FastAPIの利点を本当に実感できます。
|
||||
また、エディターで使用することで、書く必要のあるコードの少なさ、すべての型チェック、自動補完などのFastAPIの利点を実感できます。
|
||||
|
||||
---
|
||||
|
||||
## FastAPIをインストールする { #install-fastapi }
|
||||
## FastAPIをインストールする
|
||||
|
||||
最初のステップは、FastAPIのインストールです。
|
||||
|
||||
[仮想環境](../virtual-environments.md){.internal-link target=_blank} を作成して有効化し、それから **FastAPIをインストール** してください:
|
||||
チュートリアルのために、すべてのオプションの依存関係と機能をインストールしたいとき:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install "fastapi[standard]"
|
||||
$ pip install "fastapi[all]"
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
...これには、コードを実行するサーバーとして使用できる `uvicorn`も含まれます。
|
||||
|
||||
/// note | 備考
|
||||
|
||||
`pip install "fastapi[standard]"` でインストールすると、`fastapi-cloud-cli` を含むいくつかのデフォルトのオプション標準依存関係が付属します。これにより、<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a> にデプロイできます。
|
||||
パーツ毎にインストールすることも可能です。
|
||||
|
||||
これらのオプション依存関係が不要な場合は、代わりに `pip install fastapi` をインストールできます。
|
||||
以下は、アプリケーションを本番環境にデプロイする際に行うであろうものです:
|
||||
|
||||
標準依存関係はインストールしたいが `fastapi-cloud-cli` は不要な場合は、`pip install "fastapi[standard-no-fastapi-cloud-cli]"` でインストールできます。
|
||||
```
|
||||
pip install fastapi
|
||||
```
|
||||
|
||||
また、サーバーとして動作するように`uvicorn` をインストールします:
|
||||
|
||||
```
|
||||
pip install "uvicorn[standard]"
|
||||
```
|
||||
|
||||
そして、使用したい依存関係をそれぞれ同様にインストールします。
|
||||
|
||||
///
|
||||
|
||||
## 高度なユーザーガイド { #advanced-user-guide }
|
||||
## 高度なユーザーガイド
|
||||
|
||||
この **チュートリアル - ユーザーガイド** の後で、後から読める **高度なユーザーガイド** もあります。
|
||||
**高度なユーザーガイド**もあり、**チュートリアル - ユーザーガイド**の後で読むことができます。
|
||||
|
||||
**高度なユーザーガイド** は本チュートリアルをベースにしており、同じ概念を使用し、いくつかの追加機能を教えます。
|
||||
**高度なユーザーガイド**は**チュートリアル - ユーザーガイド**に基づいており、同じ概念を使用し、いくつかの追加機能を紹介しています。
|
||||
|
||||
ただし、最初に **チュートリアル - ユーザーガイド**(今読んでいる内容)をお読みください。
|
||||
ただし、最初に**チュートリアル - ユーザーガイド**(現在読んでいる内容)をお読みください。
|
||||
|
||||
**チュートリアル - ユーザーガイド** だけで完全なアプリケーションを構築できるように設計されており、その後ニーズに応じて、**高度なユーザーガイド** の追加のアイデアのいくつかを使って、さまざまな方法で拡張できます。
|
||||
**チュートリアル-ユーザーガイド**だけで完全なアプリケーションを構築できるように設計されています。加えて、**高度なユーザーガイド**の中からニーズに応じたアイデアを使用して、様々な拡張が可能です。
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user