mirror of
https://github.com/fastapi/fastapi.git
synced 2026-02-10 22:32:08 -05:00
Compare commits
11 Commits
0.128.7
...
add-tests-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fed2671c4 | ||
|
|
d90bcc8569 | ||
|
|
27cc340880 | ||
|
|
9e85c19d3a | ||
|
|
3441e14197 | ||
|
|
e1adc4a739 | ||
|
|
e6475e960a | ||
|
|
2d43382626 | ||
|
|
0b5fea716b | ||
|
|
22d795d890 | ||
|
|
dada1d581f |
24
.github/workflows/test.yml
vendored
24
.github/workflows/test.yml
vendored
@@ -14,7 +14,6 @@ on:
|
||||
|
||||
env:
|
||||
UV_NO_SYNC: true
|
||||
INLINE_SNAPSHOT_DEFAULT_FLAGS: review
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
@@ -50,45 +49,31 @@ jobs:
|
||||
matrix:
|
||||
os: [ windows-latest, macos-latest ]
|
||||
python-version: [ "3.14" ]
|
||||
uv-resolution:
|
||||
- highest
|
||||
starlette-src:
|
||||
- starlette-pypi
|
||||
- starlette-git
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
python-version: "3.9"
|
||||
coverage: coverage
|
||||
uv-resolution: lowest-direct
|
||||
- os: macos-latest
|
||||
python-version: "3.10"
|
||||
coverage: coverage
|
||||
uv-resolution: highest
|
||||
- os: windows-latest
|
||||
python-version: "3.12"
|
||||
coverage: coverage
|
||||
uv-resolution: lowest-direct
|
||||
- os: ubuntu-latest
|
||||
python-version: "3.13"
|
||||
coverage: coverage
|
||||
uv-resolution: highest
|
||||
# Ubuntu with 3.13 needs coverage for CodSpeed benchmarks
|
||||
- os: ubuntu-latest
|
||||
python-version: "3.13"
|
||||
coverage: coverage
|
||||
uv-resolution: highest
|
||||
codspeed: codspeed
|
||||
- os: ubuntu-latest
|
||||
python-version: "3.14"
|
||||
coverage: coverage
|
||||
uv-resolution: highest
|
||||
starlette-src: starlette-git
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
UV_PYTHON: ${{ matrix.python-version }}
|
||||
UV_RESOLUTION: ${{ matrix.uv-resolution }}
|
||||
STARLETTE_SRC: ${{ matrix.starlette-src }}
|
||||
steps:
|
||||
- name: Dump GitHub context
|
||||
env:
|
||||
@@ -107,14 +92,11 @@ jobs:
|
||||
pyproject.toml
|
||||
uv.lock
|
||||
- name: Install Dependencies
|
||||
run: uv sync --no-dev --group tests --extra all
|
||||
- name: Install Starlette from source
|
||||
if: matrix.starlette-src == 'starlette-git'
|
||||
run: uv pip install "git+https://github.com/Kludex/starlette@main"
|
||||
run: uv sync --locked --no-dev --group tests --extra all
|
||||
- run: mkdir coverage
|
||||
- name: Test
|
||||
if: matrix.codspeed != 'codspeed'
|
||||
run: uv run --no-sync bash scripts/test.sh
|
||||
run: uv run bash scripts/test.sh
|
||||
env:
|
||||
COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }}
|
||||
CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}
|
||||
@@ -126,7 +108,7 @@ jobs:
|
||||
CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}
|
||||
with:
|
||||
mode: simulation
|
||||
run: uv run --no-sync coverage run -m pytest tests/ --codspeed
|
||||
run: uv run coverage run -m pytest tests/ --codspeed
|
||||
# Do not store coverage for all possible combinations to avoid file size max errors in Smokeshow
|
||||
- name: Store coverage files
|
||||
if: matrix.coverage == 'coverage'
|
||||
|
||||
6
.github/workflows/translate.yml
vendored
6
.github/workflows/translate.yml
vendored
@@ -35,11 +35,6 @@ on:
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
max:
|
||||
description: Maximum number of items to translate (e.g. 10)
|
||||
type: number
|
||||
required: false
|
||||
default: 10
|
||||
|
||||
jobs:
|
||||
langs:
|
||||
@@ -120,4 +115,3 @@ jobs:
|
||||
EN_PATH: ${{ github.event.inputs.en_path }}
|
||||
COMMAND: ${{ matrix.command }}
|
||||
COMMIT_IN_PLACE: ${{ github.event.inputs.commit_in_place }}
|
||||
MAX: ${{ github.event.inputs.max }}
|
||||
|
||||
10
README.md
10
README.md
@@ -34,7 +34,7 @@ The key features are:
|
||||
* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance).
|
||||
* **Fast to code**: Increase the speed to develop features by about 200% to 300%. *
|
||||
* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. *
|
||||
* **Intuitive**: Great editor support. <dfn title="also known as auto-complete, autocompletion, IntelliSense">Completion</dfn> everywhere. Less time debugging.
|
||||
* **Intuitive**: Great editor support. <abbr title="also known as auto-complete, autocompletion, IntelliSense">Completion</abbr> everywhere. Less time debugging.
|
||||
* **Easy**: Designed to be easy to use and learn. Less time reading docs.
|
||||
* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.
|
||||
* **Robust**: Get production-ready code. With automatic interactive documentation.
|
||||
@@ -371,7 +371,7 @@ item: Item
|
||||
* Validation of data:
|
||||
* Automatic and clear errors when the data is invalid.
|
||||
* Validation even for deeply nested JSON objects.
|
||||
* <dfn title="also known as: serialization, parsing, marshalling">Conversion</dfn> of input data: coming from the network to Python data and types. Reading from:
|
||||
* <abbr title="also known as: serialization, parsing, marshalling">Conversion</abbr> of input data: coming from the network to Python data and types. Reading from:
|
||||
* JSON.
|
||||
* Path parameters.
|
||||
* Query parameters.
|
||||
@@ -379,7 +379,7 @@ item: Item
|
||||
* Headers.
|
||||
* Forms.
|
||||
* Files.
|
||||
* <dfn title="also known as: serialization, parsing, marshalling">Conversion</dfn> of output data: converting from Python data and types to network data (as JSON):
|
||||
* <abbr title="also known as: serialization, parsing, marshalling">Conversion</abbr> of output data: converting from Python data and types to network data (as JSON):
|
||||
* Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc).
|
||||
* `datetime` objects.
|
||||
* `UUID` objects.
|
||||
@@ -442,7 +442,7 @@ For a more complete example including more features, see the <a href="https://fa
|
||||
|
||||
* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**.
|
||||
* How to set **validation constraints** as `maximum_length` or `regex`.
|
||||
* A very powerful and easy to use **<dfn title="also known as components, resources, providers, services, injectables">Dependency Injection</dfn>** system.
|
||||
* A very powerful and easy to use **<abbr title="also known as components, resources, providers, services, injectables">Dependency Injection</abbr>** system.
|
||||
* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth.
|
||||
* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic).
|
||||
* **GraphQL** integration with <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> and other libraries.
|
||||
@@ -527,7 +527,7 @@ Used by Starlette:
|
||||
|
||||
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Required if you want to use the `TestClient`.
|
||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <dfn title="converting the string that comes from an HTTP request into Python data">"parsing"</dfn>, with `request.form()`.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
||||
|
||||
Used by FastAPI:
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ Siehe Abschnitt `### Content of code snippets` im allgemeinen Prompt in `scripts
|
||||
|
||||
//// tab | Test
|
||||
|
||||
Gestern schrieb mein Freund: „Wenn man ‚incorrectly‘ korrekt schreibt, hat man es falsch geschrieben“. Worauf ich antwortete: „Korrekt, aber ‚incorrectly‘ ist inkorrekterweise nicht ‚„incorrectly“‘“.
|
||||
Gestern schrieb mein Freund: „Wenn man unkorrekt korrekt schreibt, hat man es unkorrekt geschrieben“. Worauf ich antwortete: „Korrekt, aber ‚unkorrekt‘ ist unkorrekterweise nicht ‚„unkorrekt“‘“.
|
||||
|
||||
/// note | Hinweis
|
||||
|
||||
@@ -202,6 +202,11 @@ Hier einige Dinge, die in HTML-„abbr“-Elemente gepackt sind (einige sind erf
|
||||
* <abbr title="XML Web Token">XWT</abbr>
|
||||
* <abbr title="Paralleles Server-Gateway-Interface">PSGI</abbr>
|
||||
|
||||
### Das abbr gibt eine Erklärung { #the-abbr-gives-an-explanation }
|
||||
|
||||
* <abbr title="Eine Gruppe von Maschinen, die so konfiguriert sind, dass sie verbunden sind und in irgendeiner Weise zusammenarbeiten.">Cluster</abbr>
|
||||
* <abbr title="Eine Methode des Machine Learning, die künstliche neuronale Netze mit zahlreichen versteckten Schichten zwischen Eingabe- und Ausgabeschicht verwendet und so eine umfassende interne Struktur entwickelt">Deep Learning</abbr>
|
||||
|
||||
### Das abbr gibt eine vollständige Phrase und eine Erklärung { #the-abbr-gives-a-full-phrase-and-an-explanation }
|
||||
|
||||
* <abbr title="Mozilla Developer Network – Mozilla-Entwicklernetzwerk: Dokumentation für Entwickler, geschrieben von den Firefox-Leuten">MDN</abbr>
|
||||
@@ -219,11 +224,6 @@ Siehe Abschnitt `### HTML abbr elements` im allgemeinen Prompt in `scripts/trans
|
||||
|
||||
////
|
||||
|
||||
## HTML „dfn“-Elemente { #html-dfn-elements }
|
||||
|
||||
* <dfn title="Eine Gruppe von Maschinen, die so konfiguriert sind, dass sie verbunden sind und in irgendeiner Weise zusammenarbeiten.">Cluster</dfn>
|
||||
* <dfn title="Eine Methode des Machine Learning, die künstliche neuronale Netze mit zahlreichen versteckten Schichten zwischen Eingabe- und Ausgabeschicht verwendet und so eine umfassende interne Struktur entwickelt">Deep Learning</dfn>
|
||||
|
||||
## Überschriften { #headings }
|
||||
|
||||
//// tab | Test
|
||||
@@ -248,7 +248,7 @@ Die einzige strenge Regel für Überschriften ist, dass das LLM den Hash-Teil in
|
||||
|
||||
Siehe Abschnitt `### Headings` im allgemeinen Prompt in `scripts/translate.py`.
|
||||
|
||||
Für einige sprachsspezifische Anweisungen, siehe z. B. den Abschnitt `### Headings` in `docs/de/llm-prompt.md`.
|
||||
Für einige sprachspezifische Anweisungen, siehe z. B. den Abschnitt `### Headings` in `docs/de/llm-prompt.md`.
|
||||
|
||||
////
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -202,6 +202,11 @@ Here some things wrapped in HTML "abbr" elements (Some are invented):
|
||||
* <abbr title="XML Web Token">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface">PSGI</abbr>
|
||||
|
||||
### The abbr gives an explanation { #the-abbr-gives-an-explanation }
|
||||
|
||||
* <abbr title="A group of machines that are configured to be connected and work together in some way.">cluster</abbr>
|
||||
* <abbr title="A method of machine learning that uses artificial neural networks with numerous hidden layers between input and output layers, thereby developing a comprehensive internal structure">Deep Learning</abbr>
|
||||
|
||||
### The abbr gives a full phrase and an explanation { #the-abbr-gives-a-full-phrase-and-an-explanation }
|
||||
|
||||
* <abbr title="Mozilla Developer Network: documentation for developers, written by the Firefox people">MDN</abbr>
|
||||
@@ -219,11 +224,6 @@ See section `### HTML abbr elements` in the general prompt in `scripts/translate
|
||||
|
||||
////
|
||||
|
||||
## HTML "dfn" elements { #html-dfn-elements }
|
||||
|
||||
* <dfn title="A group of machines that are configured to be connected and work together in some way.">cluster</dfn>
|
||||
* <dfn title="A method of machine learning that uses artificial neural networks with numerous hidden layers between input and output layers, thereby developing a comprehensive internal structure">Deep Learning</dfn>
|
||||
|
||||
## Headings { #headings }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
@@ -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] *}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ In that case, you can simply swap the standard `dataclasses` with `pydantic.data
|
||||
|
||||
6. Here we are returning a dictionary that contains `items` which is a list of dataclasses.
|
||||
|
||||
FastAPI is still capable of <dfn title="converting the data to a format that can be transmitted">serializing</dfn> the data to JSON.
|
||||
FastAPI is still capable of <abbr title="converting the data to a format that can be transmitted">serializing</abbr> the data to JSON.
|
||||
|
||||
7. Here the `response_model` is using a type annotation of a list of `Author` dataclasses.
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ You could do that with `openapi_extra`:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *}
|
||||
|
||||
In this example, we didn't declare any Pydantic model. In fact, the request body is not even <dfn title="converted from some plain format, like bytes, into Python objects">parsed</dfn> as JSON, it is read directly as `bytes`, and the function `magic_data_reader()` would be in charge of parsing it in some way.
|
||||
In this example, we didn't declare any Pydantic model. In fact, the request body is not even <abbr title="converted from some plain format, like bytes, into Python objects">parsed</abbr> as JSON, it is read directly as `bytes`, and the function `magic_data_reader()` would be in charge of parsing it in some way.
|
||||
|
||||
Nevertheless, we can declare the expected schema for the request body.
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ There are several Flask REST frameworks, but after investing the time and work i
|
||||
|
||||
### <a href="https://marshmallow.readthedocs.io/en/stable/" class="external-link" target="_blank">Marshmallow</a> { #marshmallow }
|
||||
|
||||
One of the main features needed by API systems is data "<dfn title="also called marshalling, conversion">serialization</dfn>" which is taking data from the code (Python) and converting it into something that can be sent through the network. For example, converting an object containing data from a database into a JSON object. Converting `datetime` objects into strings, etc.
|
||||
One of the main features needed by API systems is data "<abbr title="also called marshalling, conversion">serialization</abbr>" which is taking data from the code (Python) and converting it into something that can be sent through the network. For example, converting an object containing data from a database into a JSON object. Converting `datetime` objects into strings, etc.
|
||||
|
||||
Another big feature needed by APIs is data validation, making sure that the data is valid, given certain parameters. For example, that some field is an `int`, and not some random string. This is especially useful for incoming data.
|
||||
|
||||
@@ -145,7 +145,7 @@ Without a data validation system, you would have to do all the checks by hand, i
|
||||
|
||||
These features are what Marshmallow was built to provide. It is a great library, and I have used it a lot before.
|
||||
|
||||
But it was created before there existed Python type hints. So, to define every <dfn title="the definition of how data should be formed">schema</dfn> you need to use specific utils and classes provided by Marshmallow.
|
||||
But it was created before there existed Python type hints. So, to define every <abbr title="the definition of how data should be formed">schema</abbr> you need to use specific utils and classes provided by Marshmallow.
|
||||
|
||||
/// check | Inspired **FastAPI** to
|
||||
|
||||
@@ -155,7 +155,7 @@ Use code to define "schemas" that provide data types and validation, automatical
|
||||
|
||||
### <a href="https://webargs.readthedocs.io/en/latest/" class="external-link" target="_blank">Webargs</a> { #webargs }
|
||||
|
||||
Another big feature required by APIs is <dfn title="reading and converting to Python data">parsing</dfn> data from incoming requests.
|
||||
Another big feature required by APIs is <abbr title="reading and converting to Python data">parsing</abbr> data from incoming requests.
|
||||
|
||||
Webargs is a tool that was made to provide that on top of several frameworks, including Flask.
|
||||
|
||||
@@ -419,7 +419,7 @@ Handle all the data validation, data serialization and automatic model documenta
|
||||
|
||||
### <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a> { #starlette }
|
||||
|
||||
Starlette is a lightweight <dfn title="The new standard for building asynchronous Python web applications">ASGI</dfn> framework/toolkit, which is ideal for building high-performance asyncio services.
|
||||
Starlette is a lightweight <abbr title="The new standard for building asynchronous Python web applications">ASGI</abbr> framework/toolkit, which is ideal for building high-performance asyncio services.
|
||||
|
||||
It is very simple and intuitive. It's designed to be easily extensible, and have modular components.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
#### 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
|
||||
|
||||
|
||||
@@ -203,8 +203,3 @@ Inspired by Termynal's CSS tricks with modifications
|
||||
-webkit-box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930;
|
||||
box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930;
|
||||
}
|
||||
|
||||
.md-typeset dfn {
|
||||
border-bottom: .05rem dotted var(--md-default-fg-color--light);
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
@@ -454,7 +454,7 @@ Without using containers, making applications run on startup and with restarts c
|
||||
|
||||
## Replication - Number of Processes { #replication-number-of-processes }
|
||||
|
||||
If you have a <dfn title="A group of machines that are configured to be connected and work together in some way.">cluster</dfn> of machines with **Kubernetes**, Docker Swarm Mode, Nomad, or another similar complex system to manage distributed containers on multiple machines, then you will probably want to **handle replication** at the **cluster level** instead of using a **process manager** (like Uvicorn with workers) in each container.
|
||||
If you have a <abbr title="A group of machines that are configured to be connected and work together in some way.">cluster</abbr> of machines with **Kubernetes**, Docker Swarm Mode, Nomad, or another similar complex system to manage distributed containers on multiple machines, then you will probably want to **handle replication** at the **cluster level** instead of using a **process manager** (like Uvicorn with workers) in each container.
|
||||
|
||||
One of those distributed container management systems like Kubernetes normally has some integrated way of handling **replication of containers** while still supporting **load balancing** for the incoming requests. All at the **cluster level**.
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ Here's an example of how an HTTPS API could look like, step by step, paying atte
|
||||
|
||||
It would probably all start by you **acquiring** some **domain name**. Then, you would configure it in a DNS server (possibly your same cloud provider).
|
||||
|
||||
You would probably get a cloud server (a virtual machine) or something similar, and it would have a <dfn title="Doesn't change over time. Not dynamic.">fixed</dfn> **public IP address**.
|
||||
You would probably get a cloud server (a virtual machine) or something similar, and it would have a <abbr title="That doesn't change">fixed</abbr> **public IP address**.
|
||||
|
||||
In the DNS server(s) you would configure a record (an "`A record`") to point **your domain** to the public **IP address of your server**.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
### Based on open standards { #based-on-open-standards }
|
||||
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a> for API creation, including declarations of <dfn title="also known as: endpoints, routes">path</dfn> <dfn title="also known as HTTP methods, as POST, GET, PUT, DELETE">operations</dfn>, parameters, request bodies, security, etc.
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a> for API creation, including declarations of <abbr title="also known as: endpoints, routes">path</abbr> <abbr title="also known as HTTP methods, as POST, GET, PUT, DELETE">operations</abbr>, parameters, request bodies, security, etc.
|
||||
* Automatic data model documentation with <a href="https://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a> (as OpenAPI itself is based on JSON Schema).
|
||||
* Designed around these standards, after a meticulous study. Instead of an afterthought layer on top.
|
||||
* This also allows using automatic **client code generation** in many languages.
|
||||
@@ -136,7 +136,7 @@ All built as reusable tools and components that are easy to integrate with your
|
||||
|
||||
### Dependency Injection { #dependency-injection }
|
||||
|
||||
FastAPI includes an extremely easy to use, but extremely powerful <dfn title='also known as "components", "resources", "services", "providers"'><strong>Dependency Injection</strong></dfn> system.
|
||||
FastAPI includes an extremely easy to use, but extremely powerful <abbr title='also known as "components", "resources", "services", "providers"'><strong>Dependency Injection</strong></abbr> system.
|
||||
|
||||
* Even dependencies can have dependencies, creating a hierarchy or **"graph" of dependencies**.
|
||||
* All **automatically handled** by the framework.
|
||||
@@ -153,8 +153,8 @@ Any integration is designed to be so simple to use (with dependencies) that you
|
||||
|
||||
### Tested { #tested }
|
||||
|
||||
* 100% <dfn title="The amount of code that is automatically tested">test coverage</dfn>.
|
||||
* 100% <dfn title="Python type annotations, with this your editor and external tools can give you better support">type annotated</dfn> code base.
|
||||
* 100% <abbr title="The amount of code that is automatically tested">test coverage</abbr>.
|
||||
* 100% <abbr title="Python type annotations, with this your editor and external tools can give you better support">type annotated</abbr> code base.
|
||||
* Used in production applications.
|
||||
|
||||
## Starlette features { #starlette-features }
|
||||
@@ -190,7 +190,7 @@ With **FastAPI** you get all of **Pydantic**'s features (as FastAPI is based on
|
||||
* **No brainfuck**:
|
||||
* No new schema definition micro-language to learn.
|
||||
* If you know Python types you know how to use Pydantic.
|
||||
* Plays nicely with your **<abbr title="Integrated Development Environment: similar to a code editor">IDE</abbr>/<dfn title="A program that checks for code errors">linter</dfn>/brain**:
|
||||
* Plays nicely with your **<abbr title="Integrated Development Environment: similar to a code editor">IDE</abbr>/<abbr title="A program that checks for code errors">linter</abbr>/brain**:
|
||||
* Because pydantic data structures are just instances of classes you define; auto-completion, linting, mypy and your intuition should all work properly with your validated data.
|
||||
* Validate **complex structures**:
|
||||
* Use of hierarchical Pydantic models, Python `typing`’s `List` and `Dict`, etc.
|
||||
|
||||
@@ -40,7 +40,7 @@ The key features are:
|
||||
* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance).
|
||||
* **Fast to code**: Increase the speed to develop features by about 200% to 300%. *
|
||||
* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. *
|
||||
* **Intuitive**: Great editor support. <dfn title="also known as auto-complete, autocompletion, IntelliSense">Completion</dfn> everywhere. Less time debugging.
|
||||
* **Intuitive**: Great editor support. <abbr title="also known as auto-complete, autocompletion, IntelliSense">Completion</abbr> everywhere. Less time debugging.
|
||||
* **Easy**: Designed to be easy to use and learn. Less time reading docs.
|
||||
* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.
|
||||
* **Robust**: Get production-ready code. With automatic interactive documentation.
|
||||
@@ -368,7 +368,7 @@ item: Item
|
||||
* Validation of data:
|
||||
* Automatic and clear errors when the data is invalid.
|
||||
* Validation even for deeply nested JSON objects.
|
||||
* <dfn title="also known as: serialization, parsing, marshalling">Conversion</dfn> of input data: coming from the network to Python data and types. Reading from:
|
||||
* <abbr title="also known as: serialization, parsing, marshalling">Conversion</abbr> of input data: coming from the network to Python data and types. Reading from:
|
||||
* JSON.
|
||||
* Path parameters.
|
||||
* Query parameters.
|
||||
@@ -376,7 +376,7 @@ item: Item
|
||||
* Headers.
|
||||
* Forms.
|
||||
* Files.
|
||||
* <dfn title="also known as: serialization, parsing, marshalling">Conversion</dfn> of output data: converting from Python data and types to network data (as JSON):
|
||||
* <abbr title="also known as: serialization, parsing, marshalling">Conversion</abbr> of output data: converting from Python data and types to network data (as JSON):
|
||||
* Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc).
|
||||
* `datetime` objects.
|
||||
* `UUID` objects.
|
||||
@@ -439,7 +439,7 @@ For a more complete example including more features, see the <a href="https://fa
|
||||
|
||||
* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**.
|
||||
* How to set **validation constraints** as `maximum_length` or `regex`.
|
||||
* A very powerful and easy to use **<dfn title="also known as components, resources, providers, services, injectables">Dependency Injection</dfn>** system.
|
||||
* A very powerful and easy to use **<abbr title="also known as components, resources, providers, services, injectables">Dependency Injection</abbr>** system.
|
||||
* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth.
|
||||
* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic).
|
||||
* **GraphQL** integration with <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> and other libraries.
|
||||
@@ -524,7 +524,7 @@ Used by Starlette:
|
||||
|
||||
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Required if you want to use the `TestClient`.
|
||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <dfn title="converting the string that comes from an HTTP request into Python data">"parsing"</dfn>, with `request.form()`.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
||||
|
||||
Used by FastAPI:
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Python has support for optional "type hints" (also called "type annotations").
|
||||
|
||||
These **"type hints"** or annotations are a special syntax that allow declaring the <dfn title="for example: str, int, float, bool">type</dfn> of a variable.
|
||||
These **"type hints"** or annotations are a special syntax that allow declaring the <abbr title="for example: str, int, float, bool">type</abbr> of a variable.
|
||||
|
||||
By declaring types for your variables, editors and tools can give you better support.
|
||||
|
||||
@@ -34,7 +34,7 @@ The function does the following:
|
||||
|
||||
* Takes a `first_name` and `last_name`.
|
||||
* Converts the first letter of each one to upper case with `title()`.
|
||||
* <dfn title="Puts them together, as one. With the contents of one after the other.">Concatenates</dfn> them with a space in the middle.
|
||||
* <abbr title="Puts them together, as one. With the contents of one after the other.">Concatenates</abbr> them with a space in the middle.
|
||||
|
||||
{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *}
|
||||
|
||||
@@ -222,7 +222,7 @@ You can declare that a variable can be any of **several types**, for example, an
|
||||
|
||||
In Python 3.6 and above (including Python 3.10) you can use the `Union` type from `typing` and put inside the square brackets the possible types to accept.
|
||||
|
||||
In Python 3.10 there's also a **new syntax** where you can put the possible types separated by a <dfn title='also called "bitwise or operator", but that meaning is not relevant here'>vertical bar (`|`)</dfn>.
|
||||
In Python 3.10 there's also a **new syntax** where you can put the possible types separated by a <abbr title='also called "bitwise or operator", but that meaning is not relevant here'>vertical bar (`|`)</abbr>.
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
@@ -336,7 +336,7 @@ And the same as with previous Python versions, from the `typing` module:
|
||||
* `Optional`
|
||||
* ...and others.
|
||||
|
||||
In Python 3.10, as an alternative to using the generics `Union` and `Optional`, you can use the <dfn title='also called "bitwise or operator", but that meaning is not relevant here'>vertical bar (`|`)</dfn> to declare unions of types, that's a lot better and simpler.
|
||||
In Python 3.10, as an alternative to using the generics `Union` and `Optional`, you can use the <abbr title='also called "bitwise or operator", but that meaning is not relevant here'>vertical bar (`|`)</abbr> to declare unions of types, that's a lot better and simpler.
|
||||
|
||||
////
|
||||
|
||||
@@ -411,7 +411,7 @@ Pydantic has a special behavior when you use `Optional` or `Union[Something, Non
|
||||
|
||||
## Type Hints with Metadata Annotations { #type-hints-with-metadata-annotations }
|
||||
|
||||
Python also has a feature that allows putting **additional <dfn title="Data about the data, in this case, information about the type, e.g. a description.">metadata</dfn>** in these type hints using `Annotated`.
|
||||
Python also has a feature that allows putting **additional <abbr title="Data about the data, in this case, information about the type, e.g. a description.">metadata</abbr>** in these type hints using `Annotated`.
|
||||
|
||||
Since Python 3.9, `Annotated` is a part of the standard library, so you can import it from `typing`.
|
||||
|
||||
|
||||
@@ -7,124 +7,10 @@ hide:
|
||||
|
||||
## Latest Changes
|
||||
|
||||
## 0.128.7
|
||||
|
||||
### Features
|
||||
|
||||
* ✨ Show a clear error on attempt to include router into itself. PR [#14258](https://github.com/fastapi/fastapi/pull/14258) by [@JavierSanchezCastro](https://github.com/JavierSanchezCastro).
|
||||
* ✨ Replace `dict` by `Mapping` on `HTTPException.headers`. PR [#12997](https://github.com/fastapi/fastapi/pull/12997) by [@rijenkii](https://github.com/rijenkii).
|
||||
|
||||
### Refactors
|
||||
|
||||
* ♻️ Simplify reading files in memory, do it sequentially instead of (fake) parallel. PR [#14884](https://github.com/fastapi/fastapi/pull/14884) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Docs
|
||||
|
||||
* 📝 Use `dfn` tag for definitions instead of `abbr` in docs. PR [#14744](https://github.com/fastapi/fastapi/pull/14744) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
|
||||
### Internal
|
||||
|
||||
* ✅ Tweak comment in test to reference PR. PR [#14885](https://github.com/fastapi/fastapi/pull/14885) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update LLM-prompt for `abbr` and `dfn` tags. PR [#14747](https://github.com/fastapi/fastapi/pull/14747) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* ✅ Test order for the submitted byte Files. PR [#14828](https://github.com/fastapi/fastapi/pull/14828) by [@valentinDruzhinin](https://github.com/valentinDruzhinin).
|
||||
* 🔧 Configure `test` workflow to run tests with `inline-snapshot=review`. PR [#14876](https://github.com/fastapi/fastapi/pull/14876) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
|
||||
## 0.128.6
|
||||
|
||||
### Fixes
|
||||
|
||||
* 🐛 Fix `on_startup` and `on_shutdown` parameters of `APIRouter`. PR [#14873](https://github.com/fastapi/fastapi/pull/14873) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
|
||||
### Translations
|
||||
|
||||
* 🌐 Update translations for zh (update-outdated). PR [#14843](https://github.com/fastapi/fastapi/pull/14843) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Internal
|
||||
|
||||
* ✅ Fix parameterized tests with snapshots. PR [#14875](https://github.com/fastapi/fastapi/pull/14875) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
|
||||
## 0.128.5
|
||||
|
||||
### Refactors
|
||||
|
||||
* ♻️ Refactor and simplify Pydantic v2 (and v1) compatibility internal utils. PR [#14862](https://github.com/fastapi/fastapi/pull/14862) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Internal
|
||||
|
||||
* ✅ Add inline snapshot tests for OpenAPI before changes from Pydantic v2. PR [#14864](https://github.com/fastapi/fastapi/pull/14864) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
## 0.128.4
|
||||
|
||||
### Refactors
|
||||
|
||||
* ♻️ Refactor internals, simplify Pydantic v2/v1 utils, `create_model_field`, better types for `lenient_issubclass`. PR [#14860](https://github.com/fastapi/fastapi/pull/14860) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ♻️ Simplify internals, remove Pydantic v1 only logic, no longer needed. PR [#14857](https://github.com/fastapi/fastapi/pull/14857) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ♻️ Refactor internals, cleanup unneeded Pydantic v1 specific logic. PR [#14856](https://github.com/fastapi/fastapi/pull/14856) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Translations
|
||||
|
||||
* 🌐 Update translations for fr (outdated pages). PR [#14839](https://github.com/fastapi/fastapi/pull/14839) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 🌐 Update translations for tr (outdated and missing). PR [#14838](https://github.com/fastapi/fastapi/pull/14838) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
|
||||
### Internal
|
||||
|
||||
* ⬆️ Upgrade development dependencies. PR [#14854](https://github.com/fastapi/fastapi/pull/14854) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
## 0.128.3
|
||||
|
||||
### Refactors
|
||||
|
||||
* ♻️ Re-implement `on_event` in FastAPI for compatibility with the next Starlette, while keeping backwards compatibility. PR [#14851](https://github.com/fastapi/fastapi/pull/14851) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Upgrades
|
||||
|
||||
* ⬆️ Upgrade Starlette supported version range to `starlette>=0.40.0,<1.0.0`. PR [#14853](https://github.com/fastapi/fastapi/pull/14853) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Translations
|
||||
|
||||
* 🌐 Update translations for ru (update-outdated). PR [#14834](https://github.com/fastapi/fastapi/pull/14834) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Internal
|
||||
|
||||
* 👷 Run tests with Starlette from git. PR [#14849](https://github.com/fastapi/fastapi/pull/14849) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👷 Run tests with lower bound uv sync, upgrade `fastapi[all]` minimum dependencies: `ujson >=5.8.0`, `orjson >=3.9.3`. PR [#14846](https://github.com/fastapi/fastapi/pull/14846) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
## 0.128.2
|
||||
|
||||
### Features
|
||||
|
||||
* ✨ Add support for PEP695 `TypeAliasType`. PR [#13920](https://github.com/fastapi/fastapi/pull/13920) by [@cstruct](https://github.com/cstruct).
|
||||
* ✨ Allow `Response` type hint as dependency annotation. PR [#14794](https://github.com/fastapi/fastapi/pull/14794) by [@jonathan-fulton](https://github.com/jonathan-fulton).
|
||||
|
||||
### Fixes
|
||||
|
||||
* 🐛 Fix using `Json[list[str]]` type (issue #10997). PR [#14616](https://github.com/fastapi/fastapi/pull/14616) by [@mkanetsuna](https://github.com/mkanetsuna).
|
||||
|
||||
### 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
|
||||
|
||||
* 🌐 Enable Traditional Chinese translations. PR [#14842](https://github.com/fastapi/fastapi/pull/14842) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Enable French docs translations. PR [#14841](https://github.com/fastapi/fastapi/pull/14841) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 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).
|
||||
|
||||
### Internal
|
||||
|
||||
* 🔨 Add max pages to translate to configs. PR [#14840](https://github.com/fastapi/fastapi/pull/14840) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
## 0.128.1
|
||||
|
||||
### Features
|
||||
|
||||
@@ -46,7 +46,7 @@ But even if you **fill the data** and click "Execute", because the docs UI works
|
||||
|
||||
In some special use cases (probably not very common), you might want to **restrict** the cookies that you want to receive.
|
||||
|
||||
Your API now has the power to control its own <dfn title="This is a joke, just in case. It has nothing to do with cookie consents, but it's funny that even the API can now reject the poor cookies. Have a cookie. 🍪">cookie consent</dfn>. 🤪🍪
|
||||
Your API now has the power to control its own <abbr title="This is a joke, just in case. It has nothing to do with cookie consents, but it's funny that even the API can now reject the poor cookies. Have a cookie. 🍪">cookie consent</abbr>. 🤪🍪
|
||||
|
||||
You can use Pydantic's model configuration to `forbid` any `extra` fields:
|
||||
|
||||
@@ -54,9 +54,9 @@ You can use Pydantic's model configuration to `forbid` any `extra` fields:
|
||||
|
||||
If a client tries to send some **extra cookies**, they will receive an **error** response.
|
||||
|
||||
Poor cookie banners with all their effort to get your consent for the <dfn title="This is another joke. Don't pay attention to me. Have some coffee for your cookie. ☕">API to reject it</dfn>. 🍪
|
||||
Poor cookie banners with all their effort to get your consent for the <abbr title="This is another joke. Don't pay attention to me. Have some coffee for your cookie. ☕">API to reject it</abbr>. 🍪
|
||||
|
||||
For example, if the client tries to send a `santa_tracker` cookie with a value of `good-list-please`, the client will receive an **error** response telling them that the `santa_tracker` <dfn title="Santa disapproves the lack of cookies. 🎅 Okay, no more cookie jokes.">cookie is not allowed</dfn>:
|
||||
For example, if the client tries to send a `santa_tracker` cookie with a value of `good-list-please`, the client will receive an **error** response telling them that the `santa_tracker` <abbr title="Santa disapproves the lack of cookies. 🎅 Okay, no more cookie jokes.">cookie is not allowed</abbr>:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -73,4 +73,4 @@ For example, if the client tries to send a `santa_tracker` cookie with a value o
|
||||
|
||||
## Summary { #summary }
|
||||
|
||||
You can use **Pydantic models** to declare <dfn title="Have a last cookie before you go. 🍪">**cookies**</dfn> in **FastAPI**. 😎
|
||||
You can use **Pydantic models** to declare <abbr title="Have a last cookie before you go. 🍪">**cookies**</abbr> in **FastAPI**. 😎
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Dependencies with yield { #dependencies-with-yield }
|
||||
|
||||
FastAPI supports dependencies that do some <dfn title='sometimes also called "exit code", "cleanup code", "teardown code", "closing code", "context manager exit code", etc.'>extra steps after finishing</dfn>.
|
||||
FastAPI supports dependencies that do some <abbr title='sometimes also called "exit code", "cleanup code", "teardown code", "closing code", "context manager exit code", etc.'>extra steps after finishing</abbr>.
|
||||
|
||||
To do this, use `yield` instead of `return`, and write the extra steps (code) after.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Dependencies { #dependencies }
|
||||
|
||||
**FastAPI** has a very powerful but intuitive **<dfn title="also known as components, resources, providers, services, injectables">Dependency Injection</dfn>** system.
|
||||
**FastAPI** has a very powerful but intuitive **<abbr title="also known as components, resources, providers, services, injectables">Dependency Injection</abbr>** system.
|
||||
|
||||
It is designed to be very simple to use, and to make it very easy for any developer to integrate other components with **FastAPI**.
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ query_extractor --> query_or_cookie_extractor --> read_query
|
||||
|
||||
If one of your dependencies is declared multiple times for the same *path operation*, for example, multiple dependencies have a common sub-dependency, **FastAPI** will know to call that sub-dependency only once per request.
|
||||
|
||||
And it will save the returned value in a <dfn title="A utility/system to store computed/generated values, to reuse them instead of computing them again.">"cache"</dfn> and pass it to all the "dependants" that need it in that specific request, instead of calling the dependency multiple times for the same request.
|
||||
And it will save the returned value in a <abbr title="A utility/system to store computed/generated values, to reuse them instead of computing them again.">"cache"</abbr> and pass it to all the "dependants" that need it in that specific request, instead of calling the dependency multiple times for the same request.
|
||||
|
||||
In an advanced scenario where you know you need the dependency to be called at every step (possibly multiple times) in the same request instead of using the "cached" value, you can set the parameter `use_cache=False` when using `Depends`:
|
||||
|
||||
|
||||
@@ -271,7 +271,7 @@ We are going to call them "**operations**" too.
|
||||
The `@app.get("/")` tells **FastAPI** that the function right below is in charge of handling requests that go to:
|
||||
|
||||
* the path `/`
|
||||
* using a <dfn title="an HTTP GET method"><code>get</code> operation</dfn>
|
||||
* using a <abbr title="an HTTP GET method"><code>get</code> operation</abbr>
|
||||
|
||||
/// info | `@decorator` Info
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ You can add a `summary` and `description`:
|
||||
|
||||
## Description from docstring { #description-from-docstring }
|
||||
|
||||
As descriptions tend to be long and cover multiple lines, you can declare the *path operation* description in the function <dfn title="a multi-line string as the first expression inside a function (not assigned to any variable) used for documentation">docstring</dfn> and **FastAPI** will read it from there.
|
||||
As descriptions tend to be long and cover multiple lines, you can declare the *path operation* description in the function <abbr title="a multi-line string as the first expression inside a function (not assigned to any variable) used for documentation">docstring</abbr> and **FastAPI** will read it from there.
|
||||
|
||||
You can write <a href="https://en.wikipedia.org/wiki/Markdown" class="external-link" target="_blank">Markdown</a> in the docstring, it will be interpreted and displayed correctly (taking into account docstring indentation).
|
||||
|
||||
@@ -90,7 +90,7 @@ So, if you don't provide one, **FastAPI** will automatically generate one of "Su
|
||||
|
||||
## Deprecate a *path operation* { #deprecate-a-path-operation }
|
||||
|
||||
If you need to mark a *path operation* as <dfn title="obsolete, recommended not to use it">deprecated</dfn>, but without removing it, pass the parameter `deprecated`:
|
||||
If you need to mark a *path operation* as <abbr title="obsolete, recommended not to use it">deprecated</abbr>, but without removing it, pass the parameter `deprecated`:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ This will give you editor support inside of your function, with error checks, co
|
||||
|
||||
///
|
||||
|
||||
## Data <dfn title="also known as: serialization, parsing, marshalling">conversion</dfn> { #data-conversion }
|
||||
## Data <abbr title="also known as: serialization, parsing, marshalling">conversion</abbr> { #data-conversion }
|
||||
|
||||
If you run this example and open your browser at <a href="http://127.0.0.1:8000/items/3" class="external-link" target="_blank">http://127.0.0.1:8000/items/3</a>, you will see a response of:
|
||||
|
||||
@@ -38,7 +38,7 @@ If you run this example and open your browser at <a href="http://127.0.0.1:8000/
|
||||
|
||||
Notice that the value your function received (and returned) is `3`, as a Python `int`, not a string `"3"`.
|
||||
|
||||
So, with that type declaration, **FastAPI** gives you automatic request <dfn title="converting the string that comes from an HTTP request into Python data">"parsing"</dfn>.
|
||||
So, with that type declaration, **FastAPI** gives you automatic request <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>.
|
||||
|
||||
///
|
||||
|
||||
@@ -144,7 +144,7 @@ Then create class attributes with fixed values, which will be the available vali
|
||||
|
||||
/// tip
|
||||
|
||||
If you are wondering, "AlexNet", "ResNet", and "LeNet" are just names of Machine Learning <dfn title="Technically, Deep Learning model architectures">models</dfn>.
|
||||
If you are wondering, "AlexNet", "ResNet", and "LeNet" are just names of Machine Learning <abbr title="Technically, Deep Learning model architectures">models</abbr>.
|
||||
|
||||
///
|
||||
|
||||
@@ -242,7 +242,7 @@ In that case, the URL would be: `/files//home/johndoe/myfile.txt`, with a double
|
||||
With **FastAPI**, by using short, intuitive and standard Python type declarations, you get:
|
||||
|
||||
* Editor support: error checks, autocompletion, etc.
|
||||
* Data "<dfn title="converting the string that comes from an HTTP request into Python data">parsing</dfn>"
|
||||
* Data "<abbr title="converting the string that comes from an HTTP request into Python data">parsing</abbr>"
|
||||
* Data validation
|
||||
* API annotation and automatic documentation
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ FastAPI will now:
|
||||
|
||||
## Alternative (old): `Query` as the default value { #alternative-old-query-as-the-default-value }
|
||||
|
||||
Previous versions of FastAPI (before <dfn title="before 2023-03">0.95.0</dfn>) required you to use `Query` as the default value of your parameter, instead of putting it in `Annotated`, there's a high chance that you will see code using it around, so I'll explain it to you.
|
||||
Previous versions of FastAPI (before <abbr title="before 2023-03">0.95.0</abbr>) required you to use `Query` as the default value of your parameter, instead of putting it in `Annotated`, there's a high chance that you will see code using it around, so I'll explain it to you.
|
||||
|
||||
/// tip
|
||||
|
||||
@@ -192,7 +192,7 @@ You can also add a parameter `min_length`:
|
||||
|
||||
## Add regular expressions { #add-regular-expressions }
|
||||
|
||||
You can define a <dfn title="A regular expression, regex or regexp is a sequence of characters that define a search pattern for strings.">regular expression</dfn> `pattern` that the parameter should match:
|
||||
You can define a <abbr title="A regular expression, regex or regexp is a sequence of characters that define a search pattern for strings.">regular expression</abbr> `pattern` that the parameter should match:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
|
||||
|
||||
@@ -372,7 +372,7 @@ Then you can declare an `alias`, and that alias is what will be used to find the
|
||||
|
||||
Now let's say you don't like this parameter anymore.
|
||||
|
||||
You have to leave it there a while because there are clients using it, but you want the docs to clearly show it as <dfn title="obsolete, recommended not to use it">deprecated</dfn>.
|
||||
You have to leave it there a while because there are clients using it, but you want the docs to clearly show it as <abbr title="obsolete, recommended not to use it">deprecated</abbr>.
|
||||
|
||||
Then pass the parameter `deprecated=True` to `Query`:
|
||||
|
||||
@@ -402,7 +402,7 @@ Pydantic also has <a href="https://docs.pydantic.dev/latest/concepts/validators/
|
||||
|
||||
///
|
||||
|
||||
For example, this custom validator checks that the item ID starts with `isbn-` for an <abbr title="International Standard Book Number">ISBN</abbr> book number or with `imdb-` for an <abbr title="Internet Movie Database: a website with information about movies">IMDB</abbr> movie URL ID:
|
||||
For example, this custom validator checks that the item ID starts with `isbn-` for an <abbr title="ISBN means International Standard Book Number">ISBN</abbr> book number or with `imdb-` for an <abbr title="IMDB (Internet Movie Database) is a website with information about movies">IMDB</abbr> movie URL ID:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
|
||||
|
||||
@@ -436,7 +436,7 @@ Did you notice? a string using `value.startswith()` can take a tuple, and it wil
|
||||
|
||||
#### A Random Item { #a-random-item }
|
||||
|
||||
With `data.items()` we get an <dfn title="Something we can iterate on with a for loop, like a list, set, etc.">iterable object</dfn> with tuples containing the key and value for each dictionary item.
|
||||
With `data.items()` we get an <abbr title="Something we can iterate on with a for loop, like a list, set, etc.">iterable object</abbr> with tuples containing the key and value for each dictionary item.
|
||||
|
||||
We convert this iterable object into a proper `list` with `list(data.items())`.
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ But when you declare them with Python types (in the example above, as `int`), th
|
||||
All the same process that applied for path parameters also applies for query parameters:
|
||||
|
||||
* Editor support (obviously)
|
||||
* Data <dfn title="converting the string that comes from an HTTP request into Python data">"parsing"</dfn>
|
||||
* Data <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>
|
||||
* Data validation
|
||||
* Automatic documentation
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ Create form parameters the same way you would for `Body` or `Query`:
|
||||
|
||||
For example, in one of the ways the OAuth2 specification can be used (called "password flow") it is required to send a `username` and `password` as form fields.
|
||||
|
||||
The <dfn title="specification">spec</dfn> requires the fields to be exactly named `username` and `password`, and to be sent as form fields, not JSON.
|
||||
The <abbr title="specification">spec</abbr> requires the fields to be exactly named `username` and `password`, and to be sent as form fields, not JSON.
|
||||
|
||||
With `Form` you can declare the same configurations as with `Body` (and `Query`, `Path`, `Cookie`), including validation, examples, an alias (e.g. `user-name` instead of `username`), etc.
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ This will also work because `RedirectResponse` is a subclass of `Response`, and
|
||||
|
||||
But when you return some other arbitrary object that is not a valid Pydantic type (e.g. a database object) and you annotate it like that in the function, FastAPI will try to create a Pydantic response model from that type annotation, and will fail.
|
||||
|
||||
The same would happen if you had something like a <dfn title='A union between multiple types means "any of these types".'>union</dfn> between different types where one or more of them are not valid Pydantic types, for example this would fail 💥:
|
||||
The same would happen if you had something like a <abbr title='A union between multiple types means "any of these types".'>union</abbr> between different types where one or more of them are not valid Pydantic types, for example this would fail 💥:
|
||||
|
||||
{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ You can of course also pass multiple `examples`:
|
||||
|
||||
When you do this, the examples will be part of the internal **JSON Schema** for that body data.
|
||||
|
||||
Nevertheless, at the <dfn title="2023-08-26">time of writing this</dfn>, Swagger UI, the tool in charge of showing the docs UI, doesn't support showing multiple examples for the data in **JSON Schema**. But read below for a workaround.
|
||||
Nevertheless, at the <abbr title="2023-08-26">time of writing this</abbr>, Swagger UI, the tool in charge of showing the docs UI, doesn't support showing multiple examples for the data in **JSON Schema**. But read below for a workaround.
|
||||
|
||||
### OpenAPI-specific `examples` { #openapi-specific-examples }
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ $ cd awesome-project
|
||||
|
||||
## Create a Virtual Environment { #create-a-virtual-environment }
|
||||
|
||||
When you start working on a Python project **for the first time**, create a virtual environment **<dfn title="there are other options, this is a simple guideline">inside your project</dfn>**.
|
||||
When you start working on a Python project **for the first time**, create a virtual environment **<abbr title="there are other options, this is a simple guideline">inside your project</abbr>**.
|
||||
|
||||
/// tip
|
||||
|
||||
|
||||
@@ -317,8 +317,6 @@ extra:
|
||||
name: de - Deutsch
|
||||
- link: /es/
|
||||
name: es - español
|
||||
- link: /fr/
|
||||
name: fr - français
|
||||
- link: /ja/
|
||||
name: ja - 日本語
|
||||
- link: /ko/
|
||||
@@ -331,10 +329,6 @@ extra:
|
||||
name: tr - Türkçe
|
||||
- link: /uk/
|
||||
name: uk - українська мова
|
||||
- link: /zh/
|
||||
name: zh - 简体中文
|
||||
- link: /zh-hant/
|
||||
name: zh-hant - 繁體中文
|
||||
extra_css:
|
||||
- css/termynal.css
|
||||
- css/custom.css
|
||||
|
||||
@@ -202,10 +202,15 @@ Aquí algunas cosas envueltas en elementos HTML "abbr" (algunas son inventadas):
|
||||
* <abbr title="XML Web Token - Token web XML">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface - Interfaz de pasarela de servidor paralela">PSGI</abbr>
|
||||
|
||||
### El abbr da una explicación { #the-abbr-gives-an-explanation }
|
||||
|
||||
* <abbr title="Un grupo de máquinas configuradas para estar conectadas y trabajar juntas de alguna manera.">clúster</abbr>
|
||||
* <abbr title="Un método de machine learning que usa redes neuronales artificiales con numerosas capas ocultas entre las capas de entrada y salida, desarrollando así una estructura interna completa">Deep Learning</abbr>
|
||||
|
||||
### El abbr da una frase completa y una explicación { #the-abbr-gives-a-full-phrase-and-an-explanation }
|
||||
|
||||
* <abbr title="Mozilla Developer Network - Red de Desarrolladores de Mozilla: documentación para desarrolladores, escrita por la gente de Firefox">MDN</abbr>
|
||||
* <abbr title="Input/Output - Entrada/Salida: lectura o escritura de disco, comunicaciones de red.">I/O</abbr>.
|
||||
* <abbr title="Input/Output: lectura o escritura de disco, comunicaciones de red.">I/O</abbr>.
|
||||
|
||||
////
|
||||
|
||||
@@ -219,11 +224,6 @@ Consulta la sección `### HTML abbr elements` en el prompt general en `scripts/t
|
||||
|
||||
////
|
||||
|
||||
## Elementos HTML "dfn" { #html-dfn-elements }
|
||||
|
||||
* <dfn title="Un grupo de máquinas configuradas para estar conectadas y trabajar juntas de alguna manera.">clúster</dfn>
|
||||
* <dfn title="Un método de Machine Learning que usa redes neuronales artificiales con numerosas capas ocultas entre las capas de entrada y salida, desarrollando así una estructura interna completa">Deep Learning</dfn>
|
||||
|
||||
## Encabezados { #headings }
|
||||
|
||||
//// tab | Prueba
|
||||
@@ -433,7 +433,7 @@ Para instrucciones específicas del idioma, mira p. ej. la sección `### Heading
|
||||
* el motor de plantillas
|
||||
|
||||
* la anotación de tipos
|
||||
* la anotación de tipos
|
||||
* las anotaciones de tipos
|
||||
|
||||
* el worker del servidor
|
||||
* el worker de Uvicorn
|
||||
|
||||
@@ -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 du corps de la requête { #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 corps de la requête, **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 corps de la requête 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 corps de la requête 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 corps de la requête { #multiple-body-parameters }
|
||||
## Paramètres multiples du body
|
||||
|
||||
Dans l'exemple précédent, les chemins d'accès attendraient un corps de la requête 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 corps de la req
|
||||
}
|
||||
```
|
||||
|
||||
Mais vous pouvez également déclarer plusieurs paramètres provenant du corps de la requête, 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 corps de la requête 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 corps de la requête, et s'attendra à recevoir un corps de la requête semblable à :
|
||||
Il utilisera alors les noms des paramètres comme clés, et s'attendra à recevoir quelque chose de semblable à :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -52,29 +52,29 @@ 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 corps de la requête 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 corps de la requête { #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 corps de la requête, 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 corps de la requête 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] *}
|
||||
|
||||
Dans ce cas, **FastAPI** s'attendra à un corps de la requête semblable à :
|
||||
Dans ce cas, **FastAPI** s'attendra à un body semblable à :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -92,51 +92,51 @@ Dans ce cas, **FastAPI** s'attendra à un corps de la requête 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 corps de la requête 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 corps de la requête.
|
||||
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 corps de la requête { #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 corps de la requête, 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 corps de la requête, 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 corps de la requête 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 corps de la requête à votre fonction de chemin d'accès, même si une requête ne peut avoir qu'un seul corps de la requête.
|
||||
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 corps de la requête.
|
||||
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 corps de la requête 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}.
|
||||
|
||||
///
|
||||
|
||||
@@ -132,7 +132,7 @@ works(foo="bar") # 이건 동작합니다 🎉
|
||||
일부 텍스트
|
||||
///
|
||||
|
||||
/// note | 기술 세부사항
|
||||
/// note Technical details | 기술 세부사항
|
||||
일부 텍스트
|
||||
///
|
||||
|
||||
@@ -202,6 +202,11 @@ works(foo="bar") # 이건 동작합니다 🎉
|
||||
* <abbr title="XML Web Token - XML 웹 토큰">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface - 병렬 서버 게이트웨이 인터페이스">PSGI</abbr>
|
||||
|
||||
### abbr가 설명을 제공 { #the-abbr-gives-an-explanation }
|
||||
|
||||
* <abbr title="어떤 방식으로든 서로 연결되고 함께 작동하도록 구성된 머신들의 집합입니다.">cluster</abbr>
|
||||
* <abbr title="입력과 출력 계층 사이에 수많은 은닉 계층을 둔 인공 신경망을 사용하는 머신 러닝 방법으로, 이를 통해 포괄적인 내부 구조를 형성합니다">Deep Learning</abbr>
|
||||
|
||||
### abbr가 전체 문구와 설명을 제공 { #the-abbr-gives-a-full-phrase-and-an-explanation }
|
||||
|
||||
* <abbr title="Mozilla Developer Network - 모질라 개발자 네트워크: Firefox를 만드는 사람들이 작성한 개발자용 문서">MDN</abbr>
|
||||
@@ -219,11 +224,6 @@ works(foo="bar") # 이건 동작합니다 🎉
|
||||
|
||||
////
|
||||
|
||||
## HTML "dfn" 요소 { #html-dfn-elements }
|
||||
|
||||
* <dfn title="어떤 방식으로든 서로 연결되고 함께 작동하도록 구성된 머신들의 집합입니다.">클러스터</dfn>
|
||||
* <dfn title="입력과 출력 계층 사이에 수많은 은닉 계층을 둔 인공 신경망을 사용하는 머신 러닝 방법으로, 이를 통해 포괄적인 내부 구조를 형성합니다">딥 러닝</dfn>
|
||||
|
||||
## 제목 { #headings }
|
||||
|
||||
//// tab | 테스트
|
||||
|
||||
@@ -79,13 +79,13 @@ checker(q="somequery")
|
||||
|
||||
### `yield`와 `scope`가 있는 의존성 { #dependencies-with-yield-and-scope }
|
||||
|
||||
0.121.0 버전에서 FastAPI는 `Depends(scope="function")` 지원을 추가했습니다.
|
||||
0.121.0 버전에서 FastAPI는 `yield`가 있는 의존성에 대해 `Depends(scope="function")` 지원을 추가했습니다.
|
||||
|
||||
`Depends(scope="function")`를 사용하면, `yield` 이후의 종료 코드는 *경로 처리 함수*가 끝난 직후(클라이언트에 응답이 반환되기 전)에 실행됩니다.
|
||||
|
||||
그리고 `Depends(scope="request")`(기본값)를 사용하면, `yield` 이후의 종료 코드는 응답이 전송된 후에 실행됩니다.
|
||||
|
||||
자세한 내용은 [`yield`가 있는 의존성 - 조기 종료와 `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope) 문서를 참고하세요.
|
||||
자세한 내용은 [Dependencies with `yield` - Early exit and `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope) 문서를 참고하세요.
|
||||
|
||||
### `yield`가 있는 의존성과 `StreamingResponse`, 기술 세부사항 { #dependencies-with-yield-and-streamingresponse-technical-details }
|
||||
|
||||
@@ -133,7 +133,7 @@ SQLModel(또는 SQLAlchemy)을 사용하면서 이런 특정 사용 사례가
|
||||
|
||||
그러면 세션이 데이터베이스 연결을 해제하여, 다른 요청들이 이를 사용할 수 있게 됩니다.
|
||||
|
||||
`yield`가 있는 의존성에서 조기 종료가 필요한 다른 사용 사례가 있다면, 여러분의 구체적인 사용 사례와 `yield`가 있는 의존성에 대한 조기 종료가 어떤 점에서 이득이 되는지를 포함해 <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">GitHub Discussions 질문</a>을 생성해 주세요.
|
||||
`yield`가 있는 의존성에서 조기 종료가 필요한 다른 사용 사례가 있다면, 여러분의 구체적인 사용 사례와 `yield`가 있는 의존성에 대한 조기 종료가 어떤 점에서 이득이 되는지를 포함해 <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">GitHub Discussion Question</a>을 생성해 주세요.
|
||||
|
||||
`yield`가 있는 의존성에서 조기 종료에 대한 설득력 있는 사용 사례가 있다면, 조기 종료를 선택적으로 활성화할 수 있는 새로운 방법을 추가하는 것을 고려하겠습니다.
|
||||
|
||||
@@ -145,7 +145,7 @@ FastAPI 0.110.0 이전에는 `yield`가 있는 의존성을 사용한 다음 그
|
||||
|
||||
### 백그라운드 태스크와 `yield`가 있는 의존성, 기술 세부사항 { #background-tasks-and-dependencies-with-yield-technical-details }
|
||||
|
||||
FastAPI 0.106.0 이전에는 `yield` 이후에 예외를 발생시키는 것이 불가능했습니다. `yield`가 있는 의존성의 종료 코드는 응답이 전송된 *후에* 실행되었기 때문에, [예외 핸들러](../tutorial/handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}가 이미 실행된 뒤였습니다.
|
||||
FastAPI 0.106.0 이전에는 `yield` 이후에 예외를 발생시키는 것이 불가능했습니다. `yield`가 있는 의존성의 종료 코드는 응답이 전송된 *후에* 실행되었기 때문에, [Exception Handlers](../tutorial/handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}가 이미 실행된 뒤였습니다.
|
||||
|
||||
이는 주로 백그라운드 태스크 안에서 의존성이 "yield"한 동일한 객체들을 사용할 수 있게 하기 위한 설계였습니다. 백그라운드 태스크가 끝난 뒤에 종료 코드가 실행되었기 때문입니다.
|
||||
|
||||
|
||||
@@ -1,48 +1,32 @@
|
||||
# WSGI 포함하기 - Flask, Django 등 { #including-wsgi-flask-django-others }
|
||||
# WSGI 포함하기 - Flask, Django 그 외 { #including-wsgi-flask-django-others }
|
||||
|
||||
[서브 애플리케이션 - 마운트](sub-applications.md){.internal-link target=_blank}, [프록시 뒤에서](behind-a-proxy.md){.internal-link target=_blank}에서 본 것처럼 WSGI 애플리케이션을 마운트할 수 있습니다.
|
||||
[서브 응용 프로그램 - 마운트](sub-applications.md){.internal-link target=_blank}, [프록시 뒤편에서](behind-a-proxy.md){.internal-link target=_blank}에서 보았듯이 WSGI 응용 프로그램들을 마운트 할 수 있습니다.
|
||||
|
||||
이를 위해 `WSGIMiddleware`를 사용해 WSGI 애플리케이션(예: Flask, Django 등)을 감쌀 수 있습니다.
|
||||
이를 위해 `WSGIMiddleware`를 사용해 WSGI 응용 프로그램(예: Flask, Django 등)을 감쌀 수 있습니다.
|
||||
|
||||
## `WSGIMiddleware` 사용하기 { #using-wsgimiddleware }
|
||||
|
||||
/// info | 정보
|
||||
`WSGIMiddleware`를 불러와야 합니다.
|
||||
|
||||
이를 사용하려면 `a2wsgi`를 설치해야 합니다. 예: `pip install a2wsgi`
|
||||
그런 다음, WSGI(예: Flask) 응용 프로그램을 미들웨어로 포장합니다.
|
||||
|
||||
///
|
||||
그 후, 해당 경로에 마운트합니다.
|
||||
|
||||
`a2wsgi`에서 `WSGIMiddleware`를 import 해야 합니다.
|
||||
|
||||
그런 다음, WSGI(예: Flask) 애플리케이션을 미들웨어로 감쌉니다.
|
||||
|
||||
그리고 해당 경로에 마운트합니다.
|
||||
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[1,3,23] *}
|
||||
|
||||
/// note | 참고
|
||||
|
||||
이전에 `fastapi.middleware.wsgi`의 `WSGIMiddleware` 사용을 권장했지만 이제는 더 이상 권장되지 않습니다.
|
||||
|
||||
대신 `a2wsgi` 패키지 사용을 권장합니다. 사용 방법은 동일합니다.
|
||||
|
||||
단, `a2wsgi` 패키지가 설치되어 있고 `a2wsgi`에서 `WSGIMiddleware`를 올바르게 import 하는지만 확인하세요.
|
||||
|
||||
///
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[2:3,3] *}
|
||||
|
||||
## 확인하기 { #check-it }
|
||||
|
||||
이제 `/v1/` 경로에 있는 모든 요청은 Flask 애플리케이션에서 처리됩니다.
|
||||
이제 `/v1/` 경로에 있는 모든 요청은 Flask 응용 프로그램에서 처리됩니다.
|
||||
|
||||
그리고 나머지는 **FastAPI**에 의해 처리됩니다.
|
||||
|
||||
실행하고 <a href="http://localhost:8000/v1/" class="external-link" target="_blank">http://localhost:8000/v1/</a>로 이동하면 Flask의 응답을 볼 수 있습니다:
|
||||
실행하면 <a href="http://localhost:8000/v1/" class="external-link" target="_blank">http://localhost:8000/v1/</a>으로 이동해서 Flask의 응답을 볼 수 있습니다:
|
||||
|
||||
```txt
|
||||
Hello, World from Flask!
|
||||
```
|
||||
|
||||
그리고 <a href="http://localhost:8000/v2" class="external-link" target="_blank">http://localhost:8000/v2</a>로 이동하면 **FastAPI**의 응답을 볼 수 있습니다:
|
||||
그리고 다음으로 이동하면 <a href="http://localhost:8000/v2" class="external-link" target="_blank">http://localhost:8000/v2</a> **FastAPI**의 응답을 볼 수 있습니다:
|
||||
|
||||
```JSON
|
||||
{
|
||||
|
||||
@@ -145,6 +145,8 @@ Successfully installed fastapi pydantic
|
||||
* 다음 내용으로 `main.py` 파일을 만듭니다:
|
||||
|
||||
```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}
|
||||
```
|
||||
|
||||
@@ -243,14 +245,14 @@ Docker 지시어 <a href="https://docs.docker.com/reference/dockerfile/#cmd" cla
|
||||
✅ **Exec** form:
|
||||
|
||||
```Dockerfile
|
||||
# ✅ 이렇게 하세요
|
||||
# ✅ Do this
|
||||
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
|
||||
```
|
||||
|
||||
⛔️ **Shell** form:
|
||||
|
||||
```Dockerfile
|
||||
# ⛔️ 이렇게 하지 마세요
|
||||
# ⛔️ Don't do this
|
||||
CMD fastapi run app/main.py --port 80
|
||||
```
|
||||
|
||||
@@ -454,7 +456,7 @@ Traefik은 Docker, Kubernetes 등과 통합되어 있어, 이를 사용해 컨
|
||||
|
||||
## 복제 - 프로세스 개수 { #replication-number-of-processes }
|
||||
|
||||
**Kubernetes**, Docker Swarm Mode, Nomad 등의 복잡한 시스템으로 여러 머신에 분산된 컨테이너를 관리하는 <abbr title="어떤 방식으로 연결되어 함께 동작하도록 구성된 머신의 그룹">클러스터</abbr>를 사용한다면, 각 컨테이너에서(**워커를 사용하는 Uvicorn** 같은) **프로세스 매니저**를 쓰는 대신, **클러스터 레벨**에서 **복제를 처리**하고 싶을 가능성이 큽니다.
|
||||
**Kubernetes**, Docker Swarm Mode, Nomad 등의 복잡한 시스템으로 여러 머신에 분산된 컨테이너를 관리하는 <abbr title="A group of machines that are configured to be connected and work together in some way.">cluster</abbr>를 사용한다면, 각 컨테이너에서(**워커를 사용하는 Uvicorn** 같은) **프로세스 매니저**를 쓰는 대신, **클러스터 레벨**에서 **복제를 처리**하고 싶을 가능성이 큽니다.
|
||||
|
||||
Kubernetes 같은 분산 컨테이너 관리 시스템은 보통 들어오는 요청에 대한 **로드 밸런싱**을 지원하면서도, **컨테이너 복제**를 처리하는 통합된 방법을 가지고 있습니다. 모두 **클러스터 레벨**에서요.
|
||||
|
||||
@@ -578,7 +580,7 @@ Kubernetes를 사용한다면, 이는 아마도 <a href="https://kubernetes.io/d
|
||||
|
||||
그리고 여러 워커가 필요하다면, `--workers` 커맨드 라인 옵션을 간단히 사용하면 됩니다.
|
||||
|
||||
/// note | 기술 세부사항
|
||||
/// note Technical Details | 기술 세부사항
|
||||
|
||||
이 Docker 이미지는 Uvicorn이 죽은 워커를 관리하고 재시작하는 기능을 지원하지 않던 시기에 만들어졌습니다. 그래서 Gunicorn과 Uvicorn을 함께 사용해야 했고, Gunicorn이 Uvicorn 워커 프로세스를 관리하고 재시작하도록 하기 위해 상당한 복잡성이 추가되었습니다.
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ FastAPI는 현대적이고, 빠르며(고성능), 파이썬 표준 타입 힌트
|
||||
* **빠름**: (Starlette과 Pydantic 덕분에) **NodeJS** 및 **Go**와 대등할 정도로 매우 높은 성능. [사용 가능한 가장 빠른 파이썬 프레임워크 중 하나](#performance).
|
||||
* **빠른 코드 작성**: 약 200%에서 300%까지 기능 개발 속도 증가. *
|
||||
* **적은 버그**: 사람(개발자)에 의한 에러 약 40% 감소. *
|
||||
* **직관적**: 훌륭한 편집기 지원. 모든 곳에서 <abbr title="다른 말로는: auto-complete, autocompletion, IntelliSense">자동완성</abbr>. 적은 디버깅 시간.
|
||||
* **직관적**: 훌륭한 편집기 지원. 모든 곳에서 <abbr title="also known as auto-complete, autocompletion, IntelliSense">자동완성</abbr>. 적은 디버깅 시간.
|
||||
* **쉬움**: 쉽게 사용하고 배우도록 설계. 적은 문서 읽기 시간.
|
||||
* **짧음**: 코드 중복 최소화. 각 매개변수 선언의 여러 기능. 적은 버그.
|
||||
* **견고함**: 준비된 프로덕션 용 코드를 얻으십시오. 자동 대화형 문서와 함께.
|
||||
@@ -127,7 +127,7 @@ FastAPI는 현대적이고, 빠르며(고성능), 파이썬 표준 타입 힌트
|
||||
|
||||
<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>
|
||||
|
||||
웹 API 대신 터미널에서 사용할 <abbr title="Command Line Interface - 커맨드 라인 인터페이스">CLI</abbr> 앱을 만들고 있다면, <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>를 확인해 보십시오.
|
||||
웹 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**가 되기 위해 생겼습니다. ⌨️ 🚀
|
||||
|
||||
@@ -161,6 +161,8 @@ $ pip install "fastapi[standard]"
|
||||
다음 내용으로 `main.py` 파일을 만드십시오:
|
||||
|
||||
```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):
|
||||
|
||||
여러분의 코드가 `async` / `await`을 사용한다면, `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 @@ INFO: Application startup complete.
|
||||
|
||||
Pydantic 덕분에 표준 Python 타입을 사용해 본문을 선언합니다.
|
||||
|
||||
```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}
|
||||
|
||||
|
||||
@@ -368,7 +374,7 @@ item: Item
|
||||
* 데이터 검증:
|
||||
* 데이터가 유효하지 않을 때 자동으로 생성하는 명확한 에러.
|
||||
* 깊이 중첩된 JSON 객체에 대한 유효성 검사.
|
||||
* 입력 데이터 <abbr title="다른 말로는: serialization, parsing, marshalling">변환</abbr>: 네트워크에서 파이썬 데이터 및 타입으로 전송. 읽을 수 있는 것들:
|
||||
* 입력 데이터 <abbr title="also known as: serialization, parsing, marshalling">변환</abbr>: 네트워크에서 파이썬 데이터 및 타입으로 전송. 읽을 수 있는 것들:
|
||||
* JSON.
|
||||
* 경로 매개변수.
|
||||
* 쿼리 매개변수.
|
||||
@@ -376,7 +382,7 @@ item: Item
|
||||
* 헤더.
|
||||
* 폼(Forms).
|
||||
* 파일.
|
||||
* 출력 데이터 <abbr title="다른 말로는: serialization, parsing, marshalling">변환</abbr>: 파이썬 데이터 및 타입을 네트워크 데이터로 전환(JSON 형식으로):
|
||||
* 출력 데이터 <abbr title="also known as: serialization, parsing, marshalling">변환</abbr>: 파이썬 데이터 및 타입을 네트워크 데이터로 전환(JSON 형식으로):
|
||||
* 파이썬 타입 변환 (`str`, `int`, `float`, `bool`, `list`, 등).
|
||||
* `datetime` 객체.
|
||||
* `UUID` 객체.
|
||||
@@ -439,7 +445,7 @@ item: Item
|
||||
|
||||
* 서로 다른 장소에서 **매개변수** 선언: **헤더**, **쿠키**, **폼 필드** 그리고 **파일**.
|
||||
* `maximum_length` 또는 `regex`처럼 **유효성 제약**하는 방법.
|
||||
* 강력하고 사용하기 쉬운 **<abbr title="다른 말로는: components, resources, providers, services, injectables">의존성 주입</abbr>** 시스템.
|
||||
* 강력하고 사용하기 쉬운 **<abbr title="also known as components, resources, providers, services, injectables">의존성 주입</abbr>** 시스템.
|
||||
* **OAuth2** 지원을 포함한 **JWT tokens** 및 **HTTP Basic**을 갖는 보안과 인증.
|
||||
* (Pydantic 덕분에) **깊은 중첩 JSON 모델**을 선언하는데 더 진보한 (하지만 마찬가지로 쉬운) 기술.
|
||||
* <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> 및 기타 라이브러리와의 **GraphQL** 통합.
|
||||
|
||||
@@ -102,16 +102,15 @@
|
||||
|
||||
기본적으로 단일 값은 쿼리 매개변수로 해석되므로, 명시적으로 `Query`를 추가할 필요 없이 이렇게 하면 됩니다:
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
또는 Python 3.9에서는:
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
또는 Python 3.10 이상에서는:
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
예를 들어:
|
||||
|
||||
|
||||
@@ -52,11 +52,11 @@
|
||||
|
||||
`summary`와 `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 }
|
||||
|
||||
설명은 보통 길어지고 여러 줄에 걸쳐있기 때문에, *경로 처리* 설명을 함수 <abbr title="문서화에 사용되는 함수 내부 첫 표현식의 여러 줄 문자열(어떤 변수에도 할당되지 않음)">docstring</abbr>에 선언할 수 있으며, **FastAPI**는 그곳에서 이를 읽습니다.
|
||||
설명은 보통 길어지고 여러 줄에 걸쳐있기 때문에, *경로 처리* 설명을 함수 <abbr title="a multi-line string as the first expression inside a function (not assigned to any variable) used for documentation – 문서화에 사용되는 함수 내부 첫 표현식의 여러 줄 문자열(어떤 변수에도 할당되지 않음)">docstring</abbr>에 선언할 수 있으며, **FastAPI**는 그곳에서 이를 읽습니다.
|
||||
|
||||
독스트링에는 <a href="https://en.wikipedia.org/wiki/Markdown" class="external-link" target="_blank">Markdown</a>을 작성할 수 있으며, (독스트링의 들여쓰기를 고려하여) 올바르게 해석되고 표시됩니다.
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
|
||||
`response_description` 매개변수로 응답에 관한 설명을 명시할 수 있습니다:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[19] *}
|
||||
|
||||
/// info | 정보
|
||||
|
||||
@@ -90,7 +90,7 @@ OpenAPI는 각 *경로 처리*가 응답에 관한 설명을 요구할 것을
|
||||
|
||||
## *경로 처리* 지원중단하기 { #deprecate-a-path-operation }
|
||||
|
||||
*경로 처리*를 제거하지 않고 <abbr title="구식이며 사용하지 않는 것이 권장됨">deprecated</abbr>로 표시해야 한다면, `deprecated` 매개변수를 전달하면 됩니다:
|
||||
*경로 처리*를 제거하지 않고 <abbr title="obsolete, recommended not to use it – 구식이며 사용하지 않는 것이 권장됨">deprecated</abbr>로 표시해야 한다면, `deprecated` 매개변수를 전달하면 됩니다:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *}
|
||||
|
||||
|
||||
@@ -197,10 +197,15 @@ Aqui estão algumas coisas envolvidas em elementos HTML "abbr" (algumas são inv
|
||||
|
||||
### O abbr fornece uma frase completa { #the-abbr-gives-a-full-phrase }
|
||||
|
||||
* <abbr title="Getting Things Done – Fazer as Coisas">GTD</abbr>
|
||||
* <abbr title="less than – menos que"><code>lt</code></abbr>
|
||||
* <abbr title="XML Web Token – Token Web XML">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface – Interface de Gateway de Servidor Paralelo">PSGI</abbr>
|
||||
* <abbr title="Getting Things Done">GTD</abbr>
|
||||
* <abbr title="less than - menos que"><code>lt</code></abbr>
|
||||
* <abbr title="XML Web Token">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface - Interface de Gateway de Servidor Paralelo">PSGI</abbr>
|
||||
|
||||
### O abbr fornece uma explicação { #the-abbr-gives-an-explanation }
|
||||
|
||||
* <abbr title="Um grupo de máquinas configuradas para estarem conectadas e trabalharem juntas de alguma forma.">cluster</abbr>
|
||||
* <abbr title="Um método de aprendizado de máquina que usa redes neurais artificiais com numerosas camadas ocultas entre as camadas de entrada e saída, desenvolvendo assim uma estrutura interna abrangente">Deep Learning</abbr>
|
||||
|
||||
### O abbr fornece uma frase completa e uma explicação { #the-abbr-gives-a-full-phrase-and-an-explanation }
|
||||
|
||||
@@ -219,11 +224,6 @@ Veja a seção `### HTML abbr elements` no prompt geral em `scripts/translate.py
|
||||
|
||||
////
|
||||
|
||||
## Elementos HTML "dfn" { #html-dfn-elements }
|
||||
|
||||
* <dfn title="Um grupo de máquinas configuradas para estarem conectadas e trabalharem juntas de alguma forma.">cluster</dfn>
|
||||
* <dfn title="Um método de aprendizado de máquina que usa redes neurais artificiais com numerosas camadas ocultas entre as camadas de entrada e saída, desenvolvendo assim uma estrutura interna abrangente">Deep Learning</dfn>
|
||||
|
||||
## Títulos { #headings }
|
||||
|
||||
//// tab | Teste
|
||||
|
||||
@@ -148,7 +148,7 @@ Antes do FastAPI 0.106.0, lançar exceções após o `yield` não era possível,
|
||||
|
||||
Isso foi projetado assim principalmente para permitir o uso dos mesmos objetos "yielded" por dependências dentro de tarefas em segundo plano, porque o código de saída seria executado depois que as tarefas em segundo plano fossem concluídas.
|
||||
|
||||
Isso foi alterado no FastAPI 0.106.0 com a intenção de não manter recursos enquanto se espera a response percorrer a rede.
|
||||
Isso foi alterado no FastAPI 0.106.0 com a intenção de não manter recursos enquanto se espera a resposta percorrer a rede.
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
|
||||
@@ -6,29 +6,13 @@ Para isso, você pode utilizar o `WSGIMiddleware` para encapsular a sua aplicaç
|
||||
|
||||
## Usando `WSGIMiddleware` { #using-wsgimiddleware }
|
||||
|
||||
/// info | Informação
|
||||
|
||||
Isso requer instalar `a2wsgi`, por exemplo com `pip install a2wsgi`.
|
||||
|
||||
///
|
||||
|
||||
Você precisa importar o `WSGIMiddleware` de `a2wsgi`.
|
||||
Você precisa importar o `WSGIMiddleware`.
|
||||
|
||||
Em seguida, encapsule a aplicação WSGI (e.g. Flask) com o middleware.
|
||||
|
||||
E então monte isso sob um path.
|
||||
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[1,3,23] *}
|
||||
|
||||
/// note | Nota
|
||||
|
||||
Anteriormente, recomendava-se usar `WSGIMiddleware` de `fastapi.middleware.wsgi`, mas agora está descontinuado.
|
||||
|
||||
É aconselhável usar o pacote `a2wsgi` em seu lugar. O uso permanece o mesmo.
|
||||
|
||||
Apenas certifique-se de que o pacote `a2wsgi` está instalado e importe `WSGIMiddleware` corretamente de `a2wsgi`.
|
||||
|
||||
///
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[2:3,3] *}
|
||||
|
||||
## Confira { #check-it }
|
||||
|
||||
|
||||
@@ -145,6 +145,8 @@ Há outros formatos e ferramentas para definir e instalar dependências de pacot
|
||||
* Crie um arquivo `main.py` com:
|
||||
|
||||
```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 @@ Se você tiver uma configuração simples, com um **único contêiner** que ent
|
||||
|
||||
### Imagem Docker base { #base-docker-image }
|
||||
|
||||
Antes havia uma imagem oficial do FastAPI para Docker: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi-docker</a>. Mas agora ela está descontinuada. ⛔️
|
||||
Antes havia uma imagem oficial do FastAPI para Docker: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>. Mas agora ela está descontinuada. ⛔️
|
||||
|
||||
Você provavelmente **não** deve usar essa imagem base do Docker (ou qualquer outra semelhante).
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
---
|
||||
|
||||
FastAPI é um moderno e rápido (alta performance) framework web para construção de APIs com Python, baseado nos type hints padrões do Python.
|
||||
FastAPI é um moderno e rápido (alta performance) _framework web_ para construção de APIs com Python, baseado nos _type hints_ padrões do Python.
|
||||
|
||||
Os recursos chave são:
|
||||
|
||||
@@ -161,6 +161,8 @@ $ pip install "fastapi[standard]"
|
||||
Crie um arquivo `main.py` com:
|
||||
|
||||
```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):
|
||||
|
||||
Se seu código utiliza `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 @@ Agora modifique o arquivo `main.py` para receber um corpo de uma requisição `P
|
||||
|
||||
Declare o corpo utilizando tipos padrão Python, graças ao 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}
|
||||
|
||||
|
||||
@@ -405,7 +411,7 @@ Voltando ao código do exemplo anterior, **FastAPI** irá:
|
||||
* Documentar tudo com OpenAPI, que poderá ser usado por:
|
||||
* Sistemas de documentação interativos.
|
||||
* Sistemas de clientes de geração de código automáticos, para muitas linguagens.
|
||||
* Fornecer diretamente 2 interfaces web de documentação interativa.
|
||||
* Fornecer diretamente 2 interfaces _web_ de documentação interativa.
|
||||
|
||||
---
|
||||
|
||||
@@ -504,7 +510,7 @@ Siga os tutoriais do seu provedor de nuvem para implantar aplicações FastAPI c
|
||||
|
||||
## Performance { #performance }
|
||||
|
||||
Testes de performance da Independent TechEmpower mostram aplicações **FastAPI** rodando sob Uvicorn como <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">um dos frameworks Python mais rápidos disponíveis</a>, somente atrás de Starlette e Uvicorn (utilizados internamente pelo FastAPI). (*)
|
||||
Testes de performance da _Independent TechEmpower_ mostram aplicações **FastAPI** rodando sob Uvicorn como <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">um dos _frameworks_ Python mais rápidos disponíveis</a>, somente atrás de Starlette e Uvicorn (utilizados internamente pelo FastAPI). (*)
|
||||
|
||||
Para entender mais sobre isso, veja a seção <a href="https://fastapi.tiangolo.com/pt/benchmarks/" class="internal-link" target="_blank">Comparações</a>.
|
||||
|
||||
@@ -524,7 +530,7 @@ Utilizado pelo Starlette:
|
||||
|
||||
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Obrigatório caso você queira utilizar o `TestClient`.
|
||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Obrigatório se você quer utilizar a configuração padrão de templates.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Obrigatório se você deseja suporte a <abbr title="convertendo a string que vem de uma requisição HTTP em dados Python">"parsing"</abbr> de formulário, com `request.form()`.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Obrigatório se você deseja suporte a <abbr title="converting the string that comes from an HTTP request into Python data - convertendo a string que vem de uma requisição HTTP em dados Python">"parsing"</abbr> de formulário, com `request.form()`.
|
||||
|
||||
Utilizado pelo FastAPI:
|
||||
|
||||
|
||||
@@ -101,13 +101,13 @@ Obviamente, você também pode declarar parâmetros de consulta assim que você
|
||||
Dado que, por padrão, valores singulares são interpretados como parâmetros de consulta, você não precisa explicitamente adicionar uma `Query`, você pode somente:
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
Ou em Python 3.9:
|
||||
Ou como em Python 3.10 e versões superiores:
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
Por exemplo:
|
||||
|
||||
@@ -52,7 +52,7 @@ Nestes casos, pode fazer sentido armazenar as tags em um `Enum`.
|
||||
|
||||
Você pode adicionar um `summary` e uma `description`:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[18:19] *}
|
||||
|
||||
## Descrição do docstring { #description-from-docstring }
|
||||
|
||||
@@ -70,7 +70,7 @@ Ela será usada nas documentações interativas:
|
||||
|
||||
Você pode especificar a descrição da resposta com o 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 | Informação
|
||||
|
||||
|
||||
@@ -202,6 +202,11 @@ works(foo="bar") # Это работает 🎉
|
||||
* <abbr title="XML Web Token - XML веб‑токен">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface - Параллельный серверный интерфейс шлюза">PSGI</abbr>
|
||||
|
||||
### abbr даёт объяснение { #the-abbr-gives-an-explanation }
|
||||
|
||||
* <abbr title="Группа машин, которые настроены на соединение и совместную работу определённым образом.">кластер</abbr>
|
||||
* <abbr title="Метод машинного обучения, который использует искусственные нейронные сети с многочисленными скрытыми слоями между входным и выходным слоями, тем самым формируя сложную внутреннюю структуру">Глубокое обучение</abbr>
|
||||
|
||||
### abbr даёт полную расшифровку и объяснение { #the-abbr-gives-a-full-phrase-and-an-explanation }
|
||||
|
||||
* <abbr title="Mozilla Developer Network - Сеть разработчиков Mozilla: документация для разработчиков, созданная командой Firefox">MDN</abbr>
|
||||
@@ -219,11 +224,6 @@ works(foo="bar") # Это работает 🎉
|
||||
|
||||
////
|
||||
|
||||
## HTML-элементы "dfn" { #html-dfn-elements }
|
||||
|
||||
* <dfn title="Группа машин, которые настроены на соединение и совместную работу определённым образом.">кластер</dfn>
|
||||
* <dfn title="Метод машинного обучения, который использует искусственные нейронные сети с многочисленными скрытыми слоями между входным и выходным слоями, тем самым формируя сложную внутреннюю структуру">Глубокое обучение</dfn>
|
||||
|
||||
## Заголовки { #headings }
|
||||
|
||||
//// tab | Тест
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
checker(q="somequery")
|
||||
```
|
||||
|
||||
…и передаст возвращённое значение как значение зависимости в параметр `fixed_content_included` нашей *функции-обработчика пути*:
|
||||
…и передаст возвращённое значение как значение зависимости в нашу *функцию-обработчике пути* в параметр `fixed_content_included`:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[22] *}
|
||||
|
||||
|
||||
@@ -6,29 +6,13 @@
|
||||
|
||||
## Использование `WSGIMiddleware` { #using-wsgimiddleware }
|
||||
|
||||
/// info | Информация
|
||||
|
||||
Для этого требуется установить `a2wsgi`, например с помощью `pip install a2wsgi`.
|
||||
|
||||
///
|
||||
|
||||
Нужно импортировать `WSGIMiddleware` из `a2wsgi`.
|
||||
Нужно импортировать `WSGIMiddleware`.
|
||||
|
||||
Затем оберните WSGI‑приложение (например, Flask) в middleware (Промежуточный слой).
|
||||
|
||||
После этого смонтируйте его на путь.
|
||||
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[1,3,23] *}
|
||||
|
||||
/// note | Примечание
|
||||
|
||||
Ранее рекомендовалось использовать `WSGIMiddleware` из `fastapi.middleware.wsgi`, но теперь он помечен как устаревший.
|
||||
|
||||
Вместо него рекомендуется использовать пакет `a2wsgi`. Использование остаётся таким же.
|
||||
|
||||
Просто убедитесь, что пакет `a2wsgi` установлен, и импортируйте `WSGIMiddleware` из `a2wsgi`.
|
||||
|
||||
///
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[2:3,3] *}
|
||||
|
||||
## Проверьте { #check-it }
|
||||
|
||||
|
||||
@@ -145,6 +145,8 @@ Successfully installed fastapi pydantic
|
||||
* Создайте файл `main.py` со следующим содержимым:
|
||||
|
||||
```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]"
|
||||
Создайте файл `main.py` со следующим содержимым:
|
||||
|
||||
```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):
|
||||
|
||||
Если ваш код использует `async` / `await`, используйте `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 @@ INFO: Application startup complete.
|
||||
|
||||
Объявите тело запроса, используя стандартные типы Python, спасибо 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 @@
|
||||
Поскольку по умолчанию, отдельные значения интерпретируются как query-параметры, вам не нужно явно добавлять `Query`, вы можете просто сделать так:
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
Или в Python 3.9:
|
||||
Или в Python 3.10 и выше:
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
Например:
|
||||
@@ -116,7 +116,7 @@ q: Union[str, None] = None
|
||||
|
||||
/// info | Информация
|
||||
|
||||
`Body` также имеет все те же дополнительные параметры валидации и метаданных, как у `Query`, `Path` и других, которые вы увидите позже.
|
||||
`Body` также имеет все те же дополнительные параметры валидации и метаданных, как у `Query`,`Path` и других, которые вы увидите позже.
|
||||
|
||||
///
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
|
||||
Вы можете добавить параметры `summary` и `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 }
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
|
||||
Вы можете указать описание ответа с помощью параметра `response_description`:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[19] *}
|
||||
|
||||
/// info | Дополнительная информация
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
|
||||
///
|
||||
|
||||
/// check | Проверка
|
||||
/// check
|
||||
|
||||
OpenAPI указывает, что каждой *операции пути* необходимо описание ответа.
|
||||
|
||||
|
||||
@@ -1,503 +0,0 @@
|
||||
# LLM test dosyası { #llm-test-file }
|
||||
|
||||
Bu doküman, dokümantasyonu çeviren <abbr title="Large Language Model - Büyük Dil Modeli">LLM</abbr>'nin `scripts/translate.py` içindeki `general_prompt`'u ve `docs/{language code}/llm-prompt.md` içindeki dile özel prompt'u anlayıp anlamadığını test eder. Dile özel prompt, `general_prompt`'a eklenir.
|
||||
|
||||
Buraya eklenen testler, dile özel prompt'ları tasarlayan herkes tarafından görülecektir.
|
||||
|
||||
Şu şekilde kullanın:
|
||||
|
||||
* Dile özel bir prompt bulundurun: `docs/{language code}/llm-prompt.md`.
|
||||
* Bu dokümanın hedeflediğiniz dile sıfırdan yeni bir çevirisini yapın (örneğin `translate.py` içindeki `translate-page` komutu). Bu, çeviriyi `docs/{language code}/docs/_llm-test.md` altında oluşturur.
|
||||
* Çeviride her şeyin yolunda olup olmadığını kontrol edin.
|
||||
* Gerekirse dile özel prompt'u, genel prompt'u veya İngilizce dokümanı iyileştirin.
|
||||
* Ardından çeviride kalan sorunları elle düzeltin; böylece iyi bir çeviri elde edin.
|
||||
* İyi çeviri yerindeyken yeniden çeviri yapın. İdeal sonuç, LLM'nin artık çeviride hiçbir değişiklik yapmamasıdır. Bu da genel prompt'un ve dile özel prompt'un olabilecek en iyi hâle geldiği anlamına gelir (bazen rastgele gibi görünen birkaç değişiklik yapabilir; çünkü <a href="https://doublespeak.chat/#/handbook#deterministic-output" class="external-link" target="_blank">LLM'ler deterministik algoritmalar değildir</a>).
|
||||
|
||||
Testler:
|
||||
|
||||
## Code snippets { #code-snippets }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
Bu bir code snippet: `foo`. Bu da başka bir code snippet: `bar`. Bir tane daha: `baz quux`.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Bilgi
|
||||
|
||||
Code snippet'lerin içeriği olduğu gibi bırakılmalıdır.
|
||||
|
||||
`script/translate.py` içindeki genel prompt'ta `### Content of code snippets` bölümüne bakın.
|
||||
|
||||
////
|
||||
|
||||
## Alıntılar { #quotes }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
Dün bir arkadaşım şunu yazdı: "If you spell incorrectly correctly, you have spelled it incorrectly". Ben de şunu yanıtladım: "Correct, but 'incorrectly' is incorrectly not '"incorrectly"'".
|
||||
|
||||
/// note | Not
|
||||
|
||||
LLM muhtemelen bunu yanlış çevirecektir. Yeniden çeviri yapıldığında düzeltilmiş çeviriyi koruyup korumadığı önemlidir.
|
||||
|
||||
///
|
||||
|
||||
////
|
||||
|
||||
//// tab | Bilgi
|
||||
|
||||
Prompt tasarlayan kişi, düz tırnakları tipografik tırnaklara dönüştürüp dönüştürmemeyi seçebilir. Olduğu gibi bırakmak da uygundur.
|
||||
|
||||
Örneğin `docs/de/llm-prompt.md` içindeki `### Quotes` bölümüne bakın.
|
||||
|
||||
////
|
||||
|
||||
## Code snippet'lerde alıntılar { #quotes-in-code-snippets }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
`pip install "foo[bar]"`
|
||||
|
||||
Code snippet'lerde string literal örnekleri: `"this"`, `'that'`.
|
||||
|
||||
Code snippet'lerde string literal için zor bir örnek: `f"I like {'oranges' if orange else "apples"}"`
|
||||
|
||||
Hardcore: `Yesterday, my friend wrote: "If you spell incorrectly correctly, you have spelled it incorrectly". To which I answered: "Correct, but 'incorrectly' is incorrectly not '"incorrectly"'"`
|
||||
|
||||
////
|
||||
|
||||
//// tab | Bilgi
|
||||
|
||||
... Ancak code snippet'lerin içindeki tırnaklar olduğu gibi kalmalıdır.
|
||||
|
||||
////
|
||||
|
||||
## Code block'lar { #code-blocks }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
Bir Bash code örneği...
|
||||
|
||||
```bash
|
||||
# Evrene bir selam yazdır
|
||||
echo "Hello universe"
|
||||
```
|
||||
|
||||
...ve bir console code örneği...
|
||||
|
||||
```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 server
|
||||
Searching for package file structure
|
||||
```
|
||||
|
||||
...ve bir başka console code örneği...
|
||||
|
||||
```console
|
||||
// "Code" adında bir dizin oluştur
|
||||
$ mkdir code
|
||||
// O dizine geç
|
||||
$ cd code
|
||||
```
|
||||
|
||||
...ve bir Python code örneği...
|
||||
|
||||
```Python
|
||||
wont_work() # This won't work 😱
|
||||
works(foo="bar") # This works 🎉
|
||||
```
|
||||
|
||||
...ve hepsi bu.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Bilgi
|
||||
|
||||
Code block'ların içindeki code değiştirilmemelidir; tek istisna yorumlardır (comments).
|
||||
|
||||
`script/translate.py` içindeki genel prompt'ta `### Content of code blocks` bölümüne bakın.
|
||||
|
||||
////
|
||||
|
||||
## Sekmeler ve renkli kutular { #tabs-and-colored-boxes }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
/// info | Bilgi
|
||||
Some text
|
||||
///
|
||||
|
||||
/// note | Not
|
||||
Some text
|
||||
///
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
Some text
|
||||
///
|
||||
|
||||
/// check | Ek bilgi
|
||||
Some text
|
||||
///
|
||||
|
||||
/// tip | İpucu
|
||||
Some text
|
||||
///
|
||||
|
||||
/// warning | Uyarı
|
||||
Some text
|
||||
///
|
||||
|
||||
/// danger | Tehlike
|
||||
Some text
|
||||
///
|
||||
|
||||
////
|
||||
|
||||
//// tab | Bilgi
|
||||
|
||||
Sekmelerin ve `Info`/`Note`/`Warning`/vb. blokların başlığı, dikey çizgiden (`|`) sonra çeviri olarak eklenmelidir.
|
||||
|
||||
`script/translate.py` içindeki genel prompt'ta `### Special blocks` ve `### Tab blocks` bölümlerine bakın.
|
||||
|
||||
////
|
||||
|
||||
## Web ve internal link'ler { #web-and-internal-links }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
Link metni çevrilmelidir, link adresi değişmeden kalmalıdır:
|
||||
|
||||
* [Yukarıdaki başlığa link](#code-snippets)
|
||||
* [Internal link](index.md#installation){.internal-link target=_blank}
|
||||
* <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">External link</a>
|
||||
* <a href="https://fastapi.tiangolo.com/css/styles.css" class="external-link" target="_blank">Link to a style</a>
|
||||
* <a href="https://fastapi.tiangolo.com/js/logic.js" class="external-link" target="_blank">Link to a script</a>
|
||||
* <a href="https://fastapi.tiangolo.com/img/foo.jpg" class="external-link" target="_blank">Link to an image</a>
|
||||
|
||||
Link metni çevrilmelidir, link adresi çeviriye işaret etmelidir:
|
||||
|
||||
* <a href="https://fastapi.tiangolo.com/tr/" class="external-link" target="_blank">FastAPI link</a>
|
||||
|
||||
////
|
||||
|
||||
//// tab | Bilgi
|
||||
|
||||
Link'ler çevrilmelidir, ancak adresleri değişmeden kalmalıdır. Bir istisna, FastAPI dokümantasyonunun sayfalarına verilen mutlak link'lerdir. Bu durumda link, çeviriye işaret etmelidir.
|
||||
|
||||
`script/translate.py` içindeki genel prompt'ta `### Links` bölümüne bakın.
|
||||
|
||||
////
|
||||
|
||||
## HTML "abbr" öğeleri { #html-abbr-elements }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
Burada HTML "abbr" öğeleriyle sarılmış bazı şeyler var (bazıları uydurma):
|
||||
|
||||
### abbr tam bir ifade verir { #the-abbr-gives-a-full-phrase }
|
||||
|
||||
* <abbr title="Getting Things Done - İşleri Bitirme">GTD</abbr>
|
||||
* <abbr title="less than - küçüktür"><code>lt</code></abbr>
|
||||
* <abbr title="XML Web Token - XML Web Token">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface - Paralel Sunucu Gateway Interface">PSGI</abbr>
|
||||
|
||||
### abbr bir açıklama verir { #the-abbr-gives-an-explanation }
|
||||
|
||||
* <abbr title="Bir şekilde birbirine bağlanacak ve birlikte çalışacak şekilde yapılandırılmış makinelerden oluşan bir grup.">cluster</abbr>
|
||||
* <abbr title="Girdi ve çıktı katmanları arasında çok sayıda gizli katman içeren yapay sinir ağlarını kullanan; böylece kapsamlı bir iç yapı geliştiren bir machine learning yöntemi">Deep Learning</abbr>
|
||||
|
||||
### abbr tam bir ifade ve bir açıklama verir { #the-abbr-gives-a-full-phrase-and-an-explanation }
|
||||
|
||||
* <abbr title="Mozilla Developer Network - Mozilla Geliştirici Ağı: Firefox ekibi tarafından yazılmış, geliştiricilere yönelik dokümantasyon">MDN</abbr>
|
||||
* <abbr title="Input/Output - Girdi/Çıktı: disk okuma ya da yazma, ağ iletişimi.">I/O</abbr>.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Bilgi
|
||||
|
||||
"abbr" öğelerinin "title" attribute'ları belirli talimatlara göre çevrilir.
|
||||
|
||||
Çeviriler, LLM'nin kaldırmaması gereken kendi "abbr" öğelerini ekleyebilir. Örneğin İngilizce kelimeleri açıklamak için.
|
||||
|
||||
`script/translate.py` içindeki genel prompt'ta `### HTML abbr elements` bölümüne bakın.
|
||||
|
||||
////
|
||||
|
||||
## Başlıklar { #headings }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
### Bir web uygulaması geliştirin - bir öğretici { #develop-a-webapp-a-tutorial }
|
||||
|
||||
Merhaba.
|
||||
|
||||
### Type hint'ler ve -annotation'lar { #type-hints-and-annotations }
|
||||
|
||||
Tekrar merhaba.
|
||||
|
||||
### Super- ve subclass'lar { #super-and-subclasses }
|
||||
|
||||
Tekrar merhaba.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Bilgi
|
||||
|
||||
Başlıklarla ilgili tek katı kural, LLM'nin süslü parantezler içindeki hash kısmını değiştirmemesidir; böylece link'ler bozulmaz.
|
||||
|
||||
`script/translate.py` içindeki genel prompt'ta `### Headings` bölümüne bakın.
|
||||
|
||||
Dile özel bazı talimatlar için örneğin `docs/de/llm-prompt.md` içindeki `### Headings` bölümüne bakın.
|
||||
|
||||
////
|
||||
|
||||
## Dokümanlarda kullanılan terimler { #terms-used-in-the-docs }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
* siz
|
||||
* sizin
|
||||
|
||||
* örn.
|
||||
* vb.
|
||||
|
||||
* `foo` bir `int` olarak
|
||||
* `bar` bir `str` olarak
|
||||
* `baz` bir `list` olarak
|
||||
|
||||
* Tutorial - Kullanıcı kılavuzu
|
||||
* İleri Düzey Kullanıcı Kılavuzu
|
||||
* SQLModel dokümanları
|
||||
* API dokümanları
|
||||
* otomatik dokümanlar
|
||||
|
||||
* Veri Bilimi
|
||||
* Deep Learning
|
||||
* Machine Learning
|
||||
* Dependency Injection
|
||||
* HTTP Basic authentication
|
||||
* HTTP Digest
|
||||
* ISO formatı
|
||||
* JSON Schema standardı
|
||||
* JSON schema
|
||||
* schema tanımı
|
||||
* Password Flow
|
||||
* Mobil
|
||||
|
||||
* deprecated
|
||||
* designed
|
||||
* invalid
|
||||
* on the fly
|
||||
* standard
|
||||
* default
|
||||
* case-sensitive
|
||||
* case-insensitive
|
||||
|
||||
* uygulamayı serve etmek
|
||||
* sayfayı serve etmek
|
||||
|
||||
* app
|
||||
* application
|
||||
|
||||
* request
|
||||
* response
|
||||
* error response
|
||||
|
||||
* path operation
|
||||
* path operation decorator
|
||||
* path operation function
|
||||
|
||||
* body
|
||||
* request body
|
||||
* response body
|
||||
* JSON body
|
||||
* form body
|
||||
* file body
|
||||
* function body
|
||||
|
||||
* parameter
|
||||
* body parameter
|
||||
* path parameter
|
||||
* query parameter
|
||||
* cookie parameter
|
||||
* header parameter
|
||||
* form parameter
|
||||
* function parameter
|
||||
|
||||
* event
|
||||
* startup event
|
||||
* server'ın startup'ı
|
||||
* shutdown event
|
||||
* lifespan event
|
||||
|
||||
* handler
|
||||
* event handler
|
||||
* exception handler
|
||||
* handle etmek
|
||||
|
||||
* model
|
||||
* Pydantic model
|
||||
* data model
|
||||
* database model
|
||||
* form model
|
||||
* model object
|
||||
|
||||
* class
|
||||
* base class
|
||||
* parent class
|
||||
* subclass
|
||||
* child class
|
||||
* sibling class
|
||||
* class method
|
||||
|
||||
* header
|
||||
* headers
|
||||
* authorization header
|
||||
* `Authorization` header
|
||||
* forwarded header
|
||||
|
||||
* dependency injection system
|
||||
* dependency
|
||||
* dependable
|
||||
* dependant
|
||||
|
||||
* I/O bound
|
||||
* CPU bound
|
||||
* concurrency
|
||||
* parallelism
|
||||
* multiprocessing
|
||||
|
||||
* env var
|
||||
* environment variable
|
||||
* `PATH`
|
||||
* `PATH` variable
|
||||
|
||||
* authentication
|
||||
* authentication provider
|
||||
* authorization
|
||||
* authorization form
|
||||
* authorization provider
|
||||
* kullanıcı authenticate olur
|
||||
* sistem kullanıcıyı authenticate eder
|
||||
|
||||
* CLI
|
||||
* command line interface
|
||||
|
||||
* server
|
||||
* client
|
||||
|
||||
* cloud provider
|
||||
* cloud service
|
||||
|
||||
* geliştirme
|
||||
* geliştirme aşamaları
|
||||
|
||||
* dict
|
||||
* dictionary
|
||||
* enumeration
|
||||
* enum
|
||||
* enum member
|
||||
|
||||
* encoder
|
||||
* decoder
|
||||
* encode etmek
|
||||
* decode etmek
|
||||
|
||||
* exception
|
||||
* raise etmek
|
||||
|
||||
* expression
|
||||
* statement
|
||||
|
||||
* frontend
|
||||
* backend
|
||||
|
||||
* GitHub discussion
|
||||
* GitHub issue
|
||||
|
||||
* performance
|
||||
* performance optimization
|
||||
|
||||
* return type
|
||||
* return value
|
||||
|
||||
* security
|
||||
* security scheme
|
||||
|
||||
* task
|
||||
* background task
|
||||
* task function
|
||||
|
||||
* template
|
||||
* template engine
|
||||
|
||||
* type annotation
|
||||
* type hint
|
||||
|
||||
* server worker
|
||||
* Uvicorn worker
|
||||
* Gunicorn Worker
|
||||
* worker process
|
||||
* worker class
|
||||
* workload
|
||||
|
||||
* deployment
|
||||
* deploy etmek
|
||||
|
||||
* SDK
|
||||
* software development kit
|
||||
|
||||
* `APIRouter`
|
||||
* `requirements.txt`
|
||||
* Bearer Token
|
||||
* breaking change
|
||||
* bug
|
||||
* button
|
||||
* callable
|
||||
* code
|
||||
* commit
|
||||
* context manager
|
||||
* coroutine
|
||||
* database session
|
||||
* disk
|
||||
* domain
|
||||
* engine
|
||||
* fake X
|
||||
* HTTP GET method
|
||||
* item
|
||||
* library
|
||||
* lifespan
|
||||
* lock
|
||||
* middleware
|
||||
* mobile application
|
||||
* module
|
||||
* mounting
|
||||
* network
|
||||
* origin
|
||||
* override
|
||||
* payload
|
||||
* processor
|
||||
* property
|
||||
* proxy
|
||||
* pull request
|
||||
* query
|
||||
* RAM
|
||||
* remote machine
|
||||
* status code
|
||||
* string
|
||||
* tag
|
||||
* web framework
|
||||
* wildcard
|
||||
* return etmek
|
||||
* validate etmek
|
||||
|
||||
////
|
||||
|
||||
//// tab | Bilgi
|
||||
|
||||
Bu, dokümanlarda görülen (çoğunlukla) teknik terimlerin eksiksiz ve normatif olmayan bir listesidir. Prompt tasarlayan kişi için, LLM'nin hangi terimlerde desteğe ihtiyaç duyduğunu anlamada yardımcı olabilir. Örneğin iyi bir çeviriyi sürekli daha zayıf bir çeviriye geri alıyorsa. Ya da sizin dilinizde bir terimi çekimlemekte (conjugating/declinating) zorlanıyorsa.
|
||||
|
||||
Örneğin `docs/de/llm-prompt.md` içindeki `### List of English terms and their preferred German translations` bölümüne bakın.
|
||||
|
||||
////
|
||||
@@ -1,247 +0,0 @@
|
||||
# OpenAPI'de Ek Response'lar { #additional-responses-in-openapi }
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
Bu konu oldukça ileri seviye bir konudur.
|
||||
|
||||
**FastAPI**'ye yeni başlıyorsanız buna ihtiyaç duymayabilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
Ek status code'lar, media type'lar, açıklamalar vb. ile ek response'lar tanımlayabilirsiniz.
|
||||
|
||||
Bu ek response'lar OpenAPI şemasına dahil edilir; dolayısıyla API dokümanlarında da görünürler.
|
||||
|
||||
Ancak bu ek response'lar için, status code'unuzu ve içeriğinizi vererek `JSONResponse` gibi bir `Response`'u doğrudan döndürdüğünüzden emin olmanız gerekir.
|
||||
|
||||
## `model` ile Ek Response { #additional-response-with-model }
|
||||
|
||||
*Path operation decorator*'larınıza `responses` adlı bir parametre geçebilirsiniz.
|
||||
|
||||
Bu parametre bir `dict` alır: anahtarlar her response için status code'lardır (`200` gibi), değerler ise her birine ait bilgileri içeren başka `dict`'lerdir.
|
||||
|
||||
Bu response `dict`'lerinin her birinde, `response_model`'e benzer şekilde bir Pydantic model içeren `model` anahtarı olabilir.
|
||||
|
||||
**FastAPI** bu modeli alır, JSON Schema'sını üretir ve OpenAPI'de doğru yere ekler.
|
||||
|
||||
Örneğin, `404` status code'u ve `Message` Pydantic model'i ile başka bir response tanımlamak için şunu yazabilirsiniz:
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial001_py39.py hl[18,22] *}
|
||||
|
||||
/// note | Not
|
||||
|
||||
`JSONResponse`'u doğrudan döndürmeniz gerektiğini unutmayın.
|
||||
|
||||
///
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
`model` anahtarı OpenAPI'nin bir parçası değildir.
|
||||
|
||||
**FastAPI** buradaki Pydantic model'i alır, JSON Schema'yı üretir ve doğru yere yerleştirir.
|
||||
|
||||
Doğru yer şurasıdır:
|
||||
|
||||
* Değeri başka bir JSON nesnesi (`dict`) olan `content` anahtarının içinde:
|
||||
* Media type anahtarı (örn. `application/json`) bulunur; bunun değeri başka bir JSON nesnesidir ve onun içinde:
|
||||
* Değeri model'den gelen JSON Schema olan `schema` anahtarı vardır; doğru yer burasıdır.
|
||||
* **FastAPI** bunu doğrudan gömmek yerine OpenAPI'deki başka bir yerde bulunan global JSON Schema'lara bir referans ekler. Böylece diğer uygulamalar ve client'lar bu JSON Schema'ları doğrudan kullanabilir, daha iyi code generation araçları sağlayabilir, vb.
|
||||
|
||||
///
|
||||
|
||||
Bu *path operation* için OpenAPI'de üretilen response'lar şöyle olur:
|
||||
|
||||
```JSON hl_lines="3-12"
|
||||
{
|
||||
"responses": {
|
||||
"404": {
|
||||
"description": "Additional Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Message"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Item"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Schema'lar OpenAPI şemasının içinde başka bir yere referanslanır:
|
||||
|
||||
```JSON hl_lines="4-16"
|
||||
{
|
||||
"components": {
|
||||
"schemas": {
|
||||
"Message": {
|
||||
"title": "Message",
|
||||
"required": [
|
||||
"message"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"title": "Message",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Item": {
|
||||
"title": "Item",
|
||||
"required": [
|
||||
"id",
|
||||
"value"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"title": "Id",
|
||||
"type": "string"
|
||||
},
|
||||
"value": {
|
||||
"title": "Value",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ValidationError": {
|
||||
"title": "ValidationError",
|
||||
"required": [
|
||||
"loc",
|
||||
"msg",
|
||||
"type"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"msg": {
|
||||
"title": "Message",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"title": "Error Type",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"HTTPValidationError": {
|
||||
"title": "HTTPValidationError",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"detail": {
|
||||
"title": "Detail",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Ana Response İçin Ek Media Type'lar { #additional-media-types-for-the-main-response }
|
||||
|
||||
Aynı `responses` parametresini, aynı ana response için farklı media type'lar eklemek amacıyla da kullanabilirsiniz.
|
||||
|
||||
Örneğin, `image/png` için ek bir media type ekleyerek, *path operation*'ınızın bir JSON nesnesi (media type `application/json`) ya da bir PNG görseli döndürebildiğini belirtebilirsiniz:
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}
|
||||
|
||||
/// note | Not
|
||||
|
||||
Görseli `FileResponse` kullanarak doğrudan döndürmeniz gerektiğine dikkat edin.
|
||||
|
||||
///
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
`responses` parametrenizde açıkça farklı bir media type belirtmediğiniz sürece FastAPI, response'un ana response class'ı ile aynı media type'a sahip olduğunu varsayar (varsayılan `application/json`).
|
||||
|
||||
Ancak media type'ı `None` olan özel bir response class belirttiyseniz, FastAPI ilişkili bir model'i olan tüm ek response'lar için `application/json` kullanır.
|
||||
|
||||
///
|
||||
|
||||
## Bilgileri Birleştirme { #combining-information }
|
||||
|
||||
`response_model`, `status_code` ve `responses` parametreleri dahil olmak üzere, response bilgilerini birden fazla yerden birleştirebilirsiniz.
|
||||
|
||||
Varsayılan `200` status code'unu (ya da gerekiyorsa özel bir tane) kullanarak bir `response_model` tanımlayabilir, ardından aynı response için ek bilgileri `responses` içinde, doğrudan OpenAPI şemasına ekleyebilirsiniz.
|
||||
|
||||
**FastAPI**, `responses` içindeki ek bilgileri korur ve model'inizin JSON Schema'sı ile birleştirir.
|
||||
|
||||
Örneğin, Pydantic model kullanan ve özel bir `description` içeren `404` status code'lu bir response tanımlayabilirsiniz.
|
||||
|
||||
Ayrıca `response_model`'inizi kullanan, ancak özel bir `example` içeren `200` status code'lu bir response da tanımlayabilirsiniz:
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial003_py39.py hl[20:31] *}
|
||||
|
||||
Bunların hepsi OpenAPI'nize birleştirilerek dahil edilir ve API dokümanlarında gösterilir:
|
||||
|
||||
<img src="/img/tutorial/additional-responses/image01.png">
|
||||
|
||||
## Ön Tanımlı Response'ları Özel Olanlarla Birleştirme { #combine-predefined-responses-and-custom-ones }
|
||||
|
||||
Birçok *path operation* için geçerli olacak bazı ön tanımlı response'larınız olabilir; ancak bunları her *path operation*'ın ihtiyaç duyduğu özel response'larla birleştirmek isteyebilirsiniz.
|
||||
|
||||
Bu durumlarda, Python'daki bir `dict`'i `**dict_to_unpack` ile "unpacking" tekniğini kullanabilirsiniz:
|
||||
|
||||
```Python
|
||||
old_dict = {
|
||||
"old key": "old value",
|
||||
"second old key": "second old value",
|
||||
}
|
||||
new_dict = {**old_dict, "new key": "new value"}
|
||||
```
|
||||
|
||||
Burada `new_dict`, `old_dict` içindeki tüm key-value çiftlerini ve buna ek olarak yeni key-value çiftini içerir:
|
||||
|
||||
```Python
|
||||
{
|
||||
"old key": "old value",
|
||||
"second old key": "second old value",
|
||||
"new key": "new value",
|
||||
}
|
||||
```
|
||||
|
||||
Bu tekniği, *path operation*'larınızda bazı ön tanımlı response'ları yeniden kullanmak ve bunları ek özel response'larla birleştirmek için kullanabilirsiniz.
|
||||
|
||||
Örneğin:
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}
|
||||
|
||||
## OpenAPI Response'ları Hakkında Daha Fazla Bilgi { #more-information-about-openapi-responses }
|
||||
|
||||
Response'ların içine tam olarak neleri dahil edebileceğinizi görmek için OpenAPI spesifikasyonundaki şu bölümlere bakabilirsiniz:
|
||||
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object" class="external-link" target="_blank">OpenAPI Responses Object</a>, `Response Object`'i içerir.
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object" class="external-link" target="_blank">OpenAPI Response Object</a>, buradaki her şeyi `responses` parametreniz içinde, her bir response'un içine doğrudan ekleyebilirsiniz. Buna `description`, `headers`, `content` (bunun içinde farklı media type'lar ve JSON Schema'lar tanımlarsınız) ve `links` dahildir.
|
||||
@@ -1,41 +0,0 @@
|
||||
# Ek Status Code'ları { #additional-status-codes }
|
||||
|
||||
Varsayılan olarak **FastAPI**, response'ları bir `JSONResponse` kullanarak döndürür; *path operation*'ınızdan döndürdüğünüz içeriği bu `JSONResponse`'un içine yerleştirir.
|
||||
|
||||
Varsayılan status code'u veya *path operation* içinde sizin belirlediğiniz status code'u kullanır.
|
||||
|
||||
## Ek status code'ları { #additional-status-codes_1 }
|
||||
|
||||
Ana status code'a ek olarak başka status code'lar da döndürmek istiyorsanız, `JSONResponse` gibi bir `Response`'u doğrudan döndürerek bunu yapabilirsiniz ve ek status code'u doğrudan orada ayarlarsınız.
|
||||
|
||||
Örneğin, item'ları güncellemeye izin veren bir *path operation*'ınız olduğunu düşünelim; başarılı olduğunda 200 "OK" HTTP status code'unu döndürüyor olsun.
|
||||
|
||||
Ancak yeni item'ları da kabul etmesini istiyorsunuz. Ve item daha önce yoksa, onu oluşturup 201 "Created" HTTP status code'unu döndürsün.
|
||||
|
||||
Bunu yapmak için `JSONResponse` import edin ve içeriğinizi doğrudan onunla döndürün; istediğiniz `status_code`'u da ayarlayın:
|
||||
|
||||
{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
Yukarıdaki örnekte olduğu gibi bir `Response`'u doğrudan döndürdüğünüzde, response aynen olduğu gibi döndürülür.
|
||||
|
||||
Bir model ile serialize edilmez, vb.
|
||||
|
||||
İçinde olmasını istediğiniz veriyi taşıdığından emin olun ve değerlerin geçerli JSON olduğundan emin olun (eğer `JSONResponse` kullanıyorsanız).
|
||||
|
||||
///
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
`from starlette.responses import JSONResponse` da kullanabilirsiniz.
|
||||
|
||||
**FastAPI**, geliştirici olarak size kolaylık olsun diye `starlette.responses` içindekileri `fastapi.responses` altında da sunar. Ancak mevcut response'ların çoğu doğrudan Starlette'ten gelir. `status` için de aynı durum geçerlidir.
|
||||
|
||||
///
|
||||
|
||||
## OpenAPI ve API docs { #openapi-and-api-docs }
|
||||
|
||||
Ek status code'ları ve response'ları doğrudan döndürürseniz, FastAPI sizin ne döndüreceğinizi önceden bilemeyeceği için bunlar OpenAPI şemasına (API docs) dahil edilmez.
|
||||
|
||||
Ancak bunu kodunuzda şu şekilde dokümante edebilirsiniz: [Ek Response'lar](additional-responses.md){.internal-link target=_blank}.
|
||||
@@ -1,163 +0,0 @@
|
||||
# Gelişmiş Dependency'ler { #advanced-dependencies }
|
||||
|
||||
## Parametreli dependency'ler { #parameterized-dependencies }
|
||||
|
||||
Şimdiye kadar gördüğümüz tüm dependency'ler sabit bir function ya da class idi.
|
||||
|
||||
Ancak, birçok farklı function veya class tanımlamak zorunda kalmadan, dependency üzerinde bazı parametreler ayarlamak isteyebileceğiniz durumlar olabilir.
|
||||
|
||||
Örneğin, query parametresi `q`'nun belirli bir sabit içeriği barındırıp barındırmadığını kontrol eden bir dependency istediğimizi düşünelim.
|
||||
|
||||
Ama bu sabit içeriği parametreleştirebilmek istiyoruz.
|
||||
|
||||
## "Callable" bir instance { #a-callable-instance }
|
||||
|
||||
Python'da bir class'ın instance'ını "callable" yapmanın bir yolu vardır.
|
||||
|
||||
Class'ın kendisini değil (zaten callable'dır), o class'ın bir instance'ını.
|
||||
|
||||
Bunu yapmak için `__call__` adında bir method tanımlarız:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[12] *}
|
||||
|
||||
Bu durumda, ek parametreleri ve alt-dependency'leri kontrol etmek için **FastAPI**'nin kullanacağı şey bu `__call__` olacaktır; ayrıca daha sonra *path operation function* içindeki parametreye bir değer geçmek için çağrılacak olan da budur.
|
||||
|
||||
## Instance'ı parametreleştirme { #parameterize-the-instance }
|
||||
|
||||
Ve şimdi, dependency'yi "parametreleştirmek" için kullanacağımız instance parametrelerini tanımlamak üzere `__init__` kullanabiliriz:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[9] *}
|
||||
|
||||
Bu durumda **FastAPI**, `__init__` ile asla uğraşmaz veya onu önemsemez; onu doğrudan kendi kodumuzda kullanırız.
|
||||
|
||||
## Bir instance oluşturma { #create-an-instance }
|
||||
|
||||
Bu class'tan bir instance'ı şöyle oluşturabiliriz:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[18] *}
|
||||
|
||||
Böylece dependency'mizi "parametreleştirmiş" oluruz; artık içinde `"bar"` vardır ve bu değer `checker.fixed_content` attribute'u olarak durur.
|
||||
|
||||
## Instance'ı dependency olarak kullanma { #use-the-instance-as-a-dependency }
|
||||
|
||||
Sonra `Depends(FixedContentQueryChecker)` yerine `Depends(checker)` içinde bu `checker`'ı kullanabiliriz. Çünkü dependency, class'ın kendisi değil, `checker` instance'ıdır.
|
||||
|
||||
Ve dependency çözülürken **FastAPI** bu `checker`'ı şöyle çağırır:
|
||||
|
||||
```Python
|
||||
checker(q="somequery")
|
||||
```
|
||||
|
||||
...ve bunun döndürdüğü her şeyi, *path operation function* içinde `fixed_content_included` parametresine dependency değeri olarak geçirir:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[22] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bunların tamamı biraz yapay görünebilir. Ayrıca bunun nasıl faydalı olduğu da henüz çok net olmayabilir.
|
||||
|
||||
Bu örnekler bilerek basit tutuldu; ama mekanizmanın nasıl çalıştığını gösteriyor.
|
||||
|
||||
Security bölümlerinde, aynı şekilde implement edilmiş yardımcı function'lar bulunuyor.
|
||||
|
||||
Buradaki her şeyi anladıysanız, security için kullanılan bu yardımcı araçların arka planda nasıl çalıştığını da zaten biliyorsunuz demektir.
|
||||
|
||||
///
|
||||
|
||||
## `yield`, `HTTPException`, `except` ve Background Tasks ile Dependency'ler { #dependencies-with-yield-httpexception-except-and-background-tasks }
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
Büyük ihtimalle bu teknik detaylara ihtiyacınız yok.
|
||||
|
||||
Bu detaylar, özellikle 0.121.0'dan eski bir FastAPI uygulamanız varsa ve `yield` kullanan dependency'lerle ilgili sorunlar yaşıyorsanız faydalıdır.
|
||||
|
||||
///
|
||||
|
||||
`yield` kullanan dependency'ler; farklı kullanım senaryolarını kapsamak ve bazı sorunları düzeltmek için zaman içinde evrildi. Aşağıda nelerin değiştiğinin bir özeti var.
|
||||
|
||||
### `yield` ve `scope` ile dependency'ler { #dependencies-with-yield-and-scope }
|
||||
|
||||
0.121.0 sürümünde FastAPI, `Depends(scope="function")` desteğini ekledi.
|
||||
|
||||
`Depends(scope="function")` kullanıldığında, `yield` sonrasındaki çıkış kodu, *path operation function* biter bitmez, response client'a geri gönderilmeden önce çalıştırılır.
|
||||
|
||||
`Depends(scope="request")` (varsayılan) kullanıldığında ise `yield` sonrasındaki çıkış kodu, response gönderildikten sonra çalıştırılır.
|
||||
|
||||
Daha fazlasını [`yield` ile Dependency'ler - Erken çıkış ve `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope) dokümantasyonunda okuyabilirsiniz.
|
||||
|
||||
### `yield` ve `StreamingResponse` ile dependency'ler, Teknik Detaylar { #dependencies-with-yield-and-streamingresponse-technical-details }
|
||||
|
||||
FastAPI 0.118.0 öncesinde, `yield` kullanan bir dependency kullanırsanız, *path operation function* döndükten sonra ama response gönderilmeden hemen önce `yield` sonrasındaki çıkış kodu çalıştırılırdı.
|
||||
|
||||
Amaç, response'un ağ üzerinden taşınmasını beklerken gereğinden uzun süre resource tutmaktan kaçınmaktı.
|
||||
|
||||
Bu değişiklik aynı zamanda şunu da ifade ediyordu: `StreamingResponse` döndürürseniz, `yield` kullanan dependency'nin çıkış kodu zaten çalışmış olurdu.
|
||||
|
||||
Örneğin, `yield` kullanan bir dependency içinde bir veritabanı session'ınız varsa, `StreamingResponse` veri stream ederken bu session'ı kullanamazdı; çünkü `yield` sonrasındaki çıkış kodunda session zaten kapatılmış olurdu.
|
||||
|
||||
Bu davranış 0.118.0'da geri alındı ve `yield` sonrasındaki çıkış kodunun, response gönderildikten sonra çalıştırılması sağlandı.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Aşağıda göreceğiniz gibi, bu davranış 0.106.0 sürümünden önceki davranışa oldukça benzer; ancak köşe durumlar için çeşitli iyileştirmeler ve bug fix'ler içerir.
|
||||
|
||||
///
|
||||
|
||||
#### Erken Çıkış Kodu için Kullanım Senaryoları { #use-cases-with-early-exit-code }
|
||||
|
||||
Bazı özel koşullardaki kullanım senaryoları, response gönderilmeden önce `yield` kullanan dependency'lerin çıkış kodunun çalıştırıldığı eski davranıştan fayda görebilir.
|
||||
|
||||
Örneğin, `yield` kullanan bir dependency içinde yalnızca bir kullanıcıyı doğrulamak için veritabanı session'ı kullanan bir kodunuz olduğunu düşünün; ama bu session *path operation function* içinde bir daha hiç kullanılmıyor, yalnızca dependency içinde kullanılıyor **ve** response'un gönderilmesi uzun sürüyor. Mesela veriyi yavaş gönderen bir `StreamingResponse` var, ama herhangi bir nedenle veritabanını kullanmıyor.
|
||||
|
||||
Bu durumda veritabanı session'ı, response tamamen gönderilene kadar elde tutulur. Ancak session kullanılmıyorsa, bunu elde tutmak gerekli değildir.
|
||||
|
||||
Şöyle görünebilir:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial013_an_py310.py *}
|
||||
|
||||
`Session`'ın otomatik kapatılması olan çıkış kodu şurada:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}
|
||||
|
||||
...yavaş veri gönderen response'un gönderimi bittikten sonra çalıştırılır:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}
|
||||
|
||||
Ama `generate_stream()` veritabanı session'ını kullanmadığı için, response gönderilirken session'ı açık tutmak aslında gerekli değildir.
|
||||
|
||||
SQLModel (veya SQLAlchemy) kullanarak bu spesifik senaryoya sahipseniz, session'a artık ihtiyacınız kalmadıktan sonra session'ı açıkça kapatabilirsiniz:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}
|
||||
|
||||
Böylece session veritabanı bağlantısını serbest bırakır ve diğer request'ler bunu kullanabilir.
|
||||
|
||||
`yield` kullanan bir dependency'den erken çıkış gerektiren farklı bir kullanım senaryonuz varsa, lütfen kullanım senaryonuzla birlikte ve `yield` kullanan dependency'ler için erken kapatmadan neden fayda göreceğinizi açıklayarak bir <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">GitHub Discussion Sorusu</a> oluşturun.
|
||||
|
||||
`yield` kullanan dependency'lerde erken kapatma için ikna edici kullanım senaryoları varsa, erken kapatmayı seçmeli (opt-in) hale getiren yeni bir yöntem eklemeyi düşünebilirim.
|
||||
|
||||
### `yield` ve `except` ile dependency'ler, Teknik Detaylar { #dependencies-with-yield-and-except-technical-details }
|
||||
|
||||
FastAPI 0.110.0 öncesinde, `yield` kullanan bir dependency kullanır, sonra o dependency içinde `except` ile bir exception yakalar ve exception'ı tekrar raise etmezseniz; exception otomatik olarak herhangi bir exception handler'a veya internal server error handler'a raise/forward edilirdi.
|
||||
|
||||
Bu davranış 0.110.0 sürümünde değiştirildi. Amaç, handler olmayan (internal server errors) forward edilmiş exception'ların yönetilmemesinden kaynaklanan bellek tüketimini düzeltmek ve bunu normal Python kodunun davranışıyla tutarlı hale getirmekti.
|
||||
|
||||
### Background Tasks ve `yield` ile dependency'ler, Teknik Detaylar { #background-tasks-and-dependencies-with-yield-technical-details }
|
||||
|
||||
FastAPI 0.106.0 öncesinde, `yield` sonrasında exception raise etmek mümkün değildi; çünkü `yield` kullanan dependency'lerdeki çıkış kodu response gönderildikten *sonra* çalıştırılıyordu. Bu nedenle [Exception Handler'ları](../tutorial/handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} zaten çalışmış olurdu.
|
||||
|
||||
Bu tasarımın ana sebeplerinden biri, background task'lerin içinde dependency'lerin "yield ettiği" aynı objeleri kullanmaya izin vermekti; çünkü çıkış kodu, background task'ler bittikten sonra çalıştırılıyordu.
|
||||
|
||||
Bu davranış FastAPI 0.106.0'da, response'un ağ üzerinde taşınmasını beklerken resource tutmamak amacıyla değiştirildi.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Ek olarak, bir background task normalde ayrı ele alınması gereken bağımsız bir mantık setidir ve kendi resource'larına sahip olmalıdır (ör. kendi veritabanı bağlantısı).
|
||||
|
||||
Bu şekilde muhtemelen daha temiz bir kod elde edersiniz.
|
||||
|
||||
///
|
||||
|
||||
Bu davranışa güvenerek kod yazdıysanız, artık background task'ler için resource'ları background task'in içinde oluşturmalı ve içeride yalnızca `yield` kullanan dependency'lerin resource'larına bağlı olmayan verileri kullanmalısınız.
|
||||
|
||||
Örneğin, aynı veritabanı session'ını kullanmak yerine background task içinde yeni bir veritabanı session'ı oluşturur ve veritabanındaki objeleri bu yeni session ile alırsınız. Ardından, background task function'ına veritabanından gelen objeyi parametre olarak geçirmek yerine, o objenin ID'sini geçirir ve objeyi background task function'ı içinde yeniden elde edersiniz.
|
||||
@@ -1,99 +0,0 @@
|
||||
# Async Testler { #async-tests }
|
||||
|
||||
Sağlanan `TestClient` ile **FastAPI** uygulamalarınızı nasıl test edeceğinizi zaten gördünüz. Şimdiye kadar yalnızca senkron testler yazdık, yani `async` fonksiyonlar kullanmadan.
|
||||
|
||||
Testlerinizde asenkron fonksiyonlar kullanabilmek faydalı olabilir; örneğin veritabanınızı asenkron olarak sorguluyorsanız. Diyelim ki FastAPI uygulamanıza request gönderilmesini test etmek ve ardından async bir veritabanı kütüphanesi kullanırken backend'in doğru veriyi veritabanına başarıyla yazdığını doğrulamak istiyorsunuz.
|
||||
|
||||
Bunu nasıl çalıştırabileceğimize bir bakalım.
|
||||
|
||||
## pytest.mark.anyio { #pytest-mark-anyio }
|
||||
|
||||
Testlerimizde asenkron fonksiyonlar çağırmak istiyorsak, test fonksiyonlarımızın da asenkron olması gerekir. AnyIO bunun için güzel bir plugin sağlar; böylece bazı test fonksiyonlarının asenkron olarak çağrılacağını belirtebiliriz.
|
||||
|
||||
## HTTPX { #httpx }
|
||||
|
||||
**FastAPI** uygulamanız `async def` yerine normal `def` fonksiyonları kullanıyor olsa bile, altta yatan yapı hâlâ bir `async` uygulamadır.
|
||||
|
||||
`TestClient`, standart pytest kullanarak normal `def` test fonksiyonlarınızın içinden asenkron FastAPI uygulamasını çağırmak için içeride bazı “sihirli” işlemler yapar. Ancak bu sihir, onu asenkron fonksiyonların içinde kullandığımızda artık çalışmaz. Testlerimizi asenkron çalıştırdığımızda, test fonksiyonlarımızın içinde `TestClient` kullanamayız.
|
||||
|
||||
`TestClient`, <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a> tabanlıdır ve neyse ki API'yi test etmek için HTTPX'i doğrudan kullanabiliriz.
|
||||
|
||||
## Örnek { #example }
|
||||
|
||||
Basit bir örnek için, [Bigger Applications](../tutorial/bigger-applications.md){.internal-link target=_blank} ve [Testing](../tutorial/testing.md){.internal-link target=_blank} bölümlerinde anlatılana benzer bir dosya yapısı düşünelim:
|
||||
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py
|
||||
│ └── test_main.py
|
||||
```
|
||||
|
||||
`main.py` dosyası şöyle olur:
|
||||
|
||||
{* ../../docs_src/async_tests/app_a_py39/main.py *}
|
||||
|
||||
`test_main.py` dosyasında `main.py` için testler yer alır, artık şöyle görünebilir:
|
||||
|
||||
{* ../../docs_src/async_tests/app_a_py39/test_main.py *}
|
||||
|
||||
## Çalıştırma { #run-it }
|
||||
|
||||
Testlerinizi her zamanki gibi şu şekilde çalıştırabilirsiniz:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pytest
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Detaylı Anlatım { #in-detail }
|
||||
|
||||
`@pytest.mark.anyio` marker'ı, pytest'e bu test fonksiyonunun asenkron olarak çağrılması gerektiğini söyler:
|
||||
|
||||
{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[7] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Test fonksiyonu artık `TestClient` kullanırken eskiden olduğu gibi sadece `def` değil, `async def`.
|
||||
|
||||
///
|
||||
|
||||
Ardından app ile bir `AsyncClient` oluşturup `await` kullanarak ona async request'ler gönderebiliriz.
|
||||
|
||||
{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[9:12] *}
|
||||
|
||||
Bu, şu kullanıma denktir:
|
||||
|
||||
```Python
|
||||
response = client.get('/')
|
||||
```
|
||||
|
||||
...ki daha önce request'leri `TestClient` ile bu şekilde gönderiyorduk.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Yeni `AsyncClient` ile async/await kullandığımızı unutmayın; request asenkron çalışır.
|
||||
|
||||
///
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
Uygulamanız lifespan event'lerine dayanıyorsa, `AsyncClient` bu event'leri tetiklemez. Tetiklendiklerinden emin olmak için <a href="https://github.com/florimondmanca/asgi-lifespan#usage" class="external-link" target="_blank">florimondmanca/asgi-lifespan</a> paketindeki `LifespanManager`'ı kullanın.
|
||||
|
||||
///
|
||||
|
||||
## Diğer Asenkron Fonksiyon Çağrıları { #other-asynchronous-function-calls }
|
||||
|
||||
Test fonksiyonu artık asenkron olduğundan, testlerinizde FastAPI uygulamanıza request göndermenin yanında başka `async` fonksiyonları da (çağırıp `await` ederek) kodunuzun başka yerlerinde yaptığınız gibi aynı şekilde kullanabilirsiniz.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Testlerinize asenkron fonksiyon çağrıları entegre ederken `RuntimeError: Task attached to a different loop` hatasıyla karşılaşırsanız (ör. <a href="https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop" class="external-link" target="_blank">MongoDB'nin MotorClient</a> kullanımı), event loop gerektiren nesneleri yalnızca async fonksiyonların içinde oluşturmanız gerektiğini unutmayın; örneğin bir `@app.on_event("startup")` callback'i içinde.
|
||||
|
||||
///
|
||||
@@ -1,466 +0,0 @@
|
||||
# Proxy Arkasında Çalıştırma { #behind-a-proxy }
|
||||
|
||||
Birçok durumda, FastAPI uygulamanızın önünde Traefik veya Nginx gibi bir **proxy** kullanırsınız.
|
||||
|
||||
Bu proxy'ler HTTPS sertifikalarını ve diğer bazı işleri üstlenebilir.
|
||||
|
||||
## Proxy Forwarded Header'ları { #proxy-forwarded-headers }
|
||||
|
||||
Uygulamanızın önündeki bir **proxy**, request'leri **server**'ınıza göndermeden önce genelde bazı header'ları dinamik olarak ayarlar. Böylece server, request'in proxy tarafından **forward** edildiğini; domain dahil orijinal (public) URL'yi, HTTPS kullanıldığını vb. bilgileri anlayabilir.
|
||||
|
||||
**Server** programı (örneğin **FastAPI CLI** üzerinden **Uvicorn**) bu header'ları yorumlayabilir ve ardından bu bilgiyi uygulamanıza aktarabilir.
|
||||
|
||||
Ancak güvenlik nedeniyle, server güvenilir bir proxy arkasında olduğunu bilmediği için bu header'ları yorumlamaz.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
Proxy header'ları şunlardır:
|
||||
|
||||
* <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>
|
||||
|
||||
///
|
||||
|
||||
### Proxy Forwarded Header'larını Etkinleştirme { #enable-proxy-forwarded-headers }
|
||||
|
||||
FastAPI CLI'yi `--forwarded-allow-ips` *CLI Option*'ı ile başlatıp, bu forwarded header'ları okumada güvenilecek IP adreslerini verebilirsiniz.
|
||||
|
||||
Bunu `--forwarded-allow-ips="*"` olarak ayarlarsanız, gelen tüm IP'lere güvenir.
|
||||
|
||||
**Server**'ınız güvenilir bir **proxy** arkasındaysa ve onunla sadece proxy konuşuyorsa, bu ayar server'ın o **proxy**'nin IP'si her neyse onu kabul etmesini sağlar.
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi run --forwarded-allow-ips="*"
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### HTTPS ile Redirect'ler { #redirects-with-https }
|
||||
|
||||
Örneğin `/items/` adında bir *path operation* tanımladığınızı düşünelim:
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial001_01_py39.py hl[6] *}
|
||||
|
||||
Client `/items`'a gitmeye çalışırsa, varsayılan olarak `/items/`'a redirect edilir.
|
||||
|
||||
Ancak *CLI Option* `--forwarded-allow-ips` ayarlanmadan önce, `http://localhost:8000/items/`'a redirect edebilir.
|
||||
|
||||
Oysa uygulamanız `https://mysuperapp.com` üzerinde host ediliyor olabilir ve redirect'in `https://mysuperapp.com/items/` olması gerekir.
|
||||
|
||||
Artık `--proxy-headers` ayarını yaparak FastAPI'nin doğru adrese redirect edebilmesini sağlarsınız. 😎
|
||||
|
||||
```
|
||||
https://mysuperapp.com/items/
|
||||
```
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
HTTPS hakkında daha fazla bilgi için [HTTPS Hakkında](../deployment/https.md){.internal-link target=_blank} rehberine bakın.
|
||||
|
||||
///
|
||||
|
||||
### Proxy Forwarded Header'ları Nasıl Çalışır { #how-proxy-forwarded-headers-work }
|
||||
|
||||
**Proxy**'nin, client ile **application server** arasında forwarded header'ları nasıl eklediğini gösteren görsel bir temsil:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client
|
||||
participant Proxy as Proxy/Load Balancer
|
||||
participant Server as FastAPI Server
|
||||
|
||||
Client->>Proxy: HTTPS Request<br/>Host: mysuperapp.com<br/>Path: /items
|
||||
|
||||
Note over Proxy: Proxy adds forwarded headers
|
||||
|
||||
Proxy->>Server: HTTP Request<br/>X-Forwarded-For: [client IP]<br/>X-Forwarded-Proto: https<br/>X-Forwarded-Host: mysuperapp.com<br/>Path: /items
|
||||
|
||||
Note over Server: Server interprets headers<br/>(if --forwarded-allow-ips is set)
|
||||
|
||||
Server->>Proxy: HTTP Response<br/>with correct HTTPS URLs
|
||||
|
||||
Proxy->>Client: HTTPS Response
|
||||
```
|
||||
|
||||
**Proxy**, orijinal client request'ini araya girerek (intercept) alır ve request'i **application server**'a iletmeden önce özel *forwarded* header'ları (`X-Forwarded-*`) ekler.
|
||||
|
||||
Bu header'lar, aksi halde kaybolacak olan orijinal request bilgilerini korur:
|
||||
|
||||
* **X-Forwarded-For**: Orijinal client'ın IP adresi
|
||||
* **X-Forwarded-Proto**: Orijinal protokol (`https`)
|
||||
* **X-Forwarded-Host**: Orijinal host (`mysuperapp.com`)
|
||||
|
||||
**FastAPI CLI** `--forwarded-allow-ips` ile yapılandırıldığında bu header'lara güvenir ve örneğin redirect'lerde doğru URL'leri üretmek için bunları kullanır.
|
||||
|
||||
## Path Prefix'i Kırpılan (Stripped) Bir Proxy { #proxy-with-a-stripped-path-prefix }
|
||||
|
||||
Uygulamanıza bir path prefix ekleyen bir proxy'niz olabilir.
|
||||
|
||||
Bu durumlarda uygulamanızı yapılandırmak için `root_path` kullanabilirsiniz.
|
||||
|
||||
`root_path`, FastAPI'nin (Starlette üzerinden) üzerine kurulduğu ASGI spesifikasyonunun sağladığı bir mekanizmadır.
|
||||
|
||||
`root_path` bu özel senaryoları yönetmek için kullanılır.
|
||||
|
||||
Ayrıca sub-application mount ederken de içeride kullanılır.
|
||||
|
||||
Path prefix'i kırpılan bir proxy kullanmak, şu anlama gelir: Kodunuzda `/app` altında bir path tanımlarsınız; ancak üstte bir katman (proxy) ekleyip **FastAPI** uygulamanızı `/api/v1` gibi bir path'in altına koyarsınız.
|
||||
|
||||
Bu durumda, orijinal `/app` path'i aslında `/api/v1/app` altında servis edilir.
|
||||
|
||||
Kodunuzun tamamı sadece `/app` varmış gibi yazılmış olsa bile.
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[6] *}
|
||||
|
||||
Proxy, request'i app server'a (muhtemelen FastAPI CLI üzerinden Uvicorn) iletmeden önce **path prefix**'i anlık olarak **"kırpar"** (strip). Böylece uygulamanız hâlâ `/app` altında servis ediliyormuş gibi davranır ve tüm kodunuzu `/api/v1` prefix'ini içerecek şekilde güncellemeniz gerekmez.
|
||||
|
||||
Buraya kadar her şey normal çalışır.
|
||||
|
||||
Ancak entegre doküman arayüzünü (frontend) açtığınızda, OpenAPI şemasını `/api/v1/openapi.json` yerine `/openapi.json` üzerinden almayı bekler.
|
||||
|
||||
Dolayısıyla tarayıcıda çalışan frontend `/openapi.json`'a erişmeye çalışır ve OpenAPI şemasını alamaz.
|
||||
|
||||
Çünkü uygulamamız proxy arkasında `/api/v1` path prefix'i ile çalışmaktadır; frontend'in OpenAPI şemasını `/api/v1/openapi.json` üzerinden çekmesi gerekir.
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
|
||||
browser("Browser")
|
||||
proxy["Proxy on http://0.0.0.0:9999/api/v1/app"]
|
||||
server["Server on http://127.0.0.1:8000/app"]
|
||||
|
||||
browser --> proxy
|
||||
proxy --> server
|
||||
```
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`0.0.0.0` IP'si, genelde programın ilgili makine/server üzerindeki tüm kullanılabilir IP'lerde dinlediği anlamına gelir.
|
||||
|
||||
///
|
||||
|
||||
Docs UI'nin, bu API `server`'ının (proxy arkasında) `/api/v1` altında bulunduğunu belirtmek için OpenAPI şemasına da ihtiyacı olur. Örneğin:
|
||||
|
||||
```JSON hl_lines="4-8"
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
// More stuff here
|
||||
"servers": [
|
||||
{
|
||||
"url": "/api/v1"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
// More stuff here
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Bu örnekte "Proxy", **Traefik** gibi bir şey olabilir. Server da FastAPI uygulamanızı çalıştıran (Uvicorn'lu) FastAPI CLI olabilir.
|
||||
|
||||
### `root_path` Sağlama { #providing-the-root-path }
|
||||
|
||||
Bunu yapmak için `--root-path` komut satırı seçeneğini şöyle kullanabilirsiniz:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Hypercorn kullanıyorsanız, onda da `--root-path` seçeneği vardır.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
ASGI spesifikasyonu bu kullanım senaryosu için bir `root_path` tanımlar.
|
||||
|
||||
`--root-path` komut satırı seçeneği de bu `root_path`'i sağlar.
|
||||
|
||||
///
|
||||
|
||||
### Mevcut `root_path`'i Kontrol Etme { #checking-the-current-root-path }
|
||||
|
||||
Uygulamanızın her request için kullandığı mevcut `root_path` değerini alabilirsiniz; bu değer ASGI spesifikasyonunun bir parçası olan `scope` dict'inin içindedir.
|
||||
|
||||
Burada sadece göstermek için bunu mesaja dahil ediyoruz.
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[8] *}
|
||||
|
||||
Ardından Uvicorn'u şu şekilde başlatırsanız:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Response şöyle bir şey olur:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World",
|
||||
"root_path": "/api/v1"
|
||||
}
|
||||
```
|
||||
|
||||
### FastAPI Uygulamasında `root_path` Ayarlama { #setting-the-root-path-in-the-fastapi-app }
|
||||
|
||||
Alternatif olarak, `--root-path` gibi bir komut satırı seçeneği (veya muadili) sağlayamıyorsanız, FastAPI uygulamanızı oluştururken `root_path` parametresini ayarlayabilirsiniz:
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial002_py39.py hl[3] *}
|
||||
|
||||
`FastAPI`'ye `root_path` vermek, Uvicorn veya Hypercorn'a `--root-path` komut satırı seçeneğini vermekle eşdeğerdir.
|
||||
|
||||
### `root_path` Hakkında { #about-root-path }
|
||||
|
||||
Şunu unutmayın: Server (Uvicorn) bu `root_path`'i, uygulamaya iletmek dışında başka bir amaçla kullanmaz.
|
||||
|
||||
Ancak tarayıcınızla <a href="http://127.0.0.1:8000/app" class="external-link" target="_blank">http://127.0.0.1:8000/app</a> adresine giderseniz normal response'u görürsünüz:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World",
|
||||
"root_path": "/api/v1"
|
||||
}
|
||||
```
|
||||
|
||||
Yani `http://127.0.0.1:8000/api/v1/app` üzerinden erişilmeyi beklemez.
|
||||
|
||||
Uvicorn, proxy'nin Uvicorn'a `http://127.0.0.1:8000/app` üzerinden erişmesini bekler; bunun üstüne ekstra `/api/v1` prefix'ini eklemek proxy'nin sorumluluğudur.
|
||||
|
||||
## Stripped Path Prefix Kullanan Proxy'ler Hakkında { #about-proxies-with-a-stripped-path-prefix }
|
||||
|
||||
Stripped path prefix kullanan bir proxy, yapılandırma yöntemlerinden yalnızca biridir.
|
||||
|
||||
Birçok durumda varsayılan davranış, proxy'nin stripped path prefix kullanmaması olacaktır.
|
||||
|
||||
Böyle bir durumda (stripped path prefix olmadan), proxy `https://myawesomeapp.com` gibi bir yerde dinler; tarayıcı `https://myawesomeapp.com/api/v1/app`'e giderse ve sizin server'ınız (ör. Uvicorn) `http://127.0.0.1:8000` üzerinde dinliyorsa, proxy (stripped path prefix olmadan) Uvicorn'a aynı path ile erişir: `http://127.0.0.1:8000/api/v1/app`.
|
||||
|
||||
## Traefik ile Local Olarak Test Etme { #testing-locally-with-traefik }
|
||||
|
||||
<a href="https://docs.traefik.io/" class="external-link" target="_blank">Traefik</a> kullanarak, stripped path prefix'li deneyi local'de kolayca çalıştırabilirsiniz.
|
||||
|
||||
<a href="https://github.com/containous/traefik/releases" class="external-link" target="_blank">Traefik'i indirin</a>; tek bir binary'dir, sıkıştırılmış dosyayı çıkarıp doğrudan terminalden çalıştırabilirsiniz.
|
||||
|
||||
Ardından `traefik.toml` adında bir dosya oluşturup şunu yazın:
|
||||
|
||||
```TOML hl_lines="3"
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":9999"
|
||||
|
||||
[providers]
|
||||
[providers.file]
|
||||
filename = "routes.toml"
|
||||
```
|
||||
|
||||
Bu, Traefik'e 9999 portunda dinlemesini ve `routes.toml` adlı başka bir dosyayı kullanmasını söyler.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Standart HTTP portu 80 yerine 9999 portunu kullanıyoruz; böylece admin (`sudo`) yetkileriyle çalıştırmanız gerekmez.
|
||||
|
||||
///
|
||||
|
||||
Şimdi diğer dosyayı, `routes.toml`'u oluşturun:
|
||||
|
||||
```TOML hl_lines="5 12 20"
|
||||
[http]
|
||||
[http.middlewares]
|
||||
|
||||
[http.middlewares.api-stripprefix.stripPrefix]
|
||||
prefixes = ["/api/v1"]
|
||||
|
||||
[http.routers]
|
||||
|
||||
[http.routers.app-http]
|
||||
entryPoints = ["http"]
|
||||
service = "app"
|
||||
rule = "PathPrefix(`/api/v1`)"
|
||||
middlewares = ["api-stripprefix"]
|
||||
|
||||
[http.services]
|
||||
|
||||
[http.services.app]
|
||||
[http.services.app.loadBalancer]
|
||||
[[http.services.app.loadBalancer.servers]]
|
||||
url = "http://127.0.0.1:8000"
|
||||
```
|
||||
|
||||
Bu dosya, Traefik'i `/api/v1` path prefix'ini kullanacak şekilde yapılandırır.
|
||||
|
||||
Ardından Traefik, request'leri `http://127.0.0.1:8000` üzerinde çalışan Uvicorn'unuza yönlendirir.
|
||||
|
||||
Şimdi Traefik'i başlatın:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ ./traefik --configFile=traefik.toml
|
||||
|
||||
INFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Ve şimdi uygulamanızı `--root-path` seçeneğiyle başlatın:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### Response'ları Kontrol Edin { #check-the-responses }
|
||||
|
||||
Şimdi Uvicorn'un portundaki URL'ye giderseniz: <a href="http://127.0.0.1:8000/app" class="external-link" target="_blank">http://127.0.0.1:8000/app</a>, normal response'u görürsünüz:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World",
|
||||
"root_path": "/api/v1"
|
||||
}
|
||||
```
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`http://127.0.0.1:8000/app` üzerinden erişiyor olsanız bile, `root_path` değerinin `--root-path` seçeneğinden alınıp `/api/v1` olarak gösterildiğine dikkat edin.
|
||||
|
||||
///
|
||||
|
||||
Şimdi de Traefik'in portundaki URL'yi, path prefix ile birlikte açın: <a href="http://127.0.0.1:9999/api/v1/app" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/app</a>.
|
||||
|
||||
Aynı response'u alırız:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World",
|
||||
"root_path": "/api/v1"
|
||||
}
|
||||
```
|
||||
|
||||
ama bu sefer proxy'nin sağladığı prefix path olan `/api/v1` ile gelen URL'de.
|
||||
|
||||
Elbette buradaki fikir, herkesin uygulamaya proxy üzerinden erişmesidir; dolayısıyla `/api/v1` path prefix'li sürüm "doğru" olandır.
|
||||
|
||||
Uvicorn'un doğrudan sunduğu, path prefix olmayan sürüm (`http://127.0.0.1:8000/app`) ise sadece _proxy_'nin (Traefik) erişmesi için kullanılmalıdır.
|
||||
|
||||
Bu da Proxy'nin (Traefik) path prefix'i nasıl kullandığını ve server'ın (Uvicorn) `--root-path` seçeneğinden gelen `root_path`'i nasıl kullandığını gösterir.
|
||||
|
||||
### Docs UI'yi Kontrol Edin { #check-the-docs-ui }
|
||||
|
||||
Şimdi işin eğlenceli kısmı. ✨
|
||||
|
||||
Uygulamaya erişmenin "resmi" yolu, tanımladığımız path prefix ile proxy üzerinden erişmektir. Bu yüzden beklendiği gibi, Uvicorn'un doğrudan servis ettiği docs UI'yi URL'de path prefix olmadan açarsanız çalışmaz; çünkü proxy üzerinden erişileceğini varsayar.
|
||||
|
||||
Şuradan kontrol edebilirsiniz: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>:
|
||||
|
||||
<img src="/img/tutorial/behind-a-proxy/image01.png">
|
||||
|
||||
Ancak docs UI'yi proxy üzerinden, `9999` portuyla, `/api/v1/docs` altında "resmi" URL'den açarsak doğru çalışır! 🎉
|
||||
|
||||
Şuradan kontrol edebilirsiniz: <a href="http://127.0.0.1:9999/api/v1/docs" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/docs</a>:
|
||||
|
||||
<img src="/img/tutorial/behind-a-proxy/image02.png">
|
||||
|
||||
Tam istediğimiz gibi. ✔️
|
||||
|
||||
Bunun nedeni, FastAPI'nin OpenAPI içinde varsayılan `server`'ı, `root_path` tarafından verilen URL ile oluşturmak için bu `root_path`'i kullanmasıdır.
|
||||
|
||||
## Ek `server`'lar { #additional-servers }
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
Bu daha ileri seviye bir kullanım senaryosudur. İsterseniz atlayabilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
Varsayılan olarak **FastAPI**, OpenAPI şemasında `root_path` için bir `server` oluşturur.
|
||||
|
||||
Ancak başka alternatif `servers` da sağlayabilirsiniz; örneğin *aynı* docs UI'nin hem staging hem de production ortamıyla etkileşime girmesini istiyorsanız.
|
||||
|
||||
Özel bir `servers` listesi verirseniz ve bir `root_path` varsa (çünkü API'niz proxy arkasındadır), **FastAPI** bu `root_path` ile bir "server"ı listenin başına ekler.
|
||||
|
||||
Örneğin:
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial003_py39.py hl[4:7] *}
|
||||
|
||||
Şöyle bir OpenAPI şeması üretir:
|
||||
|
||||
```JSON hl_lines="5-7"
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
// More stuff here
|
||||
"servers": [
|
||||
{
|
||||
"url": "/api/v1"
|
||||
},
|
||||
{
|
||||
"url": "https://stag.example.com",
|
||||
"description": "Staging environment"
|
||||
},
|
||||
{
|
||||
"url": "https://prod.example.com",
|
||||
"description": "Production environment"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
// More stuff here
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`url` değeri `/api/v1` olan, `root_path`'ten alınmış otomatik üretilen server'a dikkat edin.
|
||||
|
||||
///
|
||||
|
||||
Docs UI'de, <a href="http://127.0.0.1:9999/api/v1/docs" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/docs</a> adresinde şöyle görünür:
|
||||
|
||||
<img src="/img/tutorial/behind-a-proxy/image03.png">
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Docs UI, seçtiğiniz server ile etkileşime girer.
|
||||
|
||||
///
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
OpenAPI spesifikasyonunda `servers` özelliği opsiyoneldir.
|
||||
|
||||
`servers` parametresini belirtmezseniz ve `root_path` `/` ile aynıysa, üretilen OpenAPI şemasında `servers` özelliği varsayılan olarak tamamen çıkarılır; bu da `url` değeri `/` olan tek bir server ile eşdeğerdir.
|
||||
|
||||
///
|
||||
|
||||
### `root_path`'ten Otomatik `server` Eklenmesini Kapatma { #disable-automatic-server-from-root-path }
|
||||
|
||||
**FastAPI**'nin `root_path` kullanarak otomatik bir server eklemesini istemiyorsanız, `root_path_in_servers=False` parametresini kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial004_py39.py hl[9] *}
|
||||
|
||||
Böylece OpenAPI şemasına dahil etmez.
|
||||
|
||||
## Bir Sub-Application Mount Etme { #mounting-a-sub-application }
|
||||
|
||||
Bir sub-application'ı ( [Sub Applications - Mounts](sub-applications.md){.internal-link target=_blank} bölümünde anlatıldığı gibi) mount etmeniz gerekiyorsa ve aynı zamanda `root_path` ile bir proxy kullanıyorsanız, bunu beklendiği gibi normal şekilde yapabilirsiniz.
|
||||
|
||||
FastAPI içeride `root_path`'i akıllıca kullanır; dolayısıyla doğrudan çalışır. ✨
|
||||
@@ -1,312 +0,0 @@
|
||||
# Özel Response - HTML, Stream, File ve Diğerleri { #custom-response-html-stream-file-others }
|
||||
|
||||
Varsayılan olarak **FastAPI**, response'ları `JSONResponse` kullanarak döndürür.
|
||||
|
||||
Bunu, [Doğrudan bir Response döndür](response-directly.md){.internal-link target=_blank} bölümünde gördüğünüz gibi doğrudan bir `Response` döndürerek geçersiz kılabilirsiniz.
|
||||
|
||||
Ancak doğrudan bir `Response` döndürürseniz (veya `JSONResponse` gibi herhangi bir alt sınıfını), veri otomatik olarak dönüştürülmez (bir `response_model` tanımlamış olsanız bile) ve dokümantasyon da otomatik üretilmez (örneğin, üretilen OpenAPI’nin parçası olarak HTTP header `Content-Type` içindeki ilgili "media type" dahil edilmez).
|
||||
|
||||
Bununla birlikte, *path operation decorator* içinde `response_class` parametresini kullanarak hangi `Response`’un (örn. herhangi bir `Response` alt sınıfı) kullanılacağını da ilan edebilirsiniz.
|
||||
|
||||
*path operation function*’ınızdan döndürdüğünüz içerik, o `Response`’un içine yerleştirilir.
|
||||
|
||||
Ve eğer bu `Response` ( `JSONResponse` ve `UJSONResponse`’ta olduğu gibi) bir JSON media type’a (`application/json`) sahipse, döndürdüğünüz veri; *path operation decorator* içinde tanımladığınız herhangi bir Pydantic `response_model` ile otomatik olarak dönüştürülür (ve filtrelenir).
|
||||
|
||||
/// note | Not
|
||||
|
||||
Media type’ı olmayan bir response class kullanırsanız, FastAPI response’unuzun content içermediğini varsayar; bu yüzden ürettiği OpenAPI dokümanında response formatını dokümante etmez.
|
||||
|
||||
///
|
||||
|
||||
## `ORJSONResponse` Kullan { #use-orjsonresponse }
|
||||
|
||||
Örneğin performansı sıkıştırmaya çalışıyorsanız, <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a> kurup kullanabilir ve response’u `ORJSONResponse` olarak ayarlayabilirsiniz.
|
||||
|
||||
Kullanmak istediğiniz `Response` class’ını (alt sınıfını) import edin ve *path operation decorator* içinde tanımlayın.
|
||||
|
||||
Büyük response'larda, doğrudan bir `Response` döndürmek bir dictionary döndürmekten çok daha hızlıdır.
|
||||
|
||||
Çünkü varsayılan olarak FastAPI, içindeki her item’ı inceleyip JSON olarak serialize edilebilir olduğundan emin olur; tutorial’da anlatılan aynı [JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank} mekanizmasını kullanır. Bu da örneğin veritabanı modelleri gibi **keyfi objeleri** döndürebilmenizi sağlar.
|
||||
|
||||
Ancak döndürdüğünüz içeriğin **JSON ile serialize edilebilir** olduğundan eminseniz, onu doğrudan response class’ına verebilir ve FastAPI’nin response class’ına vermeden önce dönüş içeriğinizi `jsonable_encoder` içinden geçirirken oluşturacağı ek yükten kaçınabilirsiniz.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial001b_py39.py hl[2,7] *}
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
`response_class` parametresi, response’un "media type"’ını tanımlamak için de kullanılır.
|
||||
|
||||
Bu durumda HTTP header `Content-Type`, `application/json` olarak ayarlanır.
|
||||
|
||||
Ve OpenAPI’de de bu şekilde dokümante edilir.
|
||||
|
||||
///
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`ORJSONResponse` yalnızca FastAPI’de vardır, Starlette’te yoktur.
|
||||
|
||||
///
|
||||
|
||||
## HTML Response { #html-response }
|
||||
|
||||
**FastAPI**’den doğrudan HTML içeren bir response döndürmek için `HTMLResponse` kullanın.
|
||||
|
||||
* `HTMLResponse` import edin.
|
||||
* *path operation decorator*’ınızın `response_class` parametresi olarak `HTMLResponse` verin.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial002_py39.py hl[2,7] *}
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
`response_class` parametresi, response’un "media type"’ını tanımlamak için de kullanılır.
|
||||
|
||||
Bu durumda HTTP header `Content-Type`, `text/html` olarak ayarlanır.
|
||||
|
||||
Ve OpenAPI’de de bu şekilde dokümante edilir.
|
||||
|
||||
///
|
||||
|
||||
### Bir `Response` Döndür { #return-a-response }
|
||||
|
||||
[Doğrudan bir Response döndür](response-directly.md){.internal-link target=_blank} bölümünde görüldüğü gibi, *path operation* içinde doğrudan bir response döndürerek response’u override edebilirsiniz.
|
||||
|
||||
Yukarıdaki örneğin aynısı, bu sefer bir `HTMLResponse` döndürerek, şöyle görünebilir:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *}
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
*path operation function*’ınızın doğrudan döndürdüğü bir `Response`, OpenAPI’de dokümante edilmez (örneğin `Content-Type` dokümante edilmez) ve otomatik interaktif dokümanlarda görünmez.
|
||||
|
||||
///
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Elbette gerçek `Content-Type` header’ı, status code vb. değerler, döndürdüğünüz `Response` objesinden gelir.
|
||||
|
||||
///
|
||||
|
||||
### OpenAPI’de Dokümante Et ve `Response`’u Override Et { #document-in-openapi-and-override-response }
|
||||
|
||||
Response’u fonksiyonun içinden override etmek ama aynı zamanda OpenAPI’de "media type"’ı dokümante etmek istiyorsanız, `response_class` parametresini kullanıp ayrıca bir `Response` objesi döndürebilirsiniz.
|
||||
|
||||
Bu durumda `response_class` sadece OpenAPI *path operation*’ını dokümante etmek için kullanılır; sizin `Response`’unuz ise olduğu gibi kullanılır.
|
||||
|
||||
#### Doğrudan bir `HTMLResponse` Döndür { #return-an-htmlresponse-directly }
|
||||
|
||||
Örneğin şöyle bir şey olabilir:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial004_py39.py hl[7,21,23] *}
|
||||
|
||||
Bu örnekte `generate_html_response()` fonksiyonu, HTML’i bir `str` olarak döndürmek yerine zaten bir `Response` üretip döndürmektedir.
|
||||
|
||||
`generate_html_response()` çağrısının sonucunu döndürerek, varsayılan **FastAPI** davranışını override edecek bir `Response` döndürmüş olursunuz.
|
||||
|
||||
Ama `response_class` içinde `HTMLResponse` da verdiğiniz için **FastAPI**, bunu OpenAPI’de ve interaktif dokümanlarda `text/html` ile HTML olarak nasıl dokümante edeceğini bilir:
|
||||
|
||||
<img src="/img/tutorial/custom-response/image01.png">
|
||||
|
||||
## Mevcut Response'lar { #available-responses }
|
||||
|
||||
Mevcut response'lardan bazıları aşağıdadır.
|
||||
|
||||
Unutmayın: `Response` ile başka herhangi bir şeyi döndürebilir, hatta özel bir alt sınıf da oluşturabilirsiniz.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
`from starlette.responses import HTMLResponse` da kullanabilirsiniz.
|
||||
|
||||
**FastAPI**, geliştirici için kolaylık olsun diye `starlette.responses` içindekileri `fastapi.responses` olarak da sağlar. Ancak mevcut response'ların çoğu doğrudan Starlette’ten gelir.
|
||||
|
||||
///
|
||||
|
||||
### `Response` { #response }
|
||||
|
||||
Ana `Response` class’ıdır; diğer tüm response'lar bundan türetilir.
|
||||
|
||||
Bunu doğrudan döndürebilirsiniz.
|
||||
|
||||
Şu parametreleri kabul eder:
|
||||
|
||||
* `content` - Bir `str` veya `bytes`.
|
||||
* `status_code` - Bir `int` HTTP status code.
|
||||
* `headers` - String’lerden oluşan bir `dict`.
|
||||
* `media_type` - Media type’ı veren bir `str`. Örn. `"text/html"`.
|
||||
|
||||
FastAPI (aslında Starlette) otomatik olarak bir Content-Length header’ı ekler. Ayrıca `media_type`’a göre bir Content-Type header’ı ekler ve text türleri için sona bir charset ekler.
|
||||
|
||||
{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
|
||||
|
||||
### `HTMLResponse` { #htmlresponse }
|
||||
|
||||
Yukarıda okuduğunuz gibi, bir miktar text veya bytes alır ve HTML response döndürür.
|
||||
|
||||
### `PlainTextResponse` { #plaintextresponse }
|
||||
|
||||
Bir miktar text veya bytes alır ve düz metin response döndürür.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial005_py39.py hl[2,7,9] *}
|
||||
|
||||
### `JSONResponse` { #jsonresponse }
|
||||
|
||||
Bir miktar veri alır ve `application/json` olarak encode edilmiş bir response döndürür.
|
||||
|
||||
Yukarıda okuduğunuz gibi, **FastAPI**’de varsayılan response budur.
|
||||
|
||||
### `ORJSONResponse` { #orjsonresponse }
|
||||
|
||||
Yukarıda okuduğunuz gibi <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a> kullanan hızlı bir alternatif JSON response.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Bunun için `orjson` kurulmalıdır; örneğin `pip install orjson`.
|
||||
|
||||
///
|
||||
|
||||
### `UJSONResponse` { #ujsonresponse }
|
||||
|
||||
<a href="https://github.com/ultrajson/ultrajson" class="external-link" target="_blank">`ujson`</a> kullanan alternatif bir JSON response.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Bunun için `ujson` kurulmalıdır; örneğin `pip install ujson`.
|
||||
|
||||
///
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
`ujson`, bazı edge-case’leri ele alma konusunda Python’un built-in implementasyonu kadar dikkatli değildir.
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial001_py39.py hl[2,7] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`ORJSONResponse` daha hızlı bir alternatif olabilir.
|
||||
|
||||
///
|
||||
|
||||
### `RedirectResponse` { #redirectresponse }
|
||||
|
||||
HTTP redirect döndürür. Varsayılan olarak 307 status code (Temporary Redirect) kullanır.
|
||||
|
||||
`RedirectResponse`’u doğrudan döndürebilirsiniz:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial006_py39.py hl[2,9] *}
|
||||
|
||||
---
|
||||
|
||||
Veya `response_class` parametresi içinde kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial006b_py39.py hl[2,7,9] *}
|
||||
|
||||
Bunu yaparsanız, *path operation* function’ınızdan doğrudan URL döndürebilirsiniz.
|
||||
|
||||
Bu durumda kullanılan `status_code`, `RedirectResponse` için varsayılan olan `307` olur.
|
||||
|
||||
---
|
||||
|
||||
Ayrıca `status_code` parametresini `response_class` parametresiyle birlikte kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial006c_py39.py hl[2,7,9] *}
|
||||
|
||||
### `StreamingResponse` { #streamingresponse }
|
||||
|
||||
Bir async generator veya normal generator/iterator alır ve response body’yi stream eder.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial007_py39.py hl[2,14] *}
|
||||
|
||||
#### `StreamingResponse`’u file-like objelerle kullanma { #using-streamingresponse-with-file-like-objects }
|
||||
|
||||
Bir <a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> objeniz varsa (örn. `open()`’ın döndürdüğü obje), o file-like obje üzerinde iterate eden bir generator function oluşturabilirsiniz.
|
||||
|
||||
Böylece önce hepsini memory’ye okumak zorunda kalmazsınız; bu generator function’ı `StreamingResponse`’a verip döndürebilirsiniz.
|
||||
|
||||
Buna cloud storage ile etkileşime giren, video işleyen ve benzeri birçok kütüphane dahildir.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial008_py39.py hl[2,10:12,14] *}
|
||||
|
||||
1. Bu generator function’dır. İçinde `yield` ifadeleri olduğu için "generator function" denir.
|
||||
2. Bir `with` bloğu kullanarak, generator function bittiğinde file-like objenin kapandığından emin oluruz. Yani response göndermeyi bitirdikten sonra kapanır.
|
||||
3. Bu `yield from`, fonksiyona `file_like` isimli şeyi iterate etmesini söyler. Ardından iterate edilen her parça için, o parçayı bu generator function’dan (`iterfile`) geliyormuş gibi yield eder.
|
||||
|
||||
Yani, içerdeki "üretme" (generating) işini başka bir şeye devreden bir generator function’dır.
|
||||
|
||||
Bunu bu şekilde yaptığımızda `with` bloğu içinde tutabilir ve böylece iş bitince file-like objenin kapanmasını garanti edebiliriz.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Burada `async` ve `await` desteklemeyen standart `open()` kullandığımız için path operation’ı normal `def` ile tanımlarız.
|
||||
|
||||
///
|
||||
|
||||
### `FileResponse` { #fileresponse }
|
||||
|
||||
Asenkron olarak bir dosyayı response olarak stream eder.
|
||||
|
||||
Diğer response türlerine göre instantiate ederken farklı argümanlar alır:
|
||||
|
||||
* `path` - Stream edilecek dosyanın dosya path'i.
|
||||
* `headers` - Eklenecek özel header’lar; dictionary olarak.
|
||||
* `media_type` - Media type’ı veren string. Ayarlanmazsa, dosya adı veya path kullanılarak media type tahmin edilir.
|
||||
* `filename` - Ayarlanırsa response içindeki `Content-Disposition`’a dahil edilir.
|
||||
|
||||
File response'ları uygun `Content-Length`, `Last-Modified` ve `ETag` header’larını içerir.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial009_py39.py hl[2,10] *}
|
||||
|
||||
`response_class` parametresini de kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial009b_py39.py hl[2,8,10] *}
|
||||
|
||||
Bu durumda *path operation* function’ınızdan doğrudan dosya path'ini döndürebilirsiniz.
|
||||
|
||||
## Özel response class { #custom-response-class }
|
||||
|
||||
`Response`’dan türeterek kendi özel response class’ınızı oluşturabilir ve kullanabilirsiniz.
|
||||
|
||||
Örneğin, dahil gelen `ORJSONResponse` class’ında kullanılmayan bazı özel ayarlarla <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a> kullanmak istediğinizi varsayalım.
|
||||
|
||||
Diyelim ki girintili ve biçimlendirilmiş JSON döndürmek istiyorsunuz; bunun için `orjson.OPT_INDENT_2` seçeneğini kullanmak istiyorsunuz.
|
||||
|
||||
Bir `CustomORJSONResponse` oluşturabilirsiniz. Burada yapmanız gereken temel şey, content’i `bytes` olarak döndüren bir `Response.render(content)` metodu yazmaktır:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial009c_py39.py hl[9:14,17] *}
|
||||
|
||||
Artık şunu döndürmek yerine:
|
||||
|
||||
```json
|
||||
{"message": "Hello World"}
|
||||
```
|
||||
|
||||
...bu response şunu döndürür:
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Hello World"
|
||||
}
|
||||
```
|
||||
|
||||
Elbette JSON’u formatlamaktan çok daha iyi şekillerde bundan faydalanabilirsiniz. 😉
|
||||
|
||||
## Varsayılan response class { #default-response-class }
|
||||
|
||||
Bir **FastAPI** class instance’ı veya bir `APIRouter` oluştururken, varsayılan olarak hangi response class’ının kullanılacağını belirtebilirsiniz.
|
||||
|
||||
Bunu tanımlayan parametre `default_response_class`’tır.
|
||||
|
||||
Aşağıdaki örnekte **FastAPI**, tüm *path operations* için varsayılan olarak `JSONResponse` yerine `ORJSONResponse` kullanır.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial010_py39.py hl[2,4] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Daha önce olduğu gibi, *path operations* içinde `response_class`’ı yine override edebilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
## Ek dokümantasyon { #additional-documentation }
|
||||
|
||||
OpenAPI’de media type’ı ve daha birçok detayı `responses` kullanarak da tanımlayabilirsiniz: [OpenAPI’de Ek Response'lar](additional-responses.md){.internal-link target=_blank}.
|
||||
@@ -1,95 +0,0 @@
|
||||
# Dataclass Kullanımı { #using-dataclasses }
|
||||
|
||||
FastAPI, **Pydantic** üzerine inşa edilmiştir ve request/response tanımlamak için Pydantic model'lerini nasıl kullanacağınızı gösteriyordum.
|
||||
|
||||
Ancak FastAPI, <a href="https://docs.python.org/3/library/dataclasses.html" class="external-link" target="_blank">`dataclasses`</a> kullanmayı da aynı şekilde destekler:
|
||||
|
||||
{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}
|
||||
|
||||
Bu destek hâlâ **Pydantic** sayesinde vardır; çünkü Pydantic, <a href="https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel" class="external-link" target="_blank">`dataclasses` için dahili destek</a> sunar.
|
||||
|
||||
Yani yukarıdaki kod Pydantic'i doğrudan kullanmasa bile, FastAPI bu standart dataclass'ları Pydantic'in kendi dataclass biçimine dönüştürmek için Pydantic'i kullanmaktadır.
|
||||
|
||||
Ve elbette aynı özellikleri destekler:
|
||||
|
||||
* veri doğrulama (data validation)
|
||||
* veri serileştirme (data serialization)
|
||||
* veri dokümantasyonu (data documentation), vb.
|
||||
|
||||
Bu, Pydantic model'lerinde olduğu gibi çalışır. Aslında arka planda da aynı şekilde, Pydantic kullanılarak yapılır.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Dataclass'ların, Pydantic model'lerinin yapabildiği her şeyi yapamadığını unutmayın.
|
||||
|
||||
Bu yüzden yine de Pydantic model'lerini kullanmanız gerekebilir.
|
||||
|
||||
Ancak elinizde zaten bir sürü dataclass varsa, bunları FastAPI ile bir web API'yi beslemek için kullanmak güzel bir numaradır. 🤓
|
||||
|
||||
///
|
||||
|
||||
## `response_model` İçinde Dataclass'lar { #dataclasses-in-response-model }
|
||||
|
||||
`response_model` parametresinde `dataclasses` da kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}
|
||||
|
||||
Dataclass otomatik olarak bir Pydantic dataclass'ına dönüştürülür.
|
||||
|
||||
Bu sayede şeması API docs kullanıcı arayüzünde görünür:
|
||||
|
||||
<img src="/img/tutorial/dataclasses/image01.png">
|
||||
|
||||
## İç İçe Veri Yapılarında Dataclass'lar { #dataclasses-in-nested-data-structures }
|
||||
|
||||
İç içe veri yapıları oluşturmak için `dataclasses` ile diğer type annotation'ları da birleştirebilirsiniz.
|
||||
|
||||
Bazı durumlarda yine de Pydantic'in `dataclasses` sürümünü kullanmanız gerekebilir. Örneğin, otomatik oluşturulan API dokümantasyonunda hata alıyorsanız.
|
||||
|
||||
Bu durumda standart `dataclasses` yerine, drop-in replacement olan `pydantic.dataclasses` kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}
|
||||
|
||||
1. `field` hâlâ standart `dataclasses` içinden import edilir.
|
||||
|
||||
2. `pydantic.dataclasses`, `dataclasses` için bir drop-in replacement'tır.
|
||||
|
||||
3. `Author` dataclass'ı, `Item` dataclass'larından oluşan bir liste içerir.
|
||||
|
||||
4. `Author` dataclass'ı, `response_model` parametresi olarak kullanılır.
|
||||
|
||||
5. Request body olarak dataclass'larla birlikte diğer standart type annotation'ları da kullanabilirsiniz.
|
||||
|
||||
Bu örnekte, `Item` dataclass'larından oluşan bir listedir.
|
||||
|
||||
6. Burada `items` içeren bir dictionary döndürüyoruz; `items` bir dataclass listesi.
|
||||
|
||||
FastAPI, veriyi JSON'a <abbr title="converting the data to a format that can be transmitted - veriyi aktarılabilir bir formata dönüştürme">serializing</abbr> etmeyi yine başarır.
|
||||
|
||||
7. Burada `response_model`, `Author` dataclass'larından oluşan bir listenin type annotation'ını kullanıyor.
|
||||
|
||||
Yine `dataclasses` ile standart type annotation'ları birleştirebilirsiniz.
|
||||
|
||||
8. Bu *path operation function*, `async def` yerine normal `def` kullanıyor.
|
||||
|
||||
Her zaman olduğu gibi, FastAPI'de ihtiyaca göre `def` ve `async def`’i birlikte kullanabilirsiniz.
|
||||
|
||||
Hangisini ne zaman kullanmanız gerektiğine dair hızlı bir hatırlatma isterseniz, [`async` ve `await`](../async.md#in-a-hurry){.internal-link target=_blank} dokümanındaki _"In a hurry?"_ bölümüne bakın.
|
||||
|
||||
9. Bu *path operation function* dataclass döndürmüyor (isterse döndürebilir), onun yerine dahili verilerle bir dictionary listesi döndürüyor.
|
||||
|
||||
FastAPI, response'u dönüştürmek için (dataclass'ları içeren) `response_model` parametresini kullanacaktır.
|
||||
|
||||
Karmaşık veri yapıları oluşturmak için `dataclasses` ile diğer type annotation'ları pek çok farklı kombinasyonda birleştirebilirsiniz.
|
||||
|
||||
Daha spesifik ayrıntılar için yukarıdaki kod içi annotation ipuçlarına bakın.
|
||||
|
||||
## Daha Fazla Öğrenin { #learn-more }
|
||||
|
||||
`dataclasses`'ı diğer Pydantic model'leriyle de birleştirebilir, onlardan kalıtım alabilir, kendi model'lerinize dahil edebilirsiniz, vb.
|
||||
|
||||
Daha fazlası için <a href="https://docs.pydantic.dev/latest/concepts/dataclasses/" class="external-link" target="_blank">Pydantic'in dataclasses dokümantasyonuna</a> bakın.
|
||||
|
||||
## Sürüm { #version }
|
||||
|
||||
Bu özellik FastAPI `0.67.0` sürümünden beri mevcuttur. 🔖
|
||||
@@ -1,165 +0,0 @@
|
||||
# Lifespan Olayları { #lifespan-events }
|
||||
|
||||
Uygulama **başlamadan** önce çalıştırılması gereken mantığı (kodu) tanımlayabilirsiniz. Bu, bu kodun **bir kez**, uygulama **request almaya başlamadan önce** çalıştırılacağı anlamına gelir.
|
||||
|
||||
Benzer şekilde, uygulama **kapanırken** çalıştırılması gereken mantığı (kodu) da tanımlayabilirsiniz. Bu durumda bu kod, muhtemelen **çok sayıda request** işlendi **sonra**, **bir kez** çalıştırılır.
|
||||
|
||||
Bu kod, uygulama request almaya **başlamadan** önce ve request’leri işlemeyi **bitirdikten** hemen sonra çalıştığı için, uygulamanın tüm **lifespan**’ını (birazdan "lifespan" kelimesi önemli olacak 😉) kapsar.
|
||||
|
||||
Bu yaklaşım, tüm uygulama boyunca kullanacağınız ve request’ler arasında **paylaşılan** **resource**’ları kurmak ve/veya sonrasında bunları **temizlemek** için çok faydalıdır. Örneğin bir veritabanı connection pool’u ya da paylaşılan bir machine learning modelini yüklemek gibi.
|
||||
|
||||
## Kullanım Senaryosu { #use-case }
|
||||
|
||||
Önce bir **kullanım senaryosu** örneğiyle başlayalım, sonra bunu bununla nasıl çözeceğimize bakalım.
|
||||
|
||||
Request’leri işlemek için kullanmak istediğiniz bazı **machine learning modelleriniz** olduğunu hayal edelim. 🤖
|
||||
|
||||
Aynı modeller request’ler arasında paylaşılır; yani request başına bir model, kullanıcı başına bir model vb. gibi değil.
|
||||
|
||||
Modeli yüklemenin, diskten çok fazla **data** okunması gerektiği için **oldukça uzun sürebildiğini** düşünelim. Dolayısıyla bunu her request için yapmak istemezsiniz.
|
||||
|
||||
Modeli modülün/dosyanın en üst seviyesinde yükleyebilirdiniz; ancak bu, basit bir otomatik test çalıştırdığınızda bile **modelin yükleneceği** anlamına gelir. Böyle olunca test, kodun bağımsız bir kısmını çalıştırabilmek için önce modelin yüklenmesini beklemek zorunda kalır ve **yavaş** olur.
|
||||
|
||||
Burada çözeceğimiz şey bu: modeli request’ler işlenmeden önce yükleyelim, ama kod yüklenirken değil; yalnızca uygulama request almaya başlamadan hemen önce.
|
||||
|
||||
## Lifespan { #lifespan }
|
||||
|
||||
Bu *startup* ve *shutdown* mantığını, `FastAPI` uygulamasının `lifespan` parametresi ve bir "context manager" kullanarak tanımlayabilirsiniz (bunun ne olduğunu birazdan göstereceğim).
|
||||
|
||||
Önce bir örnekle başlayıp sonra ayrıntılarına bakalım.
|
||||
|
||||
Aşağıdaki gibi `yield` kullanan async bir `lifespan()` fonksiyonu oluşturuyoruz:
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py39.py hl[16,19] *}
|
||||
|
||||
Burada, `yield` öncesinde (sahte) model fonksiyonunu machine learning modellerini içeren dictionary’e koyarak, modeli yükleme gibi maliyetli bir *startup* işlemini simüle ediyoruz. Bu kod, *startup* sırasında, uygulama **request almaya başlamadan önce** çalıştırılır.
|
||||
|
||||
Ardından `yield`’den hemen sonra modeli bellekten kaldırıyoruz (unload). Bu kod, uygulama **request’leri işlemeyi bitirdikten sonra**, *shutdown*’dan hemen önce çalıştırılır. Örneğin memory veya GPU gibi resource’ları serbest bırakabilir.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`shutdown`, uygulamayı **durdurduğunuzda** gerçekleşir.
|
||||
|
||||
Belki yeni bir sürüm başlatmanız gerekiyordur, ya da çalıştırmaktan sıkılmışsınızdır. 🤷
|
||||
|
||||
///
|
||||
|
||||
### Lifespan fonksiyonu { #lifespan-function }
|
||||
|
||||
Dikkat edilmesi gereken ilk şey, `yield` içeren async bir fonksiyon tanımlıyor olmamız. Bu, `yield` kullanan Dependencies’e oldukça benzer.
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py39.py hl[14:19] *}
|
||||
|
||||
Fonksiyonun `yield`’den önceki kısmı, uygulama başlamadan **önce** çalışır.
|
||||
|
||||
`yield`’den sonraki kısım ise, uygulama işini bitirdikten **sonra** çalışır.
|
||||
|
||||
### Async Context Manager { #async-context-manager }
|
||||
|
||||
Bakarsanız, fonksiyon `@asynccontextmanager` ile dekore edilmiş.
|
||||
|
||||
Bu da fonksiyonu "**async context manager**" denen şeye dönüştürür.
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py39.py hl[1,13] *}
|
||||
|
||||
Python’da **context manager**, `with` ifadesi içinde kullanabildiğiniz bir yapıdır. Örneğin `open()` bir context manager olarak kullanılabilir:
|
||||
|
||||
```Python
|
||||
with open("file.txt") as file:
|
||||
file.read()
|
||||
```
|
||||
|
||||
Python’ın güncel sürümlerinde bir de **async context manager** vardır. Bunu `async with` ile kullanırsınız:
|
||||
|
||||
```Python
|
||||
async with lifespan(app):
|
||||
await do_stuff()
|
||||
```
|
||||
|
||||
Yukarıdaki gibi bir context manager veya async context manager oluşturduğunuzda, yaptığı şey şudur: `with` bloğuna girmeden önce `yield`’den önceki kodu çalıştırır, `with` bloğundan çıktıktan sonra da `yield`’den sonraki kodu çalıştırır.
|
||||
|
||||
Yukarıdaki kod örneğimizde bunu doğrudan kullanmıyoruz; bunun yerine FastAPI’ye veriyoruz ki o kullansın.
|
||||
|
||||
`FastAPI` uygulamasının `lifespan` parametresi bir **async context manager** alır; dolayısıyla oluşturduğumuz yeni `lifespan` async context manager’ını buraya geçebiliriz.
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py39.py hl[22] *}
|
||||
|
||||
## Alternatif Events (kullanımdan kaldırıldı) { #alternative-events-deprecated }
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
*startup* ve *shutdown* işlemlerini yönetmenin önerilen yolu, yukarıda anlatıldığı gibi `FastAPI` uygulamasının `lifespan` parametresini kullanmaktır. Bir `lifespan` parametresi sağlarsanız, `startup` ve `shutdown` event handler’ları artık çağrılmaz. Ya tamamen `lifespan` ya da tamamen events; ikisi birden değil.
|
||||
|
||||
Muhtemelen bu bölümü atlayabilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
*startup* ve *shutdown* sırasında çalıştırılacak bu mantığı tanımlamanın alternatif bir yolu daha vardır.
|
||||
|
||||
Uygulama başlamadan önce veya uygulama kapanırken çalıştırılması gereken event handler’ları (fonksiyonları) tanımlayabilirsiniz.
|
||||
|
||||
Bu fonksiyonlar `async def` ile veya normal `def` ile tanımlanabilir.
|
||||
|
||||
### `startup` eventi { #startup-event }
|
||||
|
||||
Uygulama başlamadan önce çalıştırılacak bir fonksiyon eklemek için, `"startup"` event’i ile tanımlayın:
|
||||
|
||||
{* ../../docs_src/events/tutorial001_py39.py hl[8] *}
|
||||
|
||||
Bu durumda `startup` event handler fonksiyonu, "database" öğesini (sadece bir `dict`) bazı değerlerle başlatır.
|
||||
|
||||
Birden fazla event handler fonksiyonu ekleyebilirsiniz.
|
||||
|
||||
Ve tüm `startup` event handler’ları tamamlanmadan uygulamanız request almaya başlamaz.
|
||||
|
||||
### `shutdown` eventi { #shutdown-event }
|
||||
|
||||
Uygulama kapanırken çalıştırılacak bir fonksiyon eklemek için, `"shutdown"` event’i ile tanımlayın:
|
||||
|
||||
{* ../../docs_src/events/tutorial002_py39.py hl[6] *}
|
||||
|
||||
Burada `shutdown` event handler fonksiyonu, `log.txt` dosyasına `"Application shutdown"` satırını yazar.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
`open()` fonksiyonunda `mode="a"` "append" anlamına gelir; yani satır, önceki içeriği silmeden dosyada ne varsa onun sonuna eklenir.
|
||||
|
||||
///
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Dikkat edin, bu örnekte bir dosyayla etkileşen standart Python `open()` fonksiyonunu kullanıyoruz.
|
||||
|
||||
Dolayısıyla disk’e yazılmasını beklemeyi gerektiren I/O (input/output) söz konusu.
|
||||
|
||||
Ancak `open()` `async` ve `await` kullanmaz.
|
||||
|
||||
Bu yüzden event handler fonksiyonunu `async def` yerine standart `def` ile tanımlarız.
|
||||
|
||||
///
|
||||
|
||||
### `startup` ve `shutdown` birlikte { #startup-and-shutdown-together }
|
||||
|
||||
*startup* ve *shutdown* mantığınızın birbiriyle bağlantılı olma ihtimali yüksektir; bir şeyi başlatıp sonra bitirmek, bir resource edinip sonra serbest bırakmak vb. isteyebilirsiniz.
|
||||
|
||||
Bunu, ortak mantık veya değişken paylaşmayan ayrı fonksiyonlarda yapmak daha zordur; çünkü değerleri global değişkenlerde tutmanız veya benzer numaralar yapmanız gerekir.
|
||||
|
||||
Bu nedenle artık bunun yerine, yukarıda açıklandığı gibi `lifespan` kullanmanız önerilmektedir.
|
||||
|
||||
## Teknik Detaylar { #technical-details }
|
||||
|
||||
Meraklı nerd’ler için küçük bir teknik detay. 🤓
|
||||
|
||||
Altta, ASGI teknik spesifikasyonunda bu, <a href="https://asgi.readthedocs.io/en/latest/specs/lifespan.html" class="external-link" target="_blank">Lifespan Protocol</a>’ün bir parçasıdır ve `startup` ile `shutdown` adında event’ler tanımlar.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Starlette `lifespan` handler’ları hakkında daha fazlasını <a href="https://www.starlette.dev/lifespan/" class="external-link" target="_blank">Starlette's Lifespan docs</a> içinde okuyabilirsiniz.
|
||||
|
||||
Ayrıca kodunuzun başka bölgelerinde de kullanılabilecek lifespan state’i nasıl yöneteceğinizi de kapsar.
|
||||
|
||||
///
|
||||
|
||||
## Alt Uygulamalar { #sub-applications }
|
||||
|
||||
🚨 Unutmayın: Bu lifespan event’leri (`startup` ve `shutdown`) yalnızca ana uygulama için çalıştırılır; [Alt Uygulamalar - Mounts](sub-applications.md){.internal-link target=_blank} için çalıştırılmaz.
|
||||
@@ -1,208 +0,0 @@
|
||||
# SDK Üretme { #generating-sdks }
|
||||
|
||||
**FastAPI**, **OpenAPI** spesifikasyonunu temel aldığı için API'leri birçok aracın anlayabildiği standart bir formatta tanımlanabilir.
|
||||
|
||||
Bu sayede güncel **dokümantasyon**, birden fazla dilde istemci kütüphaneleri (<abbr title="Software Development Kits - Yazılım Geliştirme Kitleri">**SDKs**</abbr>) ve kodunuzla senkron kalan **test** veya **otomasyon iş akışları** üretmek kolaylaşır.
|
||||
|
||||
Bu rehberde, FastAPI backend'iniz için bir **TypeScript SDK** üretmeyi öğreneceksiniz.
|
||||
|
||||
## Açık Kaynak SDK Üreteçleri { #open-source-sdk-generators }
|
||||
|
||||
Esnek bir seçenek olan <a href="https://openapi-generator.tech/" class="external-link" target="_blank">OpenAPI Generator</a>, **birçok programlama dilini** destekler ve OpenAPI spesifikasyonunuzdan SDK üretebilir.
|
||||
|
||||
**TypeScript client**'lar için <a href="https://heyapi.dev/" class="external-link" target="_blank">Hey API</a>, TypeScript ekosistemi için özel olarak tasarlanmış, optimize bir deneyim sunan bir çözümdür.
|
||||
|
||||
Daha fazla SDK üretecini <a href="https://openapi.tools/#sdk" class="external-link" target="_blank">OpenAPI.Tools</a> üzerinde keşfedebilirsiniz.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
FastAPI otomatik olarak **OpenAPI 3.1** spesifikasyonları üretir; bu yüzden kullanacağınız aracın bu sürümü desteklemesi gerekir.
|
||||
|
||||
///
|
||||
|
||||
## FastAPI Sponsorlarından SDK Üreteçleri { #sdk-generators-from-fastapi-sponsors }
|
||||
|
||||
Bu bölüm, FastAPI'yi sponsorlayan şirketlerin sunduğu **yatırım destekli** ve **şirket destekli** çözümleri öne çıkarır. Bu ürünler, yüksek kaliteli üretilen SDK'ların üzerine **ek özellikler** ve **entegrasyonlar** sağlar.
|
||||
|
||||
✨ [**FastAPI'ye sponsor olarak**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨ bu şirketler, framework'ün ve **ekosisteminin** sağlıklı ve **sürdürülebilir** kalmasına yardımcı olur.
|
||||
|
||||
Sponsor olmaları aynı zamanda FastAPI **topluluğuna** (size) güçlü bir bağlılığı da gösterir; yalnızca **iyi bir hizmet** sunmayı değil, aynı zamanda **güçlü ve gelişen bir framework** olan FastAPI'yi desteklemeyi de önemsediklerini gösterir. 🙇
|
||||
|
||||
Örneğin şunları deneyebilirsiniz:
|
||||
|
||||
* <a href="https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship" class="external-link" target="_blank">Speakeasy</a>
|
||||
* <a href="https://www.stainless.com/?utm_source=fastapi&utm_medium=referral" class="external-link" target="_blank">Stainless</a>
|
||||
* <a href="https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi" class="external-link" target="_blank">liblab</a>
|
||||
|
||||
Bu çözümlerin bazıları açık kaynak olabilir veya ücretsiz katman sunabilir; yani finansal bir taahhüt olmadan deneyebilirsiniz. Başka ticari SDK üreteçleri de vardır ve internette bulunabilir. 🤓
|
||||
|
||||
## TypeScript SDK Oluşturma { #create-a-typescript-sdk }
|
||||
|
||||
Basit bir FastAPI uygulamasıyla başlayalım:
|
||||
|
||||
{* ../../docs_src/generate_clients/tutorial001_py39.py hl[7:9,12:13,16:17,21] *}
|
||||
|
||||
*Path operation*'ların, request payload ve response payload için kullandıkları modelleri `Item` ve `ResponseMessage` modelleriyle tanımladıklarına dikkat edin.
|
||||
|
||||
### API Dokümanları { #api-docs }
|
||||
|
||||
`/docs` adresine giderseniz, request'lerde gönderilecek ve response'larda alınacak veriler için **schema**'ları içerdiğini görürsünüz:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image01.png">
|
||||
|
||||
Bu schema'ları görebilirsiniz, çünkü uygulamada modellerle birlikte tanımlandılar.
|
||||
|
||||
Bu bilgi uygulamanın **OpenAPI schema**'sında bulunur ve sonrasında API dokümanlarında gösterilir.
|
||||
|
||||
OpenAPI'ye dahil edilen, modellerden gelen bu bilginin aynısı **client code üretmek** için kullanılabilir.
|
||||
|
||||
### Hey API { #hey-api }
|
||||
|
||||
Modelleri olan bir FastAPI uygulamamız olduğunda, Hey API ile bir TypeScript client üretebiliriz. Bunu yapmanın en hızlı yolu npx kullanmaktır.
|
||||
|
||||
```sh
|
||||
npx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client
|
||||
```
|
||||
|
||||
Bu komut `./src/client` içine bir TypeScript SDK üretecektir.
|
||||
|
||||
Web sitelerinde <a href="https://heyapi.dev/openapi-ts/get-started" class="external-link" target="_blank">`@hey-api/openapi-ts` kurulumunu</a> öğrenebilir ve <a href="https://heyapi.dev/openapi-ts/output" class="external-link" target="_blank">üretilen çıktıyı</a> inceleyebilirsiniz.
|
||||
|
||||
### SDK'yı Kullanma { #using-the-sdk }
|
||||
|
||||
Artık client code'u import edip kullanabilirsiniz. Şuna benzer görünebilir; method'lar için otomatik tamamlama aldığınıza dikkat edin:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image02.png">
|
||||
|
||||
Ayrıca gönderilecek payload için de otomatik tamamlama alırsınız:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image03.png">
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`name` ve `price` için otomatik tamamlamaya dikkat edin; bunlar FastAPI uygulamasında, `Item` modelinde tanımlanmıştı.
|
||||
|
||||
///
|
||||
|
||||
Gönderdiğiniz veriler için satır içi hatalar (inline errors) da alırsınız:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image04.png">
|
||||
|
||||
Response objesi de otomatik tamamlama sunacaktır:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image05.png">
|
||||
|
||||
## Tag'lerle FastAPI Uygulaması { #fastapi-app-with-tags }
|
||||
|
||||
Birçok durumda FastAPI uygulamanız daha büyük olacaktır ve farklı *path operation* gruplarını ayırmak için muhtemelen tag'leri kullanacaksınız.
|
||||
|
||||
Örneğin **items** için bir bölüm, **users** için başka bir bölüm olabilir ve bunları tag'lerle ayırabilirsiniz:
|
||||
|
||||
{* ../../docs_src/generate_clients/tutorial002_py39.py hl[21,26,34] *}
|
||||
|
||||
### Tag'lerle TypeScript Client Üretme { #generate-a-typescript-client-with-tags }
|
||||
|
||||
Tag'leri kullanan bir FastAPI uygulaması için client ürettiğinizde, genelde client code da tag'lere göre ayrılır.
|
||||
|
||||
Bu sayede client code tarafında her şey doğru şekilde sıralanır ve gruplandırılır:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image06.png">
|
||||
|
||||
Bu örnekte şunlar var:
|
||||
|
||||
* `ItemsService`
|
||||
* `UsersService`
|
||||
|
||||
### Client Method İsimleri { #client-method-names }
|
||||
|
||||
Şu an üretilen `createItemItemsPost` gibi method isimleri çok temiz görünmüyor:
|
||||
|
||||
```TypeScript
|
||||
ItemsService.createItemItemsPost({name: "Plumbus", price: 5})
|
||||
```
|
||||
|
||||
...çünkü client üreteci, her *path operation* için OpenAPI'nin dahili **operation ID** değerini kullanır.
|
||||
|
||||
OpenAPI, her operation ID'nin tüm *path operation*'lar arasında benzersiz olmasını ister. Bu yüzden FastAPI; operation ID'yi benzersiz tutabilmek için **function adı**, **path** ve **HTTP method/operation** bilgilerini birleştirerek üretir.
|
||||
|
||||
Ancak bunu bir sonraki adımda nasıl iyileştirebileceğinizi göstereceğim. 🤓
|
||||
|
||||
## Özel Operation ID'ler ve Daha İyi Method İsimleri { #custom-operation-ids-and-better-method-names }
|
||||
|
||||
Bu operation ID'lerin **üretilme** şeklini **değiştirerek**, client'larda daha basit **method isimleri** elde edebilirsiniz.
|
||||
|
||||
Bu durumda, her operation ID'nin **benzersiz** olduğundan başka bir şekilde emin olmanız gerekir.
|
||||
|
||||
Örneğin, her *path operation*'ın bir tag'i olmasını sağlayabilir ve operation ID'yi **tag** ve *path operation* **adı**na (function adı) göre üretebilirsiniz.
|
||||
|
||||
### Benzersiz ID Üreten Özel Fonksiyon { #custom-generate-unique-id-function }
|
||||
|
||||
FastAPI, her *path operation* için bir **unique ID** kullanır. Bu ID, **operation ID** için ve ayrıca request/response'lar için gerekebilecek özel model isimleri için de kullanılır.
|
||||
|
||||
Bu fonksiyonu özelleştirebilirsiniz. Bir `APIRoute` alır ve string döndürür.
|
||||
|
||||
Örneğin burada ilk tag'i (muhtemelen tek tag'iniz olur) ve *path operation* adını (function adı) kullanıyor.
|
||||
|
||||
Sonrasında bu özel fonksiyonu `generate_unique_id_function` parametresiyle **FastAPI**'ye geçebilirsiniz:
|
||||
|
||||
{* ../../docs_src/generate_clients/tutorial003_py39.py hl[6:7,10] *}
|
||||
|
||||
### Özel Operation ID'lerle TypeScript Client Üretme { #generate-a-typescript-client-with-custom-operation-ids }
|
||||
|
||||
Artık client'ı tekrar üretirseniz, geliştirilmiş method isimlerini göreceksiniz:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image07.png">
|
||||
|
||||
Gördüğünüz gibi method isimleri artık önce tag'i, sonra function adını içeriyor; URL path'i ve HTTP operation bilgisini artık taşımıyor.
|
||||
|
||||
### Client Üretecine Vermeden Önce OpenAPI Spesifikasyonunu Ön İşlemek { #preprocess-the-openapi-specification-for-the-client-generator }
|
||||
|
||||
Üretilen kodda hâlâ bazı **tekrarlanan bilgiler** var.
|
||||
|
||||
Bu method'un **items** ile ilişkili olduğunu zaten biliyoruz; çünkü bu kelime `ItemsService` içinde var (tag'den geliyor). Ama method adında da tag adı önek olarak duruyor. 😕
|
||||
|
||||
OpenAPI genelinde muhtemelen bunu korumak isteriz; çünkü operation ID'lerin **benzersiz** olmasını sağlar.
|
||||
|
||||
Ancak üretilen client için, client'ları üretmeden hemen önce OpenAPI operation ID'lerini **değiştirip**, method isimlerini daha hoş ve **temiz** hale getirebiliriz.
|
||||
|
||||
OpenAPI JSON'u `openapi.json` diye bir dosyaya indirip, şu tarz bir script ile **öndeki tag'i kaldırabiliriz**:
|
||||
|
||||
{* ../../docs_src/generate_clients/tutorial004_py39.py *}
|
||||
|
||||
//// tab | Node.js
|
||||
|
||||
```Javascript
|
||||
{!> ../../docs_src/generate_clients/tutorial004.js!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
Bununla operation ID'ler `items-get_items` gibi değerlerden sadece `get_items` olacak şekilde yeniden adlandırılır; böylece client üreteci daha basit method isimleri üretebilir.
|
||||
|
||||
### Ön İşlenmiş OpenAPI ile TypeScript Client Üretme { #generate-a-typescript-client-with-the-preprocessed-openapi }
|
||||
|
||||
Sonuç artık bir `openapi.json` dosyasında olduğuna göre, input konumunu güncellemeniz gerekir:
|
||||
|
||||
```sh
|
||||
npx @hey-api/openapi-ts -i ./openapi.json -o src/client
|
||||
```
|
||||
|
||||
Yeni client'ı ürettikten sonra, tüm **otomatik tamamlama**, **satır içi hatalar**, vb. ile birlikte **temiz method isimleri** elde edersiniz:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image08.png">
|
||||
|
||||
## Faydalar { #benefits }
|
||||
|
||||
Otomatik üretilen client'ları kullanınca şu alanlarda **otomatik tamamlama** elde edersiniz:
|
||||
|
||||
* Method'lar.
|
||||
* Body'deki request payload'ları, query parametreleri, vb.
|
||||
* Response payload'ları.
|
||||
|
||||
Ayrıca her şey için **satır içi hatalar** (inline errors) da olur.
|
||||
|
||||
Backend kodunu her güncellediğinizde ve frontend'i **yeniden ürettiğinizde**, yeni *path operation*'lar method olarak eklenir, eskileri kaldırılır ve diğer değişiklikler de üretilen koda yansır. 🤓
|
||||
|
||||
Bu, bir şey değiştiğinde client code'a otomatik olarak **yansıyacağı** anlamına gelir. Ayrıca client'ı **build** ettiğinizde, kullanılan verilerde bir **uyuşmazlık** (mismatch) varsa hata alırsınız.
|
||||
|
||||
Böylece üretimde son kullanıcılara hata yansımasını beklemek ve sonra sorunun nerede olduğunu debug etmeye çalışmak yerine, geliştirme sürecinin çok erken aşamalarında **birçok hatayı tespit edersiniz**. ✨
|
||||
@@ -1,97 +0,0 @@
|
||||
# İleri Seviye Middleware { #advanced-middleware }
|
||||
|
||||
Ana tutorial'da uygulamanıza [Özel Middleware](../tutorial/middleware.md){.internal-link target=_blank} eklemeyi gördünüz.
|
||||
|
||||
Ardından [`CORSMiddleware` ile CORS'u yönetmeyi](../tutorial/cors.md){.internal-link target=_blank} de okudunuz.
|
||||
|
||||
Bu bölümde diğer middleware'leri nasıl kullanacağımıza bakacağız.
|
||||
|
||||
## ASGI middleware'leri ekleme { #adding-asgi-middlewares }
|
||||
|
||||
**FastAPI**, Starlette üzerine kurulu olduğu ve <abbr title="Asynchronous Server Gateway Interface - Asenkron Sunucu Ağ Geçidi Arayüzü">ASGI</abbr> spesifikasyonunu uyguladığı için, herhangi bir ASGI middleware'ini kullanabilirsiniz.
|
||||
|
||||
Bir middleware'in çalışması için özellikle FastAPI ya da Starlette için yazılmış olması gerekmez; ASGI spec'ine uyduğu sürece yeterlidir.
|
||||
|
||||
Genel olarak ASGI middleware'leri, ilk argüman olarak bir ASGI app almayı bekleyen class'lar olur.
|
||||
|
||||
Dolayısıyla üçüncü taraf ASGI middleware'lerinin dokümantasyonunda muhtemelen şöyle bir şey yapmanızı söylerler:
|
||||
|
||||
```Python
|
||||
from unicorn import UnicornMiddleware
|
||||
|
||||
app = SomeASGIApp()
|
||||
|
||||
new_app = UnicornMiddleware(app, some_config="rainbow")
|
||||
```
|
||||
|
||||
Ancak FastAPI (aslında Starlette) bunu yapmanın daha basit bir yolunu sunar; böylece dahili middleware'ler server hatalarını doğru şekilde ele alır ve özel exception handler'lar düzgün çalışır.
|
||||
|
||||
Bunun için `app.add_middleware()` kullanırsınız (CORS örneğindeki gibi).
|
||||
|
||||
```Python
|
||||
from fastapi import FastAPI
|
||||
from unicorn import UnicornMiddleware
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
app.add_middleware(UnicornMiddleware, some_config="rainbow")
|
||||
```
|
||||
|
||||
`app.add_middleware()` ilk argüman olarak bir middleware class'ı alır ve middleware'e aktarılacak ek argümanları da kabul eder.
|
||||
|
||||
## Entegre middleware'ler { #integrated-middlewares }
|
||||
|
||||
**FastAPI**, yaygın kullanım senaryoları için birkaç middleware içerir; şimdi bunları nasıl kullanacağımıza bakacağız.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
Bir sonraki örneklerde `from starlette.middleware.something import SomethingMiddleware` kullanmanız da mümkündür.
|
||||
|
||||
**FastAPI**, size (geliştirici olarak) kolaylık olsun diye `fastapi.middleware` içinde bazı middleware'leri sağlar. Ancak mevcut middleware'lerin çoğu doğrudan Starlette'ten gelir.
|
||||
|
||||
///
|
||||
|
||||
## `HTTPSRedirectMiddleware` { #httpsredirectmiddleware }
|
||||
|
||||
Gelen tüm request'lerin `https` veya `wss` olmasını zorunlu kılar.
|
||||
|
||||
`http` veya `ws` olarak gelen herhangi bir request, bunun yerine güvenli şemaya redirect edilir.
|
||||
|
||||
{* ../../docs_src/advanced_middleware/tutorial001_py39.py hl[2,6] *}
|
||||
|
||||
## `TrustedHostMiddleware` { #trustedhostmiddleware }
|
||||
|
||||
HTTP Host Header saldırılarına karşı korunmak için, gelen tüm request'lerde `Host` header'ının doğru ayarlanmış olmasını zorunlu kılar.
|
||||
|
||||
{* ../../docs_src/advanced_middleware/tutorial002_py39.py hl[2,6:8] *}
|
||||
|
||||
Aşağıdaki argümanlar desteklenir:
|
||||
|
||||
* `allowed_hosts` - Hostname olarak izin verilmesi gereken domain adlarının listesi. `*.example.com` gibi wildcard domain'ler subdomain eşleştirmesi için desteklenir. Herhangi bir hostname'e izin vermek için `allowed_hosts=["*"]` kullanın veya middleware'i hiç eklemeyin.
|
||||
* `www_redirect` - True olarak ayarlanırsa, izin verilen host'ların www olmayan sürümlerine gelen request'ler www sürümlerine redirect edilir. Varsayılanı `True`'dur.
|
||||
|
||||
Gelen bir request doğru şekilde doğrulanmazsa `400` response gönderilir.
|
||||
|
||||
## `GZipMiddleware` { #gzipmiddleware }
|
||||
|
||||
`Accept-Encoding` header'ında `"gzip"` içeren herhangi bir request için GZip response'larını yönetir.
|
||||
|
||||
Middleware hem standart hem de streaming response'ları ele alır.
|
||||
|
||||
{* ../../docs_src/advanced_middleware/tutorial003_py39.py hl[2,6] *}
|
||||
|
||||
Aşağıdaki argümanlar desteklenir:
|
||||
|
||||
* `minimum_size` - Bayt cinsinden bu minimum boyuttan küçük response'lara GZip uygulama. Varsayılanı `500`'dür.
|
||||
* `compresslevel` - GZip sıkıştırması sırasında kullanılır. 1 ile 9 arasında bir tamsayıdır. Varsayılanı `9`'dur. Daha düşük değer daha hızlı sıkıştırma ama daha büyük dosya boyutları üretir; daha yüksek değer daha yavaş sıkıştırma ama daha küçük dosya boyutları üretir.
|
||||
|
||||
## Diğer middleware'ler { #other-middlewares }
|
||||
|
||||
Başka birçok ASGI middleware'i vardır.
|
||||
|
||||
Örneğin:
|
||||
|
||||
* <a href="https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py" class="external-link" target="_blank">Uvicorn'un `ProxyHeadersMiddleware`'i</a>
|
||||
* <a href="https://github.com/florimondmanca/msgpack-asgi" class="external-link" target="_blank">MessagePack</a>
|
||||
|
||||
Diğer mevcut middleware'leri görmek için <a href="https://www.starlette.dev/middleware/" class="external-link" target="_blank">Starlette'in Middleware dokümanlarına</a> ve <a href="https://github.com/florimondmanca/awesome-asgi" class="external-link" target="_blank">ASGI Awesome List</a> listesine bakın.
|
||||
@@ -1,186 +0,0 @@
|
||||
# OpenAPI Callback'leri { #openapi-callbacks }
|
||||
|
||||
Başka biri tarafından (muhtemelen API'nizi *kullanacak* olan aynı geliştirici tarafından) oluşturulmuş bir *external API*'ye request tetikleyebilen bir *path operation* ile bir API oluşturabilirsiniz.
|
||||
|
||||
API uygulamanızın *external API*'yi çağırdığı sırada gerçekleşen sürece "callback" denir. Çünkü dış geliştiricinin yazdığı yazılım API'nize bir request gönderir ve ardından API'niz *geri çağrı* yaparak (*call back*), bir *external API*'ye request gönderir (muhtemelen aynı geliştiricinin oluşturduğu).
|
||||
|
||||
Bu durumda, o external API'nin nasıl görünmesi *gerektiğini* dokümante etmek isteyebilirsiniz. Hangi *path operation*'a sahip olmalı, hangi body'yi beklemeli, hangi response'u döndürmeli, vb.
|
||||
|
||||
## Callback'leri olan bir uygulama { #an-app-with-callbacks }
|
||||
|
||||
Bunların hepsine bir örnekle bakalım.
|
||||
|
||||
Fatura oluşturmayı sağlayan bir uygulama geliştirdiğinizi düşünün.
|
||||
|
||||
Bu faturaların `id`, `title` (opsiyonel), `customer` ve `total` alanları olacak.
|
||||
|
||||
API'nizin kullanıcısı (external bir geliştirici) API'nizde bir POST request ile fatura oluşturacak.
|
||||
|
||||
Sonra API'niz (varsayalım ki):
|
||||
|
||||
* Faturayı external geliştiricinin bir müşterisine gönderir.
|
||||
* Parayı tahsil eder.
|
||||
* API kullanıcısına (external geliştiriciye) tekrar bir bildirim gönderir.
|
||||
* Bu, external geliştiricinin sağladığı bir *external API*'ye (*sizin API'nizden*) bir POST request gönderilerek yapılır (işte bu "callback"tir).
|
||||
|
||||
## Normal **FastAPI** uygulaması { #the-normal-fastapi-app }
|
||||
|
||||
Önce callback eklemeden önce normal API uygulamasının nasıl görüneceğine bakalım.
|
||||
|
||||
Bir `Invoice` body alacak bir *path operation*'ı ve callback için URL'yi taşıyacak `callback_url` adlı bir query parametresi olacak.
|
||||
|
||||
Bu kısım oldukça standart; kodun çoğu muhtemelen size zaten tanıdık gelecektir:
|
||||
|
||||
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`callback_url` query parametresi, Pydantic'in <a href="https://docs.pydantic.dev/latest/api/networks/" class="external-link" target="_blank">Url</a> tipini kullanır.
|
||||
|
||||
///
|
||||
|
||||
Tek yeni şey, *path operation decorator*'ına argüman olarak verilen `callbacks=invoices_callback_router.routes`. Bunun ne olduğuna şimdi bakacağız.
|
||||
|
||||
## Callback'i dokümante etmek { #documenting-the-callback }
|
||||
|
||||
Callback'in gerçek kodu, büyük ölçüde sizin API uygulamanıza bağlıdır.
|
||||
|
||||
Ve bir uygulamadan diğerine oldukça değişebilir.
|
||||
|
||||
Sadece bir-iki satır kod bile olabilir, örneğin:
|
||||
|
||||
```Python
|
||||
callback_url = "https://example.com/api/v1/invoices/events/"
|
||||
httpx.post(callback_url, json={"description": "Invoice paid", "paid": True})
|
||||
```
|
||||
|
||||
Ancak callback'in belki de en önemli kısmı, API'nizin kullanıcısının (external geliştiricinin) *external API*'yi doğru şekilde uyguladığından emin olmaktır; çünkü *sizin API'niz* callback'in request body'sinde belirli veriler gönderecektir, vb.
|
||||
|
||||
Dolayısıyla sıradaki adım olarak, *sizin API'nizden* callback almak için o *external API*'nin nasıl görünmesi gerektiğini dokümante eden kodu ekleyeceğiz.
|
||||
|
||||
Bu dokümantasyon, API'nizde `/docs` altındaki Swagger UI'da görünecek ve external geliştiricilere *external API*'yi nasıl inşa edeceklerini gösterecek.
|
||||
|
||||
Bu örnek callback'in kendisini implemente etmiyor (o zaten tek satır kod olabilir), sadece dokümantasyon kısmını ekliyor.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Gerçek callback, sadece bir HTTP request'tir.
|
||||
|
||||
Callback'i kendiniz implemente ederken <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a> veya <a href="https://requests.readthedocs.io/" class="external-link" target="_blank">Requests</a> gibi bir şey kullanabilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
## Callback dokümantasyon kodunu yazın { #write-the-callback-documentation-code }
|
||||
|
||||
Bu kod uygulamanızda çalıştırılmayacak; sadece o *external API*'nin nasıl görünmesi gerektiğini *dokümante etmek* için gerekiyor.
|
||||
|
||||
Ancak **FastAPI** ile bir API için otomatik dokümantasyonu kolayca nasıl üreteceğinizi zaten biliyorsunuz.
|
||||
|
||||
O halde aynı bilgiyi kullanarak, *external API*'nin nasıl görünmesi gerektiğini dokümante edeceğiz... external API'nin implemente etmesi gereken *path operation*'ları oluşturarak (API'nizin çağıracağı olanlar).
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bir callback'i dokümante eden kodu yazarken, kendinizi *external geliştirici* olarak hayal etmek faydalı olabilir. Ve şu anda *sizin API'nizi* değil, *external API*'yi implemente ettiğinizi düşünün.
|
||||
|
||||
Bu bakış açısını (external geliştiricinin bakış açısını) geçici olarak benimsemek; parametreleri nereye koyacağınızı, body için Pydantic modelini, response için modelini vb. external API tarafında nasıl tasarlayacağınızı daha net hale getirebilir.
|
||||
|
||||
///
|
||||
|
||||
### Bir callback `APIRouter` oluşturun { #create-a-callback-apirouter }
|
||||
|
||||
Önce bir veya daha fazla callback içerecek yeni bir `APIRouter` oluşturun.
|
||||
|
||||
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *}
|
||||
|
||||
### Callback *path operation*'ını oluşturun { #create-the-callback-path-operation }
|
||||
|
||||
Callback *path operation*'ını oluşturmak için, yukarıda oluşturduğunuz aynı `APIRouter`'ı kullanın.
|
||||
|
||||
Normal bir FastAPI *path operation*'ı gibi görünmelidir:
|
||||
|
||||
* Muhtemelen alması gereken body'nin bir deklarasyonu olmalı, örn. `body: InvoiceEvent`.
|
||||
* Ayrıca döndürmesi gereken response'un deklarasyonu da olabilir, örn. `response_model=InvoiceEventReceived`.
|
||||
|
||||
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}
|
||||
|
||||
Normal bir *path operation*'dan 2 temel farkı vardır:
|
||||
|
||||
* Gerçek bir koda ihtiyaç duymaz; çünkü uygulamanız bu kodu asla çağırmayacak. Bu yalnızca *external API*'yi dokümante etmek için kullanılır. Yani fonksiyon sadece `pass` içerebilir.
|
||||
* *path*, bir <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression" class="external-link" target="_blank">OpenAPI 3 expression</a> (aşağıda daha fazlası) içerebilir; böylece parametreler ve *sizin API'nize* gönderilen orijinal request'in bazı parçalarıyla değişkenler kullanılabilir.
|
||||
|
||||
### Callback path ifadesi { #the-callback-path-expression }
|
||||
|
||||
Callback *path*'i, *sizin API'nize* gönderilen orijinal request'in bazı parçalarını içerebilen bir <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression" class="external-link" target="_blank">OpenAPI 3 expression</a> barındırabilir.
|
||||
|
||||
Bu örnekte, bu bir `str`:
|
||||
|
||||
```Python
|
||||
"{$callback_url}/invoices/{$request.body.id}"
|
||||
```
|
||||
|
||||
Yani API'nizin kullanıcısı (external geliştirici) *sizin API'nize* şu adrese bir request gönderirse:
|
||||
|
||||
```
|
||||
https://yourapi.com/invoices/?callback_url=https://www.external.org/events
|
||||
```
|
||||
|
||||
ve JSON body şu şekilde olursa:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"id": "2expen51ve",
|
||||
"customer": "Mr. Richie Rich",
|
||||
"total": "9999"
|
||||
}
|
||||
```
|
||||
|
||||
o zaman *sizin API'niz* faturayı işleyecek ve daha sonra bir noktada `callback_url`'ye (yani *external API*'ye) bir callback request gönderecek:
|
||||
|
||||
```
|
||||
https://www.external.org/events/invoices/2expen51ve
|
||||
```
|
||||
|
||||
ve JSON body yaklaşık şöyle bir şey içerecek:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"description": "Payment celebration",
|
||||
"paid": true
|
||||
}
|
||||
```
|
||||
|
||||
ve o *external API*'den şu gibi bir JSON body içeren response bekleyecek:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"ok": true
|
||||
}
|
||||
```
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Callback URL'sinin, `callback_url` içindeki query parametresi olarak alınan URL'yi (`https://www.external.org/events`) ve ayrıca JSON body'nin içindeki fatura `id`'sini (`2expen51ve`) birlikte kullandığına dikkat edin.
|
||||
|
||||
///
|
||||
|
||||
### Callback router'ını ekleyin { #add-the-callback-router }
|
||||
|
||||
Bu noktada, yukarıda oluşturduğunuz callback router'ında gerekli callback *path operation*'ları (external geliştiricinin *external API*'de implemente etmesi gerekenler) hazır.
|
||||
|
||||
Şimdi *sizin API'nizin path operation decorator*'ında `callbacks` parametresini kullanarak, callback router'ının `.routes` attribute'unu (bu aslında route/*path operation*'lardan oluşan bir `list`) geçin:
|
||||
|
||||
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`callback=` içine router'ın kendisini (`invoices_callback_router`) değil, `invoices_callback_router.routes` şeklinde `.routes` attribute'unu verdiğinize dikkat edin.
|
||||
|
||||
///
|
||||
|
||||
### Dokümanları kontrol edin { #check-the-docs }
|
||||
|
||||
Artık uygulamanızı başlatıp <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> adresine gidebilirsiniz.
|
||||
|
||||
*Path operation*'ınız için, *external API*'nin nasıl görünmesi gerektiğini gösteren bir "Callbacks" bölümünü içeren dokümanları göreceksiniz:
|
||||
|
||||
<img src="/img/tutorial/openapi-callbacks/image01.png">
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user