diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 445676b8b..673c86127 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -14,7 +14,7 @@ repos:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: v0.11.11
+ rev: v0.12.1
hooks:
- id: ruff
args:
diff --git a/README.md b/README.md
index 78ae6b10e..ab5143084 100644
--- a/README.md
+++ b/README.md
@@ -48,7 +48,6 @@ The key features are:
-
@@ -57,11 +56,12 @@ The key features are:
-
+
+
diff --git a/docs/bn/docs/environment-variables.md b/docs/bn/docs/environment-variables.md
new file mode 100644
index 000000000..9122ca5bf
--- /dev/null
+++ b/docs/bn/docs/environment-variables.md
@@ -0,0 +1,298 @@
+# এনভায়রনমেন্ট ভেরিয়েবলস
+
+/// tip
+
+আপনি যদি "এনভায়রনমেন্ট ভেরিয়েবলস" কী এবং সেগুলো কীভাবে ব্যবহার করতে হয় সেটা জানেন, তাহলে এই অংশটি স্কিপ করে যেতে পারেন।
+
+///
+
+এনভায়রনমেন্ট ভেরিয়েবল (সংক্ষেপে "**env var**" নামেও পরিচিত) হলো এমন একটি ভেরিয়েবল যা পাইথন কোডের **বাইরে**, **অপারেটিং সিস্টেমে** থাকে এবং আপনার পাইথন কোড (বা অন্যান্য প্রোগ্রাম) দ্বারা যাকে রিড করা যায়।
+
+এনভায়রনমেন্ট ভেরিয়েবলস অ্যাপ্লিকেশনের **সেটিংস** পরিচালনা করতে, পাইথনের **ইনস্টলেশন** প্রক্রিয়ার অংশ হিসেবে, ইত্যাদি কাজে উপযোগী হতে পারে।
+
+## Env Vars তৈরী এবং ব্যবহার
+
+আপনি **শেল (টার্মিনাল)**-এ, পাইথনের প্রয়োজন ছাড়াই, এনভায়রনমেন্ট ভেরিয়েবলস **তৈরি** এবং ব্যবহার করতে পারবেনঃ
+
+//// tab | লিনাক্স, ম্যাকওএস, উইন্ডোজ Bash
+
+
+
+```console
+// আপনি চাইলে MY_NAME নামে একটি env var তৈরি করতে পারেন
+$ export MY_NAME="Wade Wilson"
+
+// তারপরে এটিকে চাইলে অন্যান্য প্রোগ্রামে ব্যবহার করতে পারেন
+$ echo "Hello $MY_NAME"
+
+Hello Wade Wilson
+```
+
+
+
+////
+
+//// tab | উইন্ডোজ পাওয়ারশেল
+
+
+
+```console
+// MY_NAME নামে env var তৈরি
+$ $Env:MY_NAME = "Wade Wilson"
+
+// অন্যান্য প্রোগ্রামে এটিকে ব্যবহার
+$ echo "Hello $Env:MY_NAME"
+
+Hello Wade Wilson
+```
+
+
+
+////
+
+## পাইথনে env vars রিড করা
+
+আপনি চাইলে পাইথনের **বাইরে**, টার্মিনালে (বা অন্য কোনো উপায়ে) এনভায়রনমেন্ট ভেরিয়েবলস তৈরি করতে পারেন, এবং পরে সেগুলো **পাইথনে রিড** (অ্যাক্সেস করতে) পারেন।
+
+উদাহরণস্বরূপ, আপনার `main.py` নামে একটি ফাইল থাকতে পারেঃ
+
+```Python hl_lines="3"
+import os
+
+name = os.getenv("MY_NAME", "World")
+print(f"Hello {name} from Python")
+```
+
+/// tip
+
+
+
+```console
+// এখনো আমরা এনভায়রনমেন্ট ভেরিয়েবল সেট করিনি
+$ python main.py
+
+// যেহেতু env var সেট করা হয়নি, তাই আমরা ডিফল্ট ভ্যালু পাচ্ছি
+
+Hello World from Python
+
+// কিন্তু আমরা প্রথমে যদি একটা এনভায়রনমেন্ট ভারিয়েবল তৈরি করে নেই
+$ export MY_NAME="Wade Wilson"
+
+// এবং তারপর আবার প্রোগ্রাটিকে কল করি
+$ python main.py
+
+// এখন এটি এনভায়রনমেন্ট ভেরিয়েবল রিড করতে পারবে
+
+Hello Wade Wilson from Python
+```
+
+
+
+////
+
+//// tab | উইন্ডোজ পাওয়ারশেল
+
+
+
+```console
+// এখনো আমরা এনভায়রনমেন্ট ভেরিয়েবল সেট করিনি
+$ python main.py
+
+// যেহেতু env var সেট করা হয়নি, তাই আমরা ডিফল্ট ভ্যালু পাচ্ছি
+
+Hello World from Python
+
+// কিন্তু আমরা প্রথমে যদি একটা এনভায়রনমেন্ট ভারিয়েবল তৈরি করে নেই
+$ $Env:MY_NAME = "Wade Wilson"
+
+// এবং তারপর আবার প্রোগ্রাটিকে কল করি
+$ python main.py
+
+// এখন এটি এনভায়রনমেন্ট ভেরিয়েবল রিড করতে পারবে
+
+Hello Wade Wilson from Python
+```
+
+
+
+////
+
+যেহেতু এনভায়রনমেন্ট ভেরিয়েবলস কোডের বাইরে সেট করা যায়, কিন্তু পরবর্তীতে কোড দ্বারা রিড করা যায়, এবং বাকি ফাইলগুলোর সাথে রাখতে (`git` এ কমিট) হয় না, তাই কনফিগারেশনস বা **সেটিংস** এর জন্য এগুলো সাধারণত ব্যবহৃত হয়ে থাকে।
+
+আপনি একটি এনভায়রনমেন্ট ভেরিয়েবল শুধুমাত্র একটি **নির্দিষ্ট প্রোগ্রাম ইনভোকেশনের** জন্যও তৈরি করতে পারেন, যা শুধুমাত্র সেই প্রোগ্রামের জন্যই এভেইলেবল থাকবে এবং শুধুমাত্র তার চলাকালীন সময় পর্যন্তই সক্রিয় থাকবে।
+
+এটি করতে, প্রোগ্রামটি রান করার ঠিক আগেই, একই লাইনে এনভায়রনমেন্ট ভেরিয়েবল তৈরি করুন:
+
+
+
+```console
+// প্রোগ্রামটি কল করার সময় একই লাইনে MY_NAME এনভায়রনমেন্ট ভেরিয়েবল তৈরি করুন
+$ MY_NAME="Wade Wilson" python main.py
+
+// এখন এটি এনভায়রনমেন্ট ভ্যরিয়েবলটিকে রিড করতে পারবে
+
+Hello Wade Wilson from Python
+
+// পরবর্তীতে এনভায়রনমেন্ট ভেরিয়েবলটিকে আর ব্যবহার করা যাচ্ছে না
+$ python main.py
+
+Hello World from Python
+```
+
+
+
+/// tip
+
+এটি নিয়ে আরো বিস্তারিত পড়তে পারেন এখানে
diff --git a/docs/es/docs/advanced/generate-clients.md b/docs/es/docs/advanced/generate-clients.md
index bf2e5cb4f..b664bceac 100644
--- a/docs/es/docs/advanced/generate-clients.md
+++ b/docs/es/docs/advanced/generate-clients.md
@@ -22,7 +22,7 @@ Y muestra su verdadero compromiso con FastAPI y su **comunidad** (tú), ya que n
Por ejemplo, podrías querer probar:
-* Speakeasy
+*
Speakeasy
*
Stainless
*
liblab
diff --git a/docs/fa/docs/learn/index.md b/docs/fa/docs/learn/index.md
new file mode 100644
index 000000000..06aa7f00e
--- /dev/null
+++ b/docs/fa/docs/learn/index.md
@@ -0,0 +1,5 @@
+# یادگیری
+
+اینجا بخشهای مقدماتی و آموزشهایی هستن که برای یادگیری **FastAPI** بهت کمک میکنن.
+
+میتونی اینو یه **کتاب**، یه **دوره آموزشی**، یا راه **رسمی** و پیشنهادی برای یادگیری FastAPI در نظر بگیری. 😎
diff --git a/docs/ja/docs/tutorial/body-fields.md b/docs/ja/docs/tutorial/body-fields.md
index 0466320f1..ce5630351 100644
--- a/docs/ja/docs/tutorial/body-fields.md
+++ b/docs/ja/docs/tutorial/body-fields.md
@@ -44,7 +44,7 @@
追加情報は`Field`や`Query`、`Body`などで宣言することができます。そしてそれは生成されたJSONスキーマに含まれます。
-後に例を用いて宣言を学ぶ際に、追加情報を句悪方法を学べます。
+後に例を用いて宣言を学ぶ際に、追加情報を追加する方法を学べます。
## まとめ
diff --git a/docs/ja/docs/tutorial/encoder.md b/docs/ja/docs/tutorial/encoder.md
index 409ebeec6..309cf8857 100644
--- a/docs/ja/docs/tutorial/encoder.md
+++ b/docs/ja/docs/tutorial/encoder.md
@@ -8,7 +8,7 @@
## `jsonable_encoder`の使用
-JSON互換のデータのみを受信するデータベース`fase_db`があるとしましょう。
+JSON互換のデータのみを受信するデータベース`fake_db`があるとしましょう。
例えば、`datetime`オブジェクトはJSONと互換性がないので、このデーターベースには受け取られません。
diff --git a/docs/ja/docs/tutorial/handling-errors.md b/docs/ja/docs/tutorial/handling-errors.md
index 9a46cc738..37315b087 100644
--- a/docs/ja/docs/tutorial/handling-errors.md
+++ b/docs/ja/docs/tutorial/handling-errors.md
@@ -63,7 +63,7 @@ Pythonの例外なので、`return`ではなく、`raise`です。
`HTTPException`を発生させる際には、`str`だけでなく、JSONに変換できる任意の値を`detail`パラメータとして渡すことができます。
-`dist`や`list`などを渡すことができます。
+`dict`や`list`などを渡すことができます。
これらは **FastAPI** によって自動的に処理され、JSONに変換されます。
diff --git a/docs/ko/docs/advanced/sub-applications.md b/docs/ko/docs/advanced/sub-applications.md
new file mode 100644
index 000000000..c5835de15
--- /dev/null
+++ b/docs/ko/docs/advanced/sub-applications.md
@@ -0,0 +1,67 @@
+# 하위 응용프로그램 - 마운트
+
+만약 각각의 독립적인 OpenAPI와 문서 UI를 갖는 두 개의 독립적인 FastAPI 응용프로그램이 필요하다면, 메인 어플리케이션에 하나 (또는 그 이상의) 하위-응용프로그램(들)을 “마운트"해서 사용할 수 있습니다.
+
+## **FastAPI** 응용프로그램 마운트
+
+“마운트"이란 완전히 “독립적인" 응용프로그램을 특정 경로에 추가하여 해당 하위 응용프로그램에서 선언된 *경로 동작*을 통해 해당 경로 아래에 있는 모든 작업들을 처리할 수 있도록 하는 것을 의미합니다.
+
+### 최상단 응용프로그램
+
+먼저, 메인, 최상단의 **FastAPI** 응용프로그램과 이것의 *경로 동작*을 생성합니다:
+
+{* ../../docs_src/sub_applications/tutorial001.py hl[3, 6:8] *}
+
+### 하위 응용프로그램
+
+다음으로, 하위 응용프로그램과 이것의 *경로 동작*을 생성합니다:
+
+이 하위 응용프로그램은 또 다른 표준 FastAPI 응용프로그램입니다. 다만 이것은 “마운트”될 것입니다:
+
+{* ../../docs_src/sub_applications/tutorial001.py hl[11, 14:16] *}
+
+### 하위 응용프로그램 마운트
+
+최상단 응용프로그램, `app`에 하위 응용프로그램, `subapi`를 마운트합니다.
+
+이 예시에서, 하위 응용프로그램션은 `/subapi` 경로에 마운트 될 것입니다:
+
+{* ../../docs_src/sub_applications/tutorial001.py hl[11, 19] *}
+
+### 자동으로 생성된 API 문서 확인
+
+이제, `uvicorn`으로 메인 응용프로그램을 실행하십시오. 당신의 파일이 `main.py`라면, 이렇게 실행합니다:
+
+
+
+```console
+$ uvicorn main:app --reload
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+그리고
http://127.0.0.1:8000/docs에서 문서를 여십시오.
+
+메인 응용프로그램의 *경로 동작*만을 포함하는, 메인 응용프로그램에 대한 자동 API 문서를 확인할 수 있습니다:
+
+

+
+다음으로,
http://127.0.0.1:8000/subapi/docs에서 하위 응용프로그램의 문서를 여십시오.
+
+하위 경로 접두사 `/subapi` 아래에 선언된 *경로 동작* 을 포함하는, 하위 응용프로그램에 대한 자동 API 문서를 확인할 수 있습니다:
+
+

+
+두 사용자 인터페이스 중 어느 하나를 사용해야하는 경우, 브라우저는 특정 응용프로그램 또는 하위 응용프로그램과 각각 통신할 수 있기 때문에 올바르게 동작할 것입니다.
+
+### 기술적 세부사항: `root_path`
+
+위에 설명된 것과 같이 하위 응용프로그램을 마운트하는 경우, FastAPI는 `root_path`라고 하는 ASGI 명세의 매커니즘을 사용하여 하위 응용프로그램에 대한 마운트 경로 통신을 처리합니다.
+
+이를 통해, 하위 응용프로그램은 문서 UI를 위해 경로 접두사를 사용해야 한다는 사실을 인지합니다.
+
+하위 응용프로그램에도 역시 다른 하위 응용프로그램을 마운트하는 것이 가능하며 FastAPI가 모든 `root_path` 들을 자동적으로 처리하기 때문에 모든 것은 올바르게 동작할 것입니다.
+
+`root_path`와 이것을 사용하는 방법에 대해서는 [프록시의 뒷단](./behind-a-proxy.md){.internal-link target=_blank} 섹션에서 배울 수 있습니다.
diff --git a/docs/pt/docs/advanced/generate-clients.md b/docs/pt/docs/advanced/generate-clients.md
index 04d7c0071..dc6b29511 100644
--- a/docs/pt/docs/advanced/generate-clients.md
+++ b/docs/pt/docs/advanced/generate-clients.md
@@ -22,7 +22,7 @@ E isso mostra o verdadeiro compromisso deles com o FastAPI e sua **comunidade**
Por exemplo, você pode querer experimentar:
-*
Speakeasy
+*
Speakeasy
*
Stainless
*
liblab
diff --git a/docs/ru/docs/advanced/index.md b/docs/ru/docs/advanced/index.md
new file mode 100644
index 000000000..b5cb733e7
--- /dev/null
+++ b/docs/ru/docs/advanced/index.md
@@ -0,0 +1,21 @@
+# Расширенное руководство пользователя
+
+## Дополнительные возможности
+
+Основное [Учебник - Руководство пользователя](../tutorial/index.md){.internal-link target=_blank} должно быть достаточно, чтобы познакомить вас со всеми основными функциями **FastAPI**.
+
+В следующих разделах вы увидите другие варианты, конфигурации и дополнительные возможности.
+
+/// tip
+
+Следующие разделы **не обязательно являются "продвинутыми"**.
+
+И вполне возможно, что для вашего случая использования решение находится в одном из них.
+
+///
+
+## Сначала прочитайте Учебник - Руководство пользователя
+
+Вы все еще можете использовать большинство функций **FastAPI** со знаниями из [Учебник - Руководство пользователя](../tutorial/index.md){.internal-link target=_blank}.
+
+И следующие разделы предполагают, что вы уже прочитали его, и предполагают, что вы знаете эти основные идеи.
diff --git a/docs/ru/docs/advanced/response-change-status-code.md b/docs/ru/docs/advanced/response-change-status-code.md
new file mode 100644
index 000000000..37dade99f
--- /dev/null
+++ b/docs/ru/docs/advanced/response-change-status-code.md
@@ -0,0 +1,31 @@
+# Response - Изменение cтатус кода
+
+Вы, вероятно, уже читали о том, что можно установить [Состояние ответа по умолчанию](../tutorial/response-status-code.md){.internal-link target=_blank}.
+
+Но в некоторых случаях вам нужно вернуть код состояния, отличный от установленного по умолчанию.
+
+## Пример использования
+
+Например, представьте, что вы хотите возвращать HTTP код состояния "OK" `200` по умолчанию.
+
+Но если данные не существовали, вы хотите создать их и вернуть HTTP код состояния "CREATED" `201`.
+
+При этом вы всё ещё хотите иметь возможность фильтровать и преобразовывать возвращаемые данные с помощью `response_model`.
+
+Для таких случаев вы можете использовать параметр `Response`.
+
+## Использование параметра `Response`
+
+Вы можете объявить параметр типа `Response` в вашей *функции обработки пути* (так же как для cookies и headers).
+
+И затем вы можете установить `status_code` в этом *временном* объекте ответа.
+
+{* ../../docs_src/response_change_status_code/tutorial001.py hl[1,9,12] *}
+
+После этого вы можете вернуть любой объект, который вам нужен, как обычно (`dict`, модель базы данных и т.д.).
+
+И если вы объявили `response_model`, он всё равно будет использоваться для фильтрации и преобразования возвращаемого объекта.
+
+**FastAPI** будет использовать этот *временный* ответ для извлечения кода состояния (а также cookies и headers) и поместит их в финальный ответ, который содержит возвращаемое вами значение, отфильтрованное любым `response_model`.
+
+Вы также можете объявить параметр `Response` в зависимостях и установить код состояния в них. Но помните, что последнее установленное значение будет иметь приоритет.
diff --git a/docs/uk/docs/tutorial/body-updates.md b/docs/uk/docs/tutorial/body-updates.md
new file mode 100644
index 000000000..e78b5a5bf
--- /dev/null
+++ b/docs/uk/docs/tutorial/body-updates.md
@@ -0,0 +1,116 @@
+# Тіло – Оновлення
+
+## Оновлення з використанням `PUT`
+
+Щоб оновити елемент, Ви можете використати
HTTP `PUT` операцію.
+
+Ви можете використати `jsonable_encoder`, щоб перетворити вхідні дані на такі, які можна зберігати як JSON (наприклад, у NoSQL базі даних). Наприклад, перетворюючи `datetime` у `str`.
+
+{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}
+
+`PUT` використовується для отримання даних, які мають замінити чинні дані.
+
+### Попередження про заміну
+
+Це означає, що якщо Ви хочете оновити елемент `bar`, використовуючи `PUT` з тілом:
+
+```Python
+{
+ "name": "Barz",
+ "price": 3,
+ "description": None,
+}
+```
+
+оскільки він не містить вже збереженого атрибута `"tax": 20.2`, модель введення прийме значення за замовчуванням `"tax": 10.5`.
+
+І дані будуть збережені з цим "новим" значенням `tax` = `10.5`.
+
+## Часткові оновлення з `PATCH`
+
+Ви також можете використовувати операцію
HTTP `PATCH` для *часткового* оновлення даних.
+
+Це означає, що Ви можете надіслати лише ті дані, які хочете оновити, залишаючи інші без змін.
+
+/// note | Примітка
+
+`PATCH` менш відомий і рідше використовується, ніж `PUT`.
+
+І багато команд використовують лише `PUT`, навіть для часткових оновлень.
+
+Ви **вільні** використовувати їх так, як хочете, **FastAPI** не накладає обмежень.
+
+Але цей посібник показує Вам більш-менш як їх задумано використовувати.
+
+///
+
+### Використання параметра `exclude_unset` у Pydantic
+
+Якщо Ви хочете отримати часткові оновлення, дуже зручно використовувати параметр `exclude_unset` у методі `.model_dump()` моделі Pydantic.
+
+Наприклад: `item.model_dump(exclude_unset=True)`.
+
+/// info | Інформація
+
+У Pydantic v1 цей метод називався `.dict()`, він був застарілий (але все ще підтримується) у Pydantic v2, і був перейменований у `.model_dump()`.
+
+Приклади тут використовують `.dict()` для сумісності з Pydantic v1, але Вам слід використовувати `.model_dump()`, якщо можете використовувати Pydantic v2.
+
+///
+
+Це створить `dict` лише з тими даними, які були явно встановлені під час створення моделі `item`, виключаючи значення за замовчуванням.
+
+Тоді Ви можете використовувати це, щоб створити `dict` лише з даними, які були встановлені (надіслані у запиті), пропускаючи значення за замовчуванням:
+
+{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}
+
+### Використання параметра `update` у Pydantic
+
+Тепер Ви можете створити копію наявної моделі за допомогою `.model_copy()`, і передати параметр `update` з `dict` , який містить дані для оновлення.
+
+/// info | Інформація
+
+У Pydantic v1 метод називався `.copy()`, він був застарілий (але все ще підтримується) у Pydantic v2, і був перейменований у `.model_copy()`.
+
+Приклади тут використовують `.copy()` для сумісності з Pydantic v1, але якщо Ви можете використовувати Pydantic v2 — Вам слід використовувати `.model_copy()` замість цього.
+
+///
+
+Наприклад: `stored_item_model.model_copy(update=update_data)`:
+
+{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}
+
+### Підсумок часткових оновлень
+
+У підсумку, щоб застосувати часткові оновлення, Ви:
+
+* (Опціонально) використовуєте `PATCH` замість `PUT`.
+* Отримуєте збережені дані.
+* Поміщаєте ці дані в модель Pydantic.
+* Генеруєте `dict` без значень за замовчуванням з моделі введення (використовуючи `exclude_unset`).
+ * Таким чином Ви оновите лише ті значення, які були явно задані користувачем, замість того, щоб перезаписувати вже збережені значення значеннями за замовчуванням з вашої моделі.
+* Створюєте копію збереженої моделі, оновлюючи її атрибути отриманими частковими оновленнями (використовуючи параметр `update`).
+* Перетворюєте скопійовану модель на щось, що можна зберегти у вашу БД (наприклад, використовуючи `jsonable_encoder`).
+ * Це можна порівняти з повторним використанням методу `.model_dump()` моделі, але це гарантує (і перетворює) значення у типи даних, які можна перетворити на JSON, наприклад, `datetime` на `str`.
+* Зберігаєте дані у вашу БД.
+* Повертаєте оновлену модель.
+
+{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}
+
+/// tip | Порада
+
+Насправді Ви можете використовувати цю саму техніку і з операцією HTTP `PUT`.
+
+Але приклад тут використовує `PATCH`, тому що він був створений саме для таких випадків.
+
+///
+
+/// note | Примітка
+
+Зверніть увагу, що модель запиту все ще проходить валідацію.
+
+Тож, якщо Ви хочете отримувати часткові оновлення, які можуть не містити жодного атрибута, Вам потрібно мати модель, де всі атрибути позначені як необов’язкові (зі значеннями за замовчуванням або `None`).
+
+Щоб розрізняти моделі з усіма необов’язковими значеннями для **оновлення** і моделі з обов’язковими значеннями для **створення**, Ви можете скористатись ідеями, описаними у [Додаткові моделі](extra-models.md){.internal-link target=_blank}.
+
+///
diff --git a/docs/uk/docs/tutorial/query-param-models.md b/docs/uk/docs/tutorial/query-param-models.md
new file mode 100644
index 000000000..97eb82fa1
--- /dev/null
+++ b/docs/uk/docs/tutorial/query-param-models.md
@@ -0,0 +1,68 @@
+# Моделі Query параметрів
+
+Якщо у Вас є група **query параметрів**, які пов’язані між собою, Ви можете створити **Pydantic-модель** для їх оголошення.
+
+Це дозволить Вам **повторно використовувати модель** у **різних місцях**, а також оголошувати перевірки та метадані для всіх параметрів одночасно. 😎
+
+/// note | Примітка
+
+Ця можливість підтримується, починаючи з версії FastAPI `0.115.0`. 🤓
+
+///
+
+## Query параметри з Pydantic-моделлю
+
+Оголосіть **query параметри**, які Вам потрібні, у **Pydantic-моделі**, а потім оголосіть цей параметр як `Query`:
+
+{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}
+
+**FastAPI** буде **витягувати** дані для **кожного поля** з **query параметрів** у запиті та передавати їх у визначену вами Pydantic-модель.
+
+## Перевірте документацію
+
+Ви можете побачити параметри запиту в UI документації за `/docs`:
+
+
+

+
+
+## Заборона зайвих Query параметрів
+
+У деяких особливих випадках (ймовірно, не дуже поширених) Ви можете захотіти **обмежити** query параметри, які дозволено отримувати.
+
+Ви можете використати конфігурацію моделі Pydantic, щоб заборонити (`forbid`) будь-які зайві (`extra`) поля:
+
+{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}
+
+Якщо клієнт спробує надіслати **зайві** дані у **query параметрах**, він отримає **помилку**.
+
+Наприклад, якщо клієнт спробує надіслати query параметр `tool` зі значенням `plumbus`, як у цьому запиті:
+
+```http
+https://example.com/items/?limit=10&tool=plumbus
+```
+
+Він отримає відповідь з **помилкою**, яка повідомить, що query параметр `tool ` не дозволено:
+
+```json
+{
+ "detail": [
+ {
+ "type": "extra_forbidden",
+ "loc": ["query", "tool"],
+ "msg": "Extra inputs are not permitted",
+ "input": "plumbus"
+ }
+ ]
+}
+```
+
+## Підсумок
+
+Ви можете використовувати **Pydantic-моделі** для оголошення **query параметрів** у **FastAPI**. 😎
+
+/// tip | Підказка
+
+Спойлер: Ви також можете використовувати Pydantic-моделі для оголошення cookie та заголовків, але про це Ви дізнаєтеся пізніше в цьому посібнику. 🤫
+
+///
diff --git a/docs/uk/docs/tutorial/response-model.md b/docs/uk/docs/tutorial/response-model.md
new file mode 100644
index 000000000..def1f8a2d
--- /dev/null
+++ b/docs/uk/docs/tutorial/response-model.md
@@ -0,0 +1,358 @@
+# Модель відповіді — Тип, що повертається
+
+Ви можете оголосити тип, який використовуватиметься у відповіді, за допомогою *анотації типу, що повертається* *функцією операцією шляху* (path operation)
+
+**Анотацію типу** можна вказати так само як і для вхідних **параметрів** функції: це можуть бути моделі Pydantic, списки (lists), словники (dictionaries), скалярні значення, як-от цілі числа (integers), булеві значення (booleans) тощо.
+
+{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}
+
+FastAPI використовуватиме цей тип, щоб:
+
+* **Перевірити правильність** повернених даних.
+ * Якщо дані не валідні (наприклад, відсутнє поле), це означає, що Ваш код додатку працює некоректно і не повертає те, що повинен. У такому випадку FastAPI поверне помилку сервера, замість того щоб віддати недопустимі дані. Так Ви та Ваші клієнти будете впевнені, що отримуєте очікувані дані у правильному форматі.
+
+* Додати **JSON Schema** відповіді до специфікації OpenAPI в *операціях шляху*.
+ * Це буде використано в **автоматичній документації**.
+ * А також інструментами, які автоматично генерують клієнтський код.
+
+Але найголовніше:
+
+* FastAPI **обмежить та відфільтрує** вихідні дані відповідно до типу, вказаного у відповіді.
+ * Це особливо важливо для **безпеки**. Деталі нижче.
+
+## Параметр `response_model`
+
+Іноді Вам потрібно або зручно повертати інші типи даних, ніж ті, що зазначені як тип відповіді.
+
+Наприклад, Ви можете **повертати словник** або об’єкт бази даних, але **оголосити модель Pydantic** як модель відповіді. Тоді модель Pydantic автоматично оброблятиме валідацію, документацію тощо.
+
+Якщо Ви додасте анотацію типу для повернення, редактор коду або mypy можуть поскаржитися, що функція повертає інший тип (наприклад, dict замість Item).
+
+У таких випадках можна скористатися параметром `response_model` в декораторі маршруту (наприклад, @app.get()).
+
+Параметр `response_model` працює з будь-яким *оператором шляху*:
+
+* `@app.get()`
+* `@app.post()`
+* `@app.put()`
+* `@app.delete()`
+* тощо.
+
+{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}
+
+/// note | Примітка
+
+Зверніть увагу, що `response_model` є параметром методу-декоратора (`get`, `post`, тощо), а не *функцією операцією шляху* (path operation function), як це робиться з параметрами або тілом запиту.
+
+///
+
+`response_model` приймає такий самий тип, який Ви б вказали для поля моделі Pydantic. Тобто це може бути як Pydantic-модель, так і, наприклад, `list` із моделей Pydantic — `List[Item]`.
+
+FastAPI використовуватиме `response_model` для створення документації, валідації даних та — найважливіше — **перетворення та фільтрації вихідних даних** згідно з оголошеним типом.
+
+/// tip | Порада
+
+Якщо у Вас увімкнено сувору перевірку типів у редакторі, mypy тощо, Ви можете оголосити тип повернення функції як `Any`.
+
+Таким чином, Ви повідомляєте редактору, що свідомо повертаєте будь-що. Але FastAPI усе одно виконуватиме створення документації, валідацію, фільтрацію тощо за допомогою параметра `response_model`.
+
+///
+
+### Пріоритет `response_model`
+
+Якщо Ви вказуєте і тип повернення, і `response_model`, то FastAPI використовуватиме `response_model` з пріоритетом.
+
+Таким чином, Ви можете додати правильні анотації типів до ваших функцій, навіть якщо вони повертають тип, відмінний від `response_model`. Це буде корисно для редакторів коду та інструментів, таких як mypy. І при цьому FastAPI продовжить виконувати валідацію даних, генерувати документацію тощо на основі `response_model`.
+
+Ви також можете використати `response_model=None`, щоб вимкнути створення моделі відповіді для цієї *операції шляху*. Це може знадобитися, якщо Ви додаєте анотації типів до об'єктів, які не є допустимими полями Pydantic — приклад цього Ви побачите в одному з наступних розділів.
+
+## Повернути ті самі вхідні дані
+
+Тут ми оголошуємо модель `UserIn`, яка містить звичайний текстовий пароль:
+
+{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}
+
+/// info | Інформація
+
+Щоб використовувати `EmailStr`, спочатку встановіть
`email-validator`.
+
+Переконайтесь, що Ви створили [віртуальне середовище](../virtual-environments.md){.internal-link target=_blank}, активували його, а потім встановили пакет, наприклад:
+
+```console
+$ pip install email-validator
+```
+
+or with:
+
+```console
+$ pip install "pydantic[email]"
+```
+
+///
+
+І ми використовуємо цю модель, щоб оголосити і вхідні, і вихідні дані:
+
+{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}
+
+Тепер, коли браузер створює користувача з паролем, API поверне той самий пароль у відповіді.
+
+У цьому випадку це може не бути проблемою, адже саме користувач надіслав пароль.
+
+Але якщо ми використаємо цю ж модель для іншої операції шляху, ми можемо випадково надіслати паролі наших користувачів кожному клієнту.
+
+/// danger | Обережно
+
+Ніколи не зберігайте пароль користувача у відкритому вигляді та не надсилайте його у відповіді, якщо тільки Ви не знаєте всі ризики і точно розумієте, що робите.
+
+///
+
+## Додайте окрему вихідну модель
+
+Замість цього ми можемо створити вхідну модель з відкритим паролем і вихідну модель без нього:
+
+{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}
+
+Тут, навіть якщо *функція операції шляху* повертає об'єкт користувача, який містить пароль:
+
+{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}
+
+...ми оголосили `response_model` як нашу модель `UserOut`, яка не містить пароля:
+
+{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}
+
+Таким чином, **FastAPI** автоматично відфільтрує всі дані, які не вказані у вихідній моделі (за допомогою Pydantic).
+
+### `response_model` або тип повернення
+
+У цьому випадку, оскільки дві моделі різні, якщо ми анотуємо тип повернення функції як `UserOut`, редактор і такі інструменти, як mypy, видадуть помилку, бо фактично ми повертаємо інший тип.
+
+Тому в цьому прикладі ми використовуємо параметр `response_model`, а не анотацію типу повернення.
+
+...але читайте далі, щоб дізнатися, як обійти це обмеження.
+
+## Тип повернення і фільтрація даних
+
+Продовжимо з попереднього прикладу. Ми хотіли **анотувати функцію одним типом**, але при цьому повертати з неї більше даних.
+
+Ми хочемо, щоб FastAPI продовжував **фільтрувати** ці дані за допомогою response_model. Тобто навіть якщо функція повертає більше інформації, у відповіді будуть лише ті поля, які вказані у response_model.
+
+У попередньому прикладі, оскільки класи були різні, нам довелося використовувати параметр `response_model`. Але це означає, що ми не отримуємо підтримки з боку редактора коду та інструментів перевірки типів щодо типу, який повертає функція.
+
+Проте в більшості випадків, коли нам потрібно зробити щось подібне, ми просто хочемо, щоб модель **відфільтрувала або прибрала** частину даних, як у цьому прикладі.
+
+У таких випадках ми можемо використати класи та спадкування, щоб скористатися **анотаціями типів** функцій — це дає кращу підтримку з боку редактора та інструментів типу mypy, і при цьому FastAPI продовжує виконувати **фільтрацію даних** у відповіді.
+
+{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}
+
+Завдяки цьому ми отримуємо підтримку інструментів — від редакторів і mypy, оскільки цей код є коректним з точки зору типів, — але ми також отримуємо фільтрацію даних від FastAPI.
+
+Як це працює? Давайте розберемося. 🤓
+
+### Типи та підтримка інструментів
+
+Спершу подивимось, як це бачать редактори, mypy та інші інструменти.
+
+`BaseUser` має базові поля. Потім `UserIn` успадковує `BaseUser` і додає поле `password`, отже, він матиме всі поля з обох моделей.
+
+Ми зазначаємо тип повернення функції як `BaseUser`, але фактично повертаємо екземпляр `UserIn`.
+
+Редактор, mypy та інші інструменти не скаржитимуться на це, тому що з точки зору типізації `UserIn` є підкласом `BaseUser`, а це означає, що він є `валідним` типом, коли очікується будь-що, що є `BaseUser`.
+
+### Фільтрація даних у FastAPI
+
+Тепер для FastAPI він бачить тип повернення і переконується, що те, що Ви повертаєте, містить **тільки** поля, які оголошені у цьому типі.
+
+FastAPI виконує кілька внутрішніх операцій з Pydantic, щоб гарантувати, що правила наслідування класів не застосовуються для фільтрації повернених даних, інакше Ви могли б повернути значно більше даних, ніж очікували.
+
+Таким чином, Ви отримуєте найкраще з двох світів: анотації типів **з підтримкою інструментів** і **фільтрацію даних**.
+
+## Подивитись у документації
+
+Коли Ви дивитесь автоматичну документацію, Ви можете побачити, що вхідна модель і вихідна модель мають власну JSON-схему:
+
+

+
+І обидві моделі використовуються для інтерактивної API-документації:
+
+

+
+## Інші анотації типів повернення
+
+Існують випадки, коли Ви повертаєте щось, що не є допустимим полем Pydantic, але анотуєте це у функції лише для того, щоб отримати підтримку від інструментів (редактора, mypy тощо).
+
+### Повернення Response напряму
+
+Найпоширенішим випадком буде [повернення Response напряму, як пояснюється пізніше у розширеній документації](../advanced/response-directly.md){.internal-link target=_blank}.
+
+{* ../../docs_src/response_model/tutorial003_02.py hl[8,10:11] *}
+
+Цей простий випадок автоматично обробляється FastAPI, тому що анотація типу повернення — це клас (або підклас) `Response`.
+
+І інструменти також будуть задоволені, бо і `RedirectResponse`, і `JSONResponse` є підкласами `Response`, отже анотація типу коректна.
+
+### Анотація підкласу Response
+
+Також можна використовувати підклас `Response` у анотації типу:
+
+{* ../../docs_src/response_model/tutorial003_03.py hl[8:9] *}
+
+Це теж працюватиме, бо `RedirectResponse` — підклас `Response`, і FastAPI автоматично обробить цей простий випадок.
+
+### Некоректні анотації типу повернення
+
+Але коли Ви повертаєте якийсь інший довільний об’єкт, що не є валідним типом Pydantic (наприклад, об’єкт бази даних), і анотуєте його так у функції, FastAPI спробує створити Pydantic модель відповіді на основі цієї анотації типу, і це завершиться помилкою.
+
+Те саме станеться, якщо Ви використовуєте
union між різними типами, де один або більше не є валідними типами Pydantic, наприклад, це спричинить помилку 💥:
+
+{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}
+
+...це не працює, тому що тип анотації не є типом Pydantic і не є просто класом `Response` або його підкласом, а є об’єднанням (union) — або `Response`, або `dict`.
+
+### Відключення Моделі Відповіді
+
+Продовжуючи приклад вище, можливо, Ви не хочете використовувати стандартну валідацію даних, автоматичну документацію, фільтрацію тощо, які FastAPI виконує за замовчуванням.
+
+Але ви все одно можете залишити анотацію типу у функції, щоб зберегти підтримку з боку інструментів, таких як редактори коду або статичні перевірки типів (наприклад, mypy).
+
+У такому випадку ви можете вимкнути генерацію моделі відповіді, встановивши `response_model=None`:
+
+{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}
+
+Це змусить FastAPI пропустити генерацію моделі відповіді, і таким чином Ви зможете використовувати будь-які анотації типів повернення без впливу на вашу FastAPI аплікацію. 🤓
+
+## Параметри кодування моделі відповіді
+
+Ваша модель відповіді може мати значення за замовчуванням, наприклад:
+
+{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}
+
+* `description: Union[str, None] = None` (або `str | None = None` у Python 3.10) має значення за замовчуванням `None`.
+* `tax: float = 10.5` має значення за замовчуванням `10.5`.
+* `tags: List[str] = []` має значення за замовчуванням порожній список: `[]`.
+
+Але Ви можете захотіти не включати їх у результат, якщо вони фактично не були збережені.
+
+Наприклад, якщо у Вас є моделі з багатьма необов’язковими атрибутами у NoSQL базі даних, але Ви не хочете відправляти дуже довгі JSON-відповіді, повні значень за замовчуванням.
+
+### Використовуйте параметр `response_model_exclude_unset`
+
+Ви можете встановити параметр декоратора шляху `response_model_exclude_unset=True`:
+
+{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}
+
+і ці значення за замовчуванням не будуть включені у відповідь, тільки фактично встановлені значення.
+
+Отже, якщо Ви надішлете запит до цього оператора шляху для елемента з item_id `foo`, відповідь (без включення значень за замовчуванням) буде:
+
+```JSON
+{
+ "name": "Foo",
+ "price": 50.2
+}
+```
+
+/// info | Інформація
+
+У Pydantic версії 1 метод називався `.dict()`, він був застарілий (але ще підтримується) у Pydantic версії 2 і перейменований у `.model_dump()`.
+
+Приклади тут використовують `.dict()` для сумісності з Pydantic v1, але Вам слід використовувати `.model_dump()`, якщо Ви можете використовувати Pydantic v2.
+
+///
+
+/// info | Інформація
+
+FastAPI використовує `.dict()` моделі Pydantic з
параметром `exclude_unset`, щоб досягти цього.
+
+///
+
+/// info | Інформація
+
+Ви також можете використовувати:
+
+* `response_model_exclude_defaults=True`
+* `response_model_exclude_none=True`
+
+як описано в
документації Pydantic for `exclude_defaults` та `exclude_none`.
+
+///
+
+#### Дані зі значеннями для полів із типовими значеннями
+
+Але якщо Ваші дані мають значення для полів моделі з типовими значеннями, як у елемента з item_id `bar`:
+
+```Python hl_lines="3 5"
+{
+ "name": "Bar",
+ "description": "The bartenders",
+ "price": 62,
+ "tax": 20.2
+}
+```
+вони будуть включені у відповідь.
+
+#### Дані з тими самими значеннями, що й типові
+
+Якщо дані мають ті самі значення, що й типові, як у елемента з item_id `baz`:
+
+```Python hl_lines="3 5-6"
+{
+ "name": "Baz",
+ "description": None,
+ "price": 50.2,
+ "tax": 10.5,
+ "tags": []
+}
+```
+
+FastAPI достатньо розумний (насправді, Pydantic достатньо розумний), щоб зрозуміти, що, хоча `description`, `tax` і `tags` мають ті самі значення, що й типові, вони були встановлені явно (а не взяті як значення за замовчуванням).
+
+Отже, вони будуть включені у JSON-відповідь.
+
+/// tip | Порада
+
+Зверніть увагу, що типові значення можуть бути будь-якими, не лише `None`.
+
+Це може бути list (`[]`), `float` 10.5 тощо.
+
+///
+
+### `response_model_include` та `response_model_exclude`
+
+Ви також можете використовувати параметри *декоратора операції шляху* `response_model_include` та `response_model_exclude`.
+
+Вони приймають `set` (множину) рядків (`str`) з іменами атрибутів, які потрібно включити (пропускаючи інші) або виключити (включаючи інші).
+
+Це можна використовувати як швидкий спосіб, якщо у Вас є лише одна модель Pydantic і Ви хочете видалити деякі дані з виводу.
+
+/// tip | Порада
+
+Але все ж рекомендується використовувати описані вище підходи, із застосуванням кількох класів, замість цих параметрів.
+
+
+Це тому, що JSON Schema, який генерується у вашому OpenAPI додатку (і в документації), все одно буде відповідати повній моделі, навіть якщо Ви використовуєте `response_model_include` або `response_model_exclude` для виключення деяких атрибутів.
+
+Це також стосується `response_model_by_alias`, який працює подібним чином.
+
+///
+
+{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}
+
+/// tip | Порада
+
+Синтаксис `{"name", "description"}` створює `set` з цими двома значеннями.
+
+Він еквівалентний `set(["name", "description"])`.
+
+///
+
+#### Використання `list` замість `set`
+
+Якщо Ви забудете використати `set` і натомість застосуєте `list` або `tuple`, FastAPI все одно перетворить це на `set`, і все працюватиме правильно:
+
+{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}
+
+## Підсумок
+
+Використовуйте параметр `response_model` *декоратора операції шляху*, щоб визначати моделі відповіді, особливо щоб гарантувати фільтрацію приватних даних.
+
+Використовуйте `response_model_exclude_unset`, щоб повертати лише явно встановлені значення.
diff --git a/docs/uk/docs/tutorial/schema-extra-example.md b/docs/uk/docs/tutorial/schema-extra-example.md
new file mode 100644
index 000000000..853fd5e65
--- /dev/null
+++ b/docs/uk/docs/tutorial/schema-extra-example.md
@@ -0,0 +1,222 @@
+# Декларування прикладів вхідних даних
+
+Ви можете задати приклади даних, які Ваш застосунок може отримувати.
+
+Ось кілька способів, як це зробити.
+
+## Додаткові дані JSON-схеми в моделях Pydantic
+
+Ви можете задати `examples` для моделі Pydantic, які буде додано до згенерованої JSON-схеми.
+
+//// tab | Pydantic v2
+
+{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}
+
+////
+
+//// tab | Pydantic v1
+
+{* ../../docs_src/schema_extra_example/tutorial001_pv1_py310.py hl[13:23] *}
+
+////
+
+Ця додаткова інформація буде додана як є до **JSON-схеми**, і вона буде використовуватися в документації до API.
+
+//// tab | Pydantic v2
+
+У версії Pydantic 2 використовується атрибут `model_config`, який приймає `dict`, як описано в
документації Pydantic: Конфігурація.
+
+Ви можете встановити `"json_schema_extra"` як `dict`, що містить будь-які додаткові дані, які Ви хочете відобразити у згенерованій JSON-схемі, включаючи `examples`.
+
+////
+
+//// tab | Pydantic v1
+
+У версії Pydantic 1 використовується внутрішній клас `Config` і параметр `schema_extra`, як описано в
документації Pydantic: Налаштування схеми.
+
+Ви можете задати `schema_extra` як `dict`, що містить будь-які додаткові дані, які Ви хочете бачити у згенерованій JSON-схемі, включаючи `examples`.
+
+////
+
+/// tip | Підказка
+
+Ви можете використати ту ж техніку, щоб розширити JSON-схему і додати власну додаткову інформацію.
+
+Наприклад, Ви можете використати її для додавання метаданих для інтерфейсу користувача на фронтенді тощо.
+
+///
+
+/// info | Інформація
+
+OpenAPI 3.1.0 (який використовується починаючи з FastAPI 0.99.0) додав підтримку `examples`, що є частиною стандарту **JSON-схеми**.
+
+До цього підтримувався лише ключ `example` з одним прикладом. Він все ще підтримується в OpenAPI 3.1.0, але є застарілим і не входить до стандарту JSON Schema. Тому рекомендується перейти з `example` на `examples`. 🤓
+
+Більше про це можна прочитати в кінці цієї сторінки.
+
+///
+
+## Додаткові аргументи `Field`
+
+Коли ви використовуєте `Field()` у моделях Pydantic, Ви також можете вказати додаткові `examples`:
+
+{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}
+
+## `examples` у JSON-схемі — OpenAPI
+
+При використанні будь-кого з наступного:
+
+* `Path()`
+* `Query()`
+* `Header()`
+* `Cookie()`
+* `Body()`
+* `Form()`
+* `File()`
+
+Ви також можете задати набір `examples` з додатковою інформацією, яка буде додана до їхніх **JSON-схем** у **OpenAPI**.
+
+### `Body` з `examples`
+
+Тут ми передаємо `examples`, які містять один приклад очікуваних даних у `Body()`:
+
+{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *}
+
+### Приклад у UI документації
+
+За допомогою будь-якого з наведених вище методів це виглядатиме так у документації за `/docs`:
+
+

+
+### `Body` з кількома `examples`
+
+Звичайно, Ви також можете передати кілька `examples`:
+
+{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *}
+
+Коли Ви це робите, приклади будуть частиною внутрішньої **JSON-схеми** для цих даних.
+
+Втім, на момент написання цього (
26 серпня 2023), Swagger UI — інструмент, який відповідає за відображення UI документації — не підтримує показ кількох прикладів у **JSON-схеми**. Але нижче можна прочитати про обхідний шлях.
+
+### Специфічні для OpenAPI `examples`
+
+Ще до того, як **JSON-схема** почала підтримувати `examples`, OpenAPI вже мала підтримку поля з такою ж назвою — `examples`.
+
+Це **специфічне для OpenAPI** поле `examples` розміщується в іншій частині специфікації OpenAPI — у **деталях кожної *операції шляху***, а не всередині самої JSON-схеми.
+
+Swagger UI вже давно підтримує це поле `examples`. Тому Ви можете використовувати його, щоб **відображати** кілька **прикладів у документації**.
+
+Це поле `examples` у специфікації OpenAPI — це `dict` (словник) з **кількома прикладами** (а не список `list`), кожен із яких може містити додаткову інформацію, що буде додана до **OpenAPI**.
+
+Воно не включається до JSON Schema кожного параметра, а розміщується зовні, безпосередньо в *операції шляху*.
+
+### Використання параметра `openapi_examples`
+
+Ви можете оголосити специфічні для OpenAPI `examples` у FastAPI за допомогою параметра `openapi_examples` для:
+
+* `Path()`
+* `Query()`
+* `Header()`
+* `Cookie()`
+* `Body()`
+* `Form()`
+* `File()`
+
+Ключі словника (`dict`) ідентифікують кожен приклад, а кожне значення `dict` — кожен специфічний словник `dict` в `examples` може містити:
+
+* `summary`: короткий опис прикладу.
+* `description`: розгорнутий опис (може містити Markdown).
+* `value`: сам приклад, наприклад, словник (`dict`).
+* `externalValue`: альтернатива `value`, URL-адреса, що вказує на приклад. Проте ця опція може не підтримуватися більшістю інструментів, на відміну від `value`.
+
+Використання виглядає так:
+
+{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}
+
+### Приклади OpenAPI у UI документації
+
+З параметром `openapi_examples`, доданим до `Body()`, документація `/docs` виглядатиме так:
+
+

+
+## Технічні деталі
+
+/// tip | Підказка
+
+Якщо Ви вже використовуєте **FastAPI** версії **0.99.0 або вище**, Ви можете **пропустити** цей розділ.
+
+Він більш актуальний для старих версій, до появи OpenAPI 3.1.0.
+
+Можна вважати це коротким **історичним екскурсом** у OpenAPI та JSON Schema. 🤓
+
+///
+
+/// warning | Попередження
+
+Це дуже технічна інформація про стандарти **JSON Schema** і **OpenAPI**.
+
+Якщо вищезгадані ідеї вже працюють у Вас — можете не заглиблюватися в ці деталі.
+
+///
+
+До OpenAPI 3.1.0 специфікація використовувала стару та модифіковану версію **JSON Schema**.
+
+Оскільки JSON Schema раніше не підтримувала `examples`, OpenAPI додала власне поле `examples`.
+
+OpenAPI також додала `example` і `examples` до інших частин специфікації:
+
+*
`Parameter Object` (в специфікації) використовується FastAPI для:
+ * `Path()`
+ * `Query()`
+ * `Header()`
+ * `Cookie()`
+*
`Request Body Object`, в полі `content`, в `Media Type Object` (в специфікації) використовується FastAPI для:
+ * `Body()`
+ * `File()`
+ * `Form()`
+
+/// info | Інформація
+
+Цей старий параметр `examples`, специфічний для OpenAPI, тепер називається `openapi_examples`, починаючи з FastAPI версії `0.103.0`.
+
+///
+
+### Поле `examples` у JSON Schema
+
+Пізніше JSON Schema додала поле
`examples` у нову версію специфікації.
+
+І вже OpenAPI 3.1.0 базується на цій новій версії (JSON Schema 2020-12), яка включає поле `examples`.
+
+Тепер це поле `examples` є пріоритетним і замінює старе (і кастомне) поле `example`, яке стало застарілим.
+
+Нове поле `examples` у JSON Schema — це **просто список (`list`)** прикладів, без додаткових метаданих (на відміну від OpenAPI).
+
+/// info | Інформація
+
+Навіть після того, як з'явився OpenAPI 3.1.0, який підтримував examples у JSON Schema, інструмент Swagger UI ще деякий час не підтримував цю версію (підтримка з’явилась з версії 5.0.0 🎉).
+
+Через це версії FastAPI до 0.99.0 все ще використовували версії OpenAPI нижчі за 3.1.0.
+
+///
+
+### `Examples` в Pydantic і FastAPI
+
+Коли Ви додаєте `examples` у модель Pydantic через `schema_extra` або `Field(examples=["something"])`, ці приклади додаються до **JSON Schema** цієї моделі.
+
+І ця **JSON Schema** Pydantic-моделі включається до **OpenAPI** Вашого API, а потім використовується в UI документації (docs UI).
+
+У версіях FastAPI до 0.99.0 (починаючи з 0.99.0 використовується новіший OpenAPI 3.1.0), коли Ви використовували `example` або `examples` з іншими утилітами (`Query()`, `Body()` тощо), ці приклади не додавалися до JSON Schema, який описує ці дані (навіть не до власної версії JSON Schema у OpenAPI). Натомість вони додавалися безпосередньо до опису *обробника шляху* *(path operation)* в OpenAPI (тобто поза межами частин, які використовують JSON Schema).
+
+Але тепер, коли FastAPI 0.99.0 і вище використовують OpenAPI 3.1.0, а той — JSON Schema 2020-12, разом із Swagger UI 5.0.0 і вище — все стало більш узгодженим, і examples тепер включаються до JSON Schema.
+
+### Swagger UI та специфічні для OpenAPI `examples`
+
+Раніше (станом на 26 серпня 2023 року) Swagger UI не підтримував кілька прикладів у JSON Schema, тому користувачі не мали можливості показати декілька прикладів у документації.
+
+Щоб вирішити це, FastAPI починаючи з версії 0.103.0 **додав підтримку** старого **OpenAPI-специфічного** поля `examples` через новий параметр `openapi_examples`. 🤓
+
+### Підсумок
+
+Раніше я казав, що не люблю історію... а тепер ось я — розповідаю "технічні історичні" лекції. 😅
+
+Коротко: **оновіться до FastAPI 0.99.0 або вище** — і все стане значно **простішим, узгодженим та інтуїтивно зрозумілим**, і Вам не доведеться знати всі ці історичні деталі. 😎
diff --git a/docs/uk/docs/tutorial/security/index.md b/docs/uk/docs/tutorial/security/index.md
new file mode 100644
index 000000000..c3d94be8d
--- /dev/null
+++ b/docs/uk/docs/tutorial/security/index.md
@@ -0,0 +1,104 @@
+# Безпека
+
+Існує багато способів реалізувати безпеку, автентифікацію та авторизацію.
+
+Це зазвичай складна і "непроста" тема.
+
+У багатьох фреймворках і системах забезпечення безпеки та автентифікації займає величезну частину зусиль і коду (іноді — понад 50% всього написаного коду).
+
+**FastAPI** надає кілька інструментів, які допоможуть Вам впоратися з **безпекою** легко, швидко, стандартним способом, без необхідності вивчати всі специфікації безпеки.
+
+Але спочатку — кілька коротких понять.
+
+## Поспішаєте?
+
+Якщо Вам не цікаві всі ці терміни й просто потрібно *швидко* додати автентифікацію за логіном і паролем — переходьте до наступних розділів.
+
+## OAuth2
+
+OAuth2 — це специфікація, що описує кілька способів обробки автентифікації та авторизації.
+
+Це досить об'ємна специфікація, яка охоплює складні випадки використання.
+
+Вона включає способи автентифікації через "третю сторону".
+
+Саме це лежить в основі "входу через Google, Facebook, X (Twitter), GitHub" тощо.
+
+### OAuth 1
+
+Раніше існував OAuth 1, який значно відрізняється від OAuth2 і є складнішим, оскільки містив специфікації для шифрування комунікацій.
+
+Зараз майже не використовується.
+
+OAuth2 не вказує, як саме шифрувати з'єднання — воно очікує, що ваш застосунок працює через HTTPS.
+
+/// tip | Порада
+
+У розділі про **деплой** Ви побачите, як налаштувати HTTPS безкоштовно з Traefik та Let's Encrypt.
+
+///
+
+## OpenID Connect
+
+OpenID Connect — ще одна специфікація, побудована на основі **OAuth2**.
+
+Вона розширює OAuth2, уточнюючи деякі неоднозначності для досягнення кращої сумісності.
+
+Наприклад, вхід через Google використовує OpenID Connect (який базується на OAuth2).
+
+Але вхід через Facebook — ні. Він має власну реалізацію на базі OAuth2.
+
+### OpenID (не "OpenID Connect")
+
+Існувала також специфікація "OpenID", яка намагалася розвʼязати ті самі задачі, що й **OpenID Connect**, але не базувалась на OAuth2.
+
+Це була зовсім інша система, і сьогодні вона майже не використовується.
+
+## OpenAPI
+
+OpenAPI (раніше Swagger) — це специфікація для побудови API (тепер під егідою Linux Foundation).
+
+**FastAPI** базується на **OpenAPI**.
+
+Завдяки цьому Ви отримуєте автоматичну інтерактивну документацію, генерацію коду та багато іншого.
+
+OpenAPI дозволяє описувати різні "схеми" безпеки.
+
+Використовуючи їх, Ви можете скористатися всіма цими інструментами, що базуються на стандартах, зокрема інтерактивними системами документації.
+
+OpenAPI визначає такі схеми безпеки:
+
+* `apiKey`: специфічний для застосунку ключ, який може передаватися через:
+ * Параметр запиту.
+ * Заголовок.
+ * Cookie.
+* `http`: стандартні методи HTTP-автентифікації, включаючи:
+ * `bearer`: заголовок `Authorization` зі значенням `Bearer` та токеном. Це успадковано з OAuth2.
+ * HTTP Basic автентифікація
+ * HTTP Digest, тощо.
+* `oauth2`: усі способи обробки безпеки за допомогою OAuth2 (так звані «потоки»).
+ * Деякі з цих потоків підходять для створення власного провайдера автентифікації OAuth 2.0 (наприклад, Google, Facebook, X (Twitter), GitHub тощо):
+ * `implicit`— неявний
+ * `clientCredentials`— облікові дані клієнта
+ * `authorizationCode` — код авторизації
+ * Але є один окремий «потік», який ідеально підходить для реалізації автентифікації всередині одного додатку:
+ * `password`: у наступних розділах буде приклад використання цього потоку.
+* `openIdConnect`: дозволяє автоматично виявляти параметри автентифікації OAuth2.
+ * Це автоматичне виявлення визначається у специфікації OpenID Connect.
+
+
+/// tip | Порада
+
+Інтеграція інших провайдерів автентифікації/авторизації, таких як Google, Facebook, X (Twitter), GitHub тощо — також можлива і відносно проста.
+
+Найскладніше — це створити власного провайдера автентифікації/авторизації, як Google чи Facebook. Але **FastAPI** надає Вам інструменти, щоб зробити це легко, беручи на себе важку частину роботи.
+
+///
+
+## Інструменти **FastAPI**
+
+FastAPI надає кілька інструментів для кожної з описаних схем безпеки в модулі `fastapi.security`, які спрощують використання цих механізмів захисту.
+
+У наступних розділах Ви побачите, як додати безпеку до свого API за допомогою цих інструментів **FastAPI**.
+
+А також побачите, як вона автоматично інтегрується в інтерактивну документацію вашого API.
diff --git a/docs/zh/docs/python-types.md b/docs/zh/docs/python-types.md
index 5126cb847..ba767da87 100644
--- a/docs/zh/docs/python-types.md
+++ b/docs/zh/docs/python-types.md
@@ -228,7 +228,7 @@ John Doe
## Pydantic 模型
-
Pydantic 是一个用来用来执行数据校验的 Python 库。
+
Pydantic 是一个用来执行数据校验的 Python 库。
你可以将数据的"结构"声明为具有属性的类。
diff --git a/fastapi/__init__.py b/fastapi/__init__.py
index 80eb783da..e672ec9e5 100644
--- a/fastapi/__init__.py
+++ b/fastapi/__init__.py
@@ -1,6 +1,6 @@
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
-__version__ = "0.115.12"
+__version__ = "0.115.14"
from starlette import status as status
diff --git a/fastapi/_compat.py b/fastapi/_compat.py
index c07e4a3b0..227ad837d 100644
--- a/fastapi/_compat.py
+++ b/fastapi/_compat.py
@@ -16,6 +16,7 @@ from typing import (
Tuple,
Type,
Union,
+ cast,
)
from fastapi.exceptions import RequestErrorModel
@@ -231,6 +232,10 @@ if PYDANTIC_V2:
field_mapping, definitions = schema_generator.generate_definitions(
inputs=inputs
)
+ for item_def in cast(Dict[str, Dict[str, Any]], definitions).values():
+ if "description" in item_def:
+ item_description = cast(str, item_def["description"]).split("\f")[0]
+ item_def["description"] = item_description
return field_mapping, definitions # type: ignore[return-value]
def is_scalar_field(field: ModelField) -> bool:
diff --git a/fastapi/applications.py b/fastapi/applications.py
index 6d427cdc2..05c7bd2be 100644
--- a/fastapi/applications.py
+++ b/fastapi/applications.py
@@ -748,7 +748,7 @@ class FastAPI(Starlette):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@@ -1720,7 +1720,7 @@ class FastAPI(Starlette):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@@ -2093,7 +2093,7 @@ class FastAPI(Starlette):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@@ -2471,7 +2471,7 @@ class FastAPI(Starlette):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@@ -2849,7 +2849,7 @@ class FastAPI(Starlette):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@@ -3222,7 +3222,7 @@ class FastAPI(Starlette):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@@ -3595,7 +3595,7 @@ class FastAPI(Starlette):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@@ -3968,7 +3968,7 @@ class FastAPI(Starlette):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@@ -4346,7 +4346,7 @@ class FastAPI(Starlette):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@@ -4425,7 +4425,7 @@ class FastAPI(Starlette):
app = FastAPI()
- @app.put("/items/{item_id}")
+ @app.trace("/items/{item_id}")
def trace_item(item_id: str):
return None
```
@@ -4515,14 +4515,17 @@ class FastAPI(Starlette):
```python
import time
+ from typing import Awaitable, Callable
- from fastapi import FastAPI, Request
+ from fastapi import FastAPI, Request, Response
app = FastAPI()
@app.middleware("http")
- async def add_process_time_header(request: Request, call_next):
+ async def add_process_time_header(
+ request: Request, call_next: Callable[[Request], Awaitable[Response]]
+ ) -> Response:
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py
index 84dfa4d03..081b63a8b 100644
--- a/fastapi/dependencies/utils.py
+++ b/fastapi/dependencies/utils.py
@@ -816,6 +816,25 @@ def request_params_to_args(
return values, errors
+def is_union_of_base_models(field_type: Any) -> bool:
+ """Check if field type is a Union where all members are BaseModel subclasses."""
+ from fastapi.types import UnionType
+
+ origin = get_origin(field_type)
+
+ # Check if it's a Union type (covers both typing.Union and types.UnionType in Python 3.10+)
+ if origin is not Union and origin is not UnionType:
+ return False
+
+ union_args = get_args(field_type)
+
+ for arg in union_args:
+ if not lenient_issubclass(arg, BaseModel):
+ return False
+
+ return True
+
+
def _should_embed_body_fields(fields: List[ModelField]) -> bool:
if not fields:
return False
@@ -829,10 +848,12 @@ def _should_embed_body_fields(fields: List[ModelField]) -> bool:
# If it explicitly specifies it is embedded, it has to be embedded
if getattr(first_field.field_info, "embed", None):
return True
- # If it's a Form (or File) field, it has to be a BaseModel to be top level
+ # If it's a Form (or File) field, it has to be a BaseModel (or a union of BaseModels) to be top level
# otherwise it has to be embedded, so that the key value pair can be extracted
- if isinstance(first_field.field_info, params.Form) and not lenient_issubclass(
- first_field.type_, BaseModel
+ if (
+ isinstance(first_field.field_info, params.Form)
+ and not lenient_issubclass(first_field.type_, BaseModel)
+ and not is_union_of_base_models(first_field.type_)
):
return True
return False
diff --git a/fastapi/routing.py b/fastapi/routing.py
index 457481e32..bf61a65c1 100644
--- a/fastapi/routing.py
+++ b/fastapi/routing.py
@@ -814,7 +814,7 @@ class APIRouter(routing.Router):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@@ -1626,7 +1626,7 @@ class APIRouter(routing.Router):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@@ -2003,7 +2003,7 @@ class APIRouter(routing.Router):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@@ -2385,7 +2385,7 @@ class APIRouter(routing.Router):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@@ -2767,7 +2767,7 @@ class APIRouter(routing.Router):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@@ -3144,7 +3144,7 @@ class APIRouter(routing.Router):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@@ -3521,7 +3521,7 @@ class APIRouter(routing.Router):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@@ -3903,7 +3903,7 @@ class APIRouter(routing.Router):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@@ -4285,7 +4285,7 @@ class APIRouter(routing.Router):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
- [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
diff --git a/fastapi/security/oauth2.py b/fastapi/security/oauth2.py
index 5ffad5986..88e394db1 100644
--- a/fastapi/security/oauth2.py
+++ b/fastapi/security/oauth2.py
@@ -85,7 +85,7 @@ class OAuth2PasswordRequestForm:
],
password: Annotated[
str,
- Form(),
+ Form(json_schema_extra={"format": "password"}),
Doc(
"""
`password` string. The OAuth2 spec requires the exact field name
@@ -130,7 +130,7 @@ class OAuth2PasswordRequestForm:
] = None,
client_secret: Annotated[
Union[str, None],
- Form(),
+ Form(json_schema_extra={"format": "password"}),
Doc(
"""
If there's a `client_password` (and a `client_id`), they can be sent
@@ -457,11 +457,26 @@ class OAuth2PasswordBearer(OAuth2):
"""
),
] = True,
+ refreshUrl: Annotated[
+ Optional[str],
+ Doc(
+ """
+ The URL to refresh the token and obtain a new one.
+ """
+ ),
+ ] = None,
):
if not scopes:
scopes = {}
flows = OAuthFlowsModel(
- password=cast(Any, {"tokenUrl": tokenUrl, "scopes": scopes})
+ password=cast(
+ Any,
+ {
+ "tokenUrl": tokenUrl,
+ "refreshUrl": refreshUrl,
+ "scopes": scopes,
+ },
+ )
)
super().__init__(
flows=flows,
diff --git a/requirements-docs.txt b/requirements-docs.txt
index bd0082304..059203ec1 100644
--- a/requirements-docs.txt
+++ b/requirements-docs.txt
@@ -1,9 +1,9 @@
-e .
-r requirements-docs-tests.txt
-mkdocs-material==9.6.1
+mkdocs-material==9.6.15
mdx-include >=1.4.1,<2.0.0
mkdocs-redirects>=1.2.1,<1.3.0
-typer == 0.15.3
+typer == 0.16.0
pyyaml >=5.3.1,<7.0.0
# For Material for MkDocs, Chinese search
jieba==0.42.1
@@ -12,7 +12,7 @@ pillow==11.1.0
# For image processing by Material for MkDocs
cairosvg==2.7.1
mkdocstrings[python]==0.26.1
-griffe-typingdoc==0.2.7
+griffe-typingdoc==0.2.8
# For griffe, it formats with black
black==25.1.0
mkdocs-macros-plugin==1.3.7
diff --git a/scripts/label_approved.py b/scripts/label_approved.py
index 271444504..81de92efb 100644
--- a/scripts/label_approved.py
+++ b/scripts/label_approved.py
@@ -27,7 +27,7 @@ if settings.debug:
logging.basicConfig(level=logging.DEBUG)
else:
logging.basicConfig(level=logging.INFO)
-logging.debug(f"Using config: {settings.json()}")
+logging.debug(f"Using config: {settings.model_dump_json()}")
g = Github(settings.token.get_secret_value())
repo = g.get_repo(settings.github_repository)
for pr in repo.get_pulls(state="open"):
@@ -48,7 +48,7 @@ for pr in repo.get_pulls(state="open"):
]
config = settings.config or default_config
for approved_label, conf in config.items():
- logging.debug(f"Processing config: {conf.json()}")
+ logging.debug(f"Processing config: {conf.model_dump_json()}")
if conf.await_label is None or (conf.await_label in pr_label_by_name):
logging.debug(f"Processable PR: {pr.number}")
if len(approved_reviews) >= conf.number:
diff --git a/tests/test_openapi_model_description_trim_on_formfeed.py b/tests/test_openapi_model_description_trim_on_formfeed.py
new file mode 100644
index 000000000..e18d4f6b2
--- /dev/null
+++ b/tests/test_openapi_model_description_trim_on_formfeed.py
@@ -0,0 +1,31 @@
+from fastapi import FastAPI
+from fastapi.testclient import TestClient
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class MyModel(BaseModel):
+ """
+ A model with a form feed character in the title.
+ \f
+ Text after form feed character.
+ """
+
+
+@app.get("/foo")
+def foo(v: MyModel): # pragma: no cover
+ pass
+
+
+client = TestClient(app)
+
+
+def test_openapi():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ openapi_schema = response.json()
+
+ assert openapi_schema["components"]["schemas"]["MyModel"]["description"] == (
+ "A model with a form feed character in the title.\n"
+ )
diff --git a/tests/test_tutorial/test_security/test_tutorial003.py b/tests/test_tutorial/test_security/test_tutorial003.py
index 37fc2618f..2bbb2e851 100644
--- a/tests/test_tutorial/test_security/test_tutorial003.py
+++ b/tests/test_tutorial/test_security/test_tutorial003.py
@@ -163,7 +163,11 @@ def test_openapi_schema(client: TestClient):
}
),
"username": {"title": "Username", "type": "string"},
- "password": {"title": "Password", "type": "string"},
+ "password": {
+ "title": "Password",
+ "type": "string",
+ "format": "password",
+ },
"scope": {"title": "Scope", "type": "string", "default": ""},
"client_id": IsDict(
{
@@ -179,11 +183,16 @@ def test_openapi_schema(client: TestClient):
{
"title": "Client Secret",
"anyOf": [{"type": "string"}, {"type": "null"}],
+ "format": "password",
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
- {"title": "Client Secret", "type": "string"}
+ {
+ "title": "Client Secret",
+ "type": "string",
+ "format": "password",
+ }
),
},
},
diff --git a/tests/test_tutorial/test_security/test_tutorial005.py b/tests/test_tutorial/test_security/test_tutorial005.py
index 0595c75a7..1abfdeb52 100644
--- a/tests/test_tutorial/test_security/test_tutorial005.py
+++ b/tests/test_tutorial/test_security/test_tutorial005.py
@@ -393,7 +393,11 @@ def test_openapi_schema(mod: ModuleType):
}
),
"username": {"title": "Username", "type": "string"},
- "password": {"title": "Password", "type": "string"},
+ "password": {
+ "title": "Password",
+ "type": "string",
+ "format": "password",
+ },
"scope": {"title": "Scope", "type": "string", "default": ""},
"client_id": IsDict(
{
@@ -409,11 +413,16 @@ def test_openapi_schema(mod: ModuleType):
{
"title": "Client Secret",
"anyOf": [{"type": "string"}, {"type": "null"}],
+ "format": "password",
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
- {"title": "Client Secret", "type": "string"}
+ {
+ "title": "Client Secret",
+ "type": "string",
+ "format": "password",
+ }
),
},
},
diff --git a/tests/test_tutorial/test_settings/test_tutorial001.py b/tests/test_tutorial/test_settings/test_tutorial001.py
index eb30dbcee..92a5782d4 100644
--- a/tests/test_tutorial/test_settings/test_tutorial001.py
+++ b/tests/test_tutorial/test_settings/test_tutorial001.py
@@ -1,14 +1,26 @@
+import importlib
+
+import pytest
from fastapi.testclient import TestClient
from pytest import MonkeyPatch
-from ...utils import needs_pydanticv2
+from ...utils import needs_pydanticv1, needs_pydanticv2
-@needs_pydanticv2
-def test_settings(monkeypatch: MonkeyPatch):
+@pytest.fixture(
+ name="app",
+ params=[
+ pytest.param("tutorial001", marks=needs_pydanticv2),
+ pytest.param("tutorial001_pv1", marks=needs_pydanticv1),
+ ],
+)
+def get_app(request: pytest.FixtureRequest, monkeypatch: MonkeyPatch):
monkeypatch.setenv("ADMIN_EMAIL", "admin@example.com")
- from docs_src.settings.tutorial001 import app
+ mod = importlib.import_module(f"docs_src.settings.{request.param}")
+ return mod.app
+
+def test_settings(app):
client = TestClient(app)
response = client.get("/info")
assert response.status_code == 200, response.text
diff --git a/tests/test_tutorial/test_settings/test_tutorial001_pv1.py b/tests/test_tutorial/test_settings/test_tutorial001_pv1.py
deleted file mode 100644
index e4659de66..000000000
--- a/tests/test_tutorial/test_settings/test_tutorial001_pv1.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from fastapi.testclient import TestClient
-from pytest import MonkeyPatch
-
-from ...utils import needs_pydanticv1
-
-
-@needs_pydanticv1
-def test_settings(monkeypatch: MonkeyPatch):
- monkeypatch.setenv("ADMIN_EMAIL", "admin@example.com")
- from docs_src.settings.tutorial001_pv1 import app
-
- client = TestClient(app)
- response = client.get("/info")
- assert response.status_code == 200, response.text
- assert response.json() == {
- "app_name": "Awesome API",
- "admin_email": "admin@example.com",
- "items_per_user": 50,
- }
diff --git a/tests/test_union_forms.py b/tests/test_union_forms.py
new file mode 100644
index 000000000..cbe98ea82
--- /dev/null
+++ b/tests/test_union_forms.py
@@ -0,0 +1,156 @@
+from typing import Union
+
+from fastapi import FastAPI, Form
+from fastapi.testclient import TestClient
+from pydantic import BaseModel
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+class UserForm(BaseModel):
+ name: str
+ email: str
+
+
+class CompanyForm(BaseModel):
+ company_name: str
+ industry: str
+
+
+@app.post("/form-union/")
+def post_union_form(data: Annotated[Union[UserForm, CompanyForm], Form()]):
+ return {"received": data}
+
+
+client = TestClient(app)
+
+
+def test_post_user_form():
+ response = client.post(
+ "/form-union/", data={"name": "John Doe", "email": "john@example.com"}
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "received": {"name": "John Doe", "email": "john@example.com"}
+ }
+
+
+def test_post_company_form():
+ response = client.post(
+ "/form-union/", data={"company_name": "Tech Corp", "industry": "Technology"}
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "received": {"company_name": "Tech Corp", "industry": "Technology"}
+ }
+
+
+def test_invalid_form_data():
+ response = client.post(
+ "/form-union/",
+ data={"name": "John", "company_name": "Tech Corp"},
+ )
+ assert response.status_code == 422, response.text
+
+
+def test_empty_form():
+ response = client.post("/form-union/")
+ assert response.status_code == 422, response.text
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+
+ assert response.json() == {
+ "openapi": "3.1.0",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/form-union/": {
+ "post": {
+ "summary": "Post Union Form",
+ "operationId": "post_union_form_form_union__post",
+ "requestBody": {
+ "content": {
+ "application/x-www-form-urlencoded": {
+ "schema": {
+ "anyOf": [
+ {"$ref": "#/components/schemas/UserForm"},
+ {"$ref": "#/components/schemas/CompanyForm"},
+ ],
+ "title": "Data",
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "CompanyForm": {
+ "properties": {
+ "company_name": {"type": "string", "title": "Company Name"},
+ "industry": {"type": "string", "title": "Industry"},
+ },
+ "type": "object",
+ "required": ["company_name", "industry"],
+ "title": "CompanyForm",
+ },
+ "HTTPValidationError": {
+ "properties": {
+ "detail": {
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ "type": "array",
+ "title": "Detail",
+ }
+ },
+ "type": "object",
+ "title": "HTTPValidationError",
+ },
+ "UserForm": {
+ "properties": {
+ "name": {"type": "string", "title": "Name"},
+ "email": {"type": "string", "title": "Email"},
+ },
+ "type": "object",
+ "required": ["name", "email"],
+ "title": "UserForm",
+ },
+ "ValidationError": {
+ "properties": {
+ "loc": {
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ "type": "array",
+ "title": "Location",
+ },
+ "msg": {"type": "string", "title": "Message"},
+ "type": {"type": "string", "title": "Error Type"},
+ },
+ "type": "object",
+ "required": ["loc", "msg", "type"],
+ "title": "ValidationError",
+ },
+ }
+ },
+ }
diff --git a/tests/test_validate_response_recursive/app_pv1.py b/tests/test_validate_response_recursive/app.py
similarity index 79%
rename from tests/test_validate_response_recursive/app_pv1.py
rename to tests/test_validate_response_recursive/app.py
index 4cfc4b3ee..d23d27980 100644
--- a/tests/test_validate_response_recursive/app_pv1.py
+++ b/tests/test_validate_response_recursive/app.py
@@ -1,6 +1,7 @@
from typing import List
from fastapi import FastAPI
+from fastapi._compat import PYDANTIC_V2
from pydantic import BaseModel
app = FastAPI()
@@ -11,9 +12,6 @@ class RecursiveItem(BaseModel):
name: str
-RecursiveItem.update_forward_refs()
-
-
class RecursiveSubitemInSubmodel(BaseModel):
sub_items2: List["RecursiveItemViaSubmodel"] = []
name: str
@@ -24,7 +22,13 @@ class RecursiveItemViaSubmodel(BaseModel):
name: str
-RecursiveSubitemInSubmodel.update_forward_refs()
+if PYDANTIC_V2:
+ RecursiveItem.model_rebuild()
+ RecursiveSubitemInSubmodel.model_rebuild()
+ RecursiveItemViaSubmodel.model_rebuild()
+else:
+ RecursiveItem.update_forward_refs()
+ RecursiveSubitemInSubmodel.update_forward_refs()
@app.get("/items/recursive", response_model=RecursiveItem)
diff --git a/tests/test_validate_response_recursive/app_pv2.py b/tests/test_validate_response_recursive/app_pv2.py
deleted file mode 100644
index 8c93a8349..000000000
--- a/tests/test_validate_response_recursive/app_pv2.py
+++ /dev/null
@@ -1,51 +0,0 @@
-from typing import List
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class RecursiveItem(BaseModel):
- sub_items: List["RecursiveItem"] = []
- name: str
-
-
-RecursiveItem.model_rebuild()
-
-
-class RecursiveSubitemInSubmodel(BaseModel):
- sub_items2: List["RecursiveItemViaSubmodel"] = []
- name: str
-
-
-class RecursiveItemViaSubmodel(BaseModel):
- sub_items1: List[RecursiveSubitemInSubmodel] = []
- name: str
-
-
-RecursiveSubitemInSubmodel.model_rebuild()
-RecursiveItemViaSubmodel.model_rebuild()
-
-
-@app.get("/items/recursive", response_model=RecursiveItem)
-def get_recursive():
- return {"name": "item", "sub_items": [{"name": "subitem", "sub_items": []}]}
-
-
-@app.get("/items/recursive-submodel", response_model=RecursiveItemViaSubmodel)
-def get_recursive_submodel():
- return {
- "name": "item",
- "sub_items1": [
- {
- "name": "subitem",
- "sub_items2": [
- {
- "name": "subsubitem",
- "sub_items1": [{"name": "subsubsubitem", "sub_items2": []}],
- }
- ],
- }
- ],
- }
diff --git a/tests/test_validate_response_recursive/test_validate_response_recursive_pv2.py b/tests/test_validate_response_recursive/test_validate_response_recursive.py
similarity index 90%
rename from tests/test_validate_response_recursive/test_validate_response_recursive_pv2.py
rename to tests/test_validate_response_recursive/test_validate_response_recursive.py
index 7d45e7fe4..21a299ab8 100644
--- a/tests/test_validate_response_recursive/test_validate_response_recursive_pv2.py
+++ b/tests/test_validate_response_recursive/test_validate_response_recursive.py
@@ -1,12 +1,9 @@
from fastapi.testclient import TestClient
-from ..utils import needs_pydanticv2
+from .app import app
-@needs_pydanticv2
def test_recursive():
- from .app_pv2 import app
-
client = TestClient(app)
response = client.get("/items/recursive")
assert response.status_code == 200, response.text
diff --git a/tests/test_validate_response_recursive/test_validate_response_recursive_pv1.py b/tests/test_validate_response_recursive/test_validate_response_recursive_pv1.py
deleted file mode 100644
index de578ae03..000000000
--- a/tests/test_validate_response_recursive/test_validate_response_recursive_pv1.py
+++ /dev/null
@@ -1,33 +0,0 @@
-from fastapi.testclient import TestClient
-
-from ..utils import needs_pydanticv1
-
-
-@needs_pydanticv1
-def test_recursive():
- from .app_pv1 import app
-
- client = TestClient(app)
- response = client.get("/items/recursive")
- assert response.status_code == 200, response.text
- assert response.json() == {
- "sub_items": [{"name": "subitem", "sub_items": []}],
- "name": "item",
- }
-
- response = client.get("/items/recursive-submodel")
- assert response.status_code == 200, response.text
- assert response.json() == {
- "name": "item",
- "sub_items1": [
- {
- "name": "subitem",
- "sub_items2": [
- {
- "name": "subsubitem",
- "sub_items1": [{"name": "subsubsubitem", "sub_items2": []}],
- }
- ],
- }
- ],
- }