* `bar` как `str`
* `baz` как `list`
-* Учебник — Руководство пользователя
+* Учебник - Руководство пользователя
* Расширенное руководство пользователя
* Документация по SQLModel
* Документация API
* библиотека
* lifespan
* блокировка
-* middleware (Ð\9fромежуточный слой)
+* middleware (промежуточный слой)
* мобильное приложение
* модуль
* монтирование
# Дополнительные статус-коды { #additional-status-codes }
+
По умолчанию **FastAPI** будет возвращать ответы, используя `JSONResponse`, помещая содержимое, которое вы возвращаете из вашей *операции пути*, внутрь этого `JSONResponse`.
Он будет использовать статус-код по умолчанию или тот, который вы укажете в вашей *операции пути*.
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}
-Так мы «параметризуем» нашу зависимость: теперь внутри неё хранится "bar" в атрибуте `checker.fixed_content`.
+Так мы «параметризуем» нашу зависимость: теперь внутри неё хранится `"bar"` в атрибуте `checker.fixed_content`.
## Используем экземпляр как зависимость { #use-the-instance-as-a-dependency }
checker(q="somequery")
```
-â\80¦Ð¸ пеÑ\80едаÑ\81Ñ\82 возвÑ\80аÑ\89Ñ\91нное знаÑ\87ение как знаÑ\87ение завиÑ\81имоÑ\81Ñ\82и в паÑ\80амеÑ\82Ñ\80 `fixed_content_included` наÑ\88ей *Ñ\84Ñ\83нкÑ\86ии-обÑ\80абоÑ\82Ñ\87икÑ\83 пÑ\83Ñ\82и*:
+â\80¦Ð¸ пеÑ\80едаÑ\81Ñ\82 возвÑ\80аÑ\89Ñ\91нное знаÑ\87ение как знаÑ\87ение завиÑ\81имоÑ\81Ñ\82и в наÑ\88Ñ\83 *Ñ\84Ñ\83нкÑ\86иÑ\8e-обÑ\80абоÑ\82Ñ\87ик пÑ\83Ñ\82и* в паÑ\80амеÑ\82Ñ\80 `fixed_content_included`:
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}
И, конечно, поддерживаются те же возможности:
-- валидация данных
-- сериализация данных
-- документирование данных и т.д.
+* валидация данных
+* сериализация данных
+* документирование данных и т.д.
Это работает так же, как с Pydantic-моделями. И на самом деле под капотом это достигается тем же образом, с использованием Pydantic.
# События lifespan { #lifespan-events }
-Вы можете определить логику (код), которую нужно выполнить перед тем, как приложение начнет запускаться. Это означает, что этот код будет выполнен один раз, перед тем как приложение начнет получать HTTP-запросы.
+Вы можете определить логику (код), которую нужно выполнить перед тем, как приложение **запустится**. Это означает, что этот код будет выполнен **один раз**, **перед** тем как приложение **начнет получать HTTP-запросы**.
-Аналогично, вы можете определить логику (код), которую нужно выполнить, когда приложение завершает работу. В этом случае код будет выполнен один раз, после обработки, возможно, многих запросов.
+Аналогично, вы можете определить логику (код), которую нужно выполнить, когда приложение **завершает работу**. В этом случае код будет выполнен **один раз**, **после обработки**, возможно, **многих HTTP-запросов**.
-Поскольку этот код выполняется до того, как приложение начинает принимать запросы, и сразу после того, как оно заканчивает их обрабатывать, он охватывает весь lifespan (жизненный цикл) приложения (слово «lifespan» станет важным через секунду 😉).
+Поскольку этот код выполняется до того, как приложение **начинает** принимать HTTP-запросы, и сразу после того, как оно **заканчивает** их обрабатывать, он охватывает весь **lifespan** (жизненный цикл) приложения (слово «lifespan» станет важным через секунду 😉).
-Это может быть очень полезно для настройки ресурсов, которые нужны для всего приложения, которые разделяются между запросами и/или которые нужно затем очистить. Например, пул подключений к базе данных или загрузка общей модели Машинного обучения.
+Это может быть очень полезно для настройки **ресурсов**, которые нужны для всего приложения, которые **разделяются** между HTTP-запросами и/или которые нужно затем **очистить**. Например, пул подключений к базе данных или загрузка общей модели Машинного обучения.
## Вариант использования { #use-case }
-Начнем с примера варианта использования, а затем посмотрим, как это решить.
+Начнем с примера **варианта использования**, а затем посмотрим, как это решить.
-Представим, что у вас есть несколько моделей Машинного обучения, которые вы хотите использовать для обработки запросов. 🤖
+Представим, что у вас есть несколько **моделей Машинного обучения**, которые вы хотите использовать для обработки HTTP-запросов. 🤖
-Эти же модели разделяются между запросами, то есть это не одна модель на запрос, не одна на пользователя и т.п.
+Эти же модели разделяются между HTTP-запросами, то есть это не одна модель на HTTP-запрос, не одна на пользователя и т.п.
-Представим, что загрузка модели может занимать довольно много времени, потому что ей нужно прочитать много данных с диска. Поэтому вы не хотите делать это для каждого запроса.
+Представим, что загрузка модели может **занимать довольно много времени**, потому что ей нужно прочитать много **данных с диска**. Поэтому вы не хотите делать это для каждого HTTP-запроса.
-Ð\92Ñ\8b могли бÑ\8b загÑ\80Ñ\83зиÑ\82Ñ\8c еÑ\91 на веÑ\80Ñ\85нем Ñ\83Ñ\80овне модÑ\83лÑ\8f/Ñ\84айла, но Ñ\8dÑ\82о ознаÑ\87ало бÑ\8b, Ñ\87Ñ\82о моделÑ\8c загÑ\80Ñ\83жаеÑ\82Ñ\81Ñ\8f даже еÑ\81ли вÑ\8b пÑ\80оÑ\81Ñ\82о запÑ\83Ñ\81каеÑ\82е пÑ\80оÑ\81Ñ\82ой авÑ\82омаÑ\82иÑ\87еÑ\81кий Ñ\82еÑ\81Ñ\82; Ñ\82огда Ñ\8dÑ\82оÑ\82 Ñ\82еÑ\81Ñ\82 бÑ\83деÑ\82 медленнÑ\8bм, так как ему придется ждать загрузки модели перед запуском независимой части кода.
+Ð\92Ñ\8b могли бÑ\8b загÑ\80Ñ\83зиÑ\82Ñ\8c еÑ\91 на веÑ\80Ñ\85нем Ñ\83Ñ\80овне модÑ\83лÑ\8f/Ñ\84айла, но Ñ\8dÑ\82о ознаÑ\87ало бÑ\8b, Ñ\87Ñ\82о моделÑ\8c бÑ\83деÑ\82 **загÑ\80Ñ\83жаÑ\82Ñ\8cÑ\81Ñ\8f** даже еÑ\81ли вÑ\8b пÑ\80оÑ\81Ñ\82о запÑ\83Ñ\81каеÑ\82е пÑ\80оÑ\81Ñ\82ой авÑ\82омаÑ\82иÑ\87еÑ\81кий Ñ\82еÑ\81Ñ\82; Ñ\82огда Ñ\8dÑ\82оÑ\82 Ñ\82еÑ\81Ñ\82 бÑ\83деÑ\82 **медленнÑ\8bм**, так как ему придется ждать загрузки модели перед запуском независимой части кода.
-Именно это мы и решим: давайте загружать модель перед тем, как начнётся обработка запросов, но только непосредственно перед тем, как приложение начнет принимать запросы, а не во время загрузки кода.
+Именно это мы и решим: давайте загружать модель перед тем, как начнётся обработка HTTP-запросов, но только непосредственно перед тем, как приложение начнет принимать HTTP-запросы, а не во время загрузки кода.
## Lifespan { #lifespan }
-Вы можете определить логику для startup и shutdown, используя параметр `lifespan` приложения `FastAPI` и «менеджер контекста» (через секунду покажу что это).
+Вы можете определить логику для *startup* и *shutdown*, используя параметр `lifespan` приложения `FastAPI` и «менеджер контекста» (через секунду покажу что это).
Начнем с примера, а затем разберём его подробнее.
{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}
-Здесь мы симулируем дорогую операцию startup по загрузке модели, помещая (фиктивную) функцию модели в словарь с моделями Машинного обучения до `yield`. Этот код будет выполнен до того, как приложение начнет принимать запросы, во время startup.
+Здесь мы симулируем дорогую операцию *startup* по загрузке модели, помещая (фиктивную) функцию модели в словарь с моделями Машинного обучения до `yield`. Этот код будет выполнен **до** того, как приложение **начнет принимать HTTP-запросы**, во время *startup*.
-А затем сразу после `yield` мы выгружаем модель. Этот код будет выполнен после того, как приложение закончит обрабатывать запросы, непосредственно перед shutdown. Это может, например, освободить ресурсы, такие как память или GPU.
+А затем сразу после `yield` мы выгружаем модель. Этот код будет выполнен **после** того, как приложение **закончит обрабатывать HTTP-запросы**, непосредственно перед *shutdown*. Это может, например, освободить ресурсы, такие как память или GPU.
/// tip | Совет
-`shutdown` произойдёт, когда вы останавливаете приложение.
+`shutdown` произойдёт, когда вы **останавливаете** приложение.
Возможно, вам нужно запустить новую версию, или вы просто устали от него. 🤷
{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}
-Первая часть функции, до `yield`, будет выполнена до запуска приложения.
+Первая часть функции, до `yield`, будет выполнена **до** запуска приложения.
-А часть после `yield` будет выполнена после завершения работы приложения.
+А часть после `yield` будет выполнена **после** завершения работы приложения.
### Асинхронный менеджер контекста { #async-context-manager }
Если присмотреться, функция декорирована `@asynccontextmanager`.
-Это превращает функцию в «асинхронный менеджер контекста».
+Это превращает функцию в «**асинхронный менеджер контекста**».
{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}
-Менеджер контекста в Python — это то, что можно использовать в операторе `with`. Например, `open()` можно использовать как менеджер контекста:
+**Менеджер контекста** в Python — это то, что можно использовать в операторе `with`. Например, `open()` можно использовать как менеджер контекста:
```Python
with open("file.txt") as file:
file.read()
```
-В последних версиях Python есть также асинхронный менеджер контекста. Его используют с `async with`:
+В последних версиях Python есть также **асинхронный менеджер контекста**. Его используют с `async with`:
```Python
async with lifespan(app):
В нашем примере выше мы не используем его напрямую, а передаём его в FastAPI, чтобы он использовал его сам.
-Параметр `lifespan` приложения `FastAPI` принимает асинхронный менеджер контекста, поэтому мы можем передать ему наш новый асинхронный менеджер контекста `lifespan`.
+Параметр `lifespan` приложения `FastAPI` принимает **асинхронный менеджер контекста**, поэтому мы можем передать ему наш новый асинхронный менеджер контекста `lifespan`.
{* ../../docs_src/events/tutorial003_py310.py hl[22] *}
/// warning | Предупреждение
-Рекомендуемый способ обрабатывать startup и shutdown — использовать параметр `lifespan` приложения `FastAPI`, как описано выше. Если вы укажете параметр `lifespan`, обработчики событий `startup` и `shutdown` больше вызываться не будут. Либо всё через `lifespan`, либо всё через события — не одновременно.
+Рекомендуемый способ обрабатывать *startup* и *shutdown* — использовать параметр `lifespan` приложения `FastAPI`, как описано выше. Если вы укажете параметр `lifespan`, обработчики событий `startup` и `shutdown` больше вызываться не будут. Либо всё через `lifespan`, либо всё через события — не одновременно.
Эту часть, скорее всего, можно пропустить.
///
-Есть альтернативный способ определить логику, которую нужно выполнить во время startup и во время shutdown.
+Есть альтернативный способ определить логику, которую нужно выполнить во время *startup* и во время *shutdown*.
Вы можете определить обработчики событий (функции), которые нужно выполнить до старта приложения или при его завершении.
Вы можете добавить более одного обработчика события.
-И ваше приложение не начнет принимать запросы, пока все обработчики события `startup` не завершатся.
+И ваше приложение не начнет принимать HTTP-запросы, пока все обработчики события `startup` не завершатся.
### Событие `shutdown` { #shutdown-event }
### `startup` и `shutdown` вместе { #startup-and-shutdown-together }
-С высокой вероятностью логика для вашего startup и shutdown связана: вы можете хотеть что-то запустить, а затем завершить, получить ресурс, а затем освободить его и т.д.
+С высокой вероятностью логика для вашего *startup* и *shutdown* связана: вы можете хотеть что-то запустить, а затем завершить, получить ресурс, а затем освободить его и т.д.
Делать это в отдельных функциях, которые не разделяют общую логику или переменные, сложнее, так как придётся хранить значения в глобальных переменных или использовать похожие приёмы.
## Технические детали { #technical-details }
-Ð\9dемного Ñ\82еÑ\85ниÑ\87еÑ\81киÑ\85 подÑ\80обноÑ\81Ñ\82ей для любопытных умников. 🤓
+Ð\9fÑ\80оÑ\81Ñ\82о Ñ\82еÑ\85ниÑ\87еÑ\81каÑ\8f подÑ\80обноÑ\81Ñ\82Ñ\8c для любопытных умников. 🤓
-Под капотом, в ASGI-технической спецификации, это часть [Протокола Lifespan](https://asgi.readthedocs.io/en/latest/specs/lifespan.html), и он определяет события `startup` и `shutdown`.
+Под капотом, в технической спецификации ASGI, это часть [Протокола Lifespan](https://asgi.readthedocs.io/en/latest/specs/lifespan.html), и он определяет события `startup` и `shutdown`.
/// note | Примечание
## Подприложения { #sub-applications }
-🚨 Имейте в виду, что эти события lifespan (startup и shutdown) будут выполнены только для основного приложения, а не для [Подприложения — Mounts](sub-applications.md).
+🚨 Имейте в виду, что эти события lifespan (startup и shutdown) будут выполнены только для основного приложения, а не для [Подприложений - Mounts](sub-applications.md).
///
-## Генераторы SDK от спонсоров FastAPI { #sdk-generators-from-fastapi-sponsors }
-
-В этом разделе представлены решения с **венчурной поддержкой** и **поддержкой компаний** от компаний, которые спонсируют FastAPI. Эти продукты предоставляют **дополнительные возможности** и **интеграции** сверх высококачественно генерируемых SDK.
-
-Благодаря ✨ [**спонсорству FastAPI**](../help-fastapi.md#sponsor-the-author) ✨ эти компании помогают обеспечивать, чтобы фреймворк и его **экосистема** оставались здоровыми и **устойчивыми**.
-
-Их спонсорство также демонстрирует серьёзную приверженность **сообществу** FastAPI (вам), показывая, что им важно не только предоставлять **отличный сервис**, но и поддерживать **надёжный и процветающий фреймворк** FastAPI. 🙇
-
-Например, вы можете попробовать:
-
-* [Stainless](https://www.stainless.com/?utm_source=fastapi&utm_medium=referral)
-
-Некоторые из этих решений также могут быть open source или иметь бесплатные тарифы, так что вы сможете попробовать их без финансовых затрат. Другие коммерческие генераторы SDK доступны и их можно найти онлайн. 🤓
-
## Создать TypeScript SDK { #create-a-typescript-sdk }
Начнём с простого приложения FastAPI:
## Base64 и файлы { #base64-vs-files }
-Сначала рассмотрите возможность использовать [Файлы в запросе](../tutorial/request-files.md) для загрузки бинарных данных и [Пользовательский HTTP-ответ — FileResponse](./custom-response.md#fileresponse--fileresponse-) для отправки бинарных данных вместо кодирования их в JSON.
+Сначала рассмотрите возможность использовать [Файлы в запросе](../tutorial/request-files.md) для загрузки бинарных данных и [Пользовательский HTTP-ответ — FileResponse](./custom-response.md#fileresponse) для отправки бинарных данных вместо кодирования их в JSON.
JSON может содержать только строки в кодировке UTF-8, поэтому он не может содержать «сырые» байты.
## Pydantic `bytes` { #pydantic-bytes }
-Вы можете объявить Pydantic-модель с полями `bytes`, а затем использовать `val_json_bytes` в конфиге модели, чтобы указать использовать base64 для валидации входящих JSON-данных; как часть этой валидации строка base64 будет декодирована в байты.
+Вы можете объявить Pydantic-модель с полями `bytes`, а затем использовать `val_json_bytes` в конфиге модели, чтобы указать использовать base64 для *валидации* входящих JSON-данных; как часть этой валидации строка base64 будет декодирована в байты.
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}
## Pydantic `bytes` для выходных данных { #pydantic-bytes-for-output-data }
-Вы также можете использовать поля `bytes` с `ser_json_bytes` в конфиге модели для выходных данных, и Pydantic будет сериализовать байты в base64 при формировании JSON-ответа.
+Вы также можете использовать поля `bytes` с `ser_json_bytes` в конфиге модели для выходных данных, и Pydantic будет *сериализовать* байты в base64 при формировании JSON-ответа.
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}
## Pydantic `bytes` для входных и выходных данных { #pydantic-bytes-for-input-and-output-data }
-И, конечно, вы можете использовать одну и ту же модель, настроенную на использование base64, чтобы обрабатывать и входящие данные (валидация) с `val_json_bytes`, и исходящие данные (сериализация) с `ser_json_bytes` при приеме и отправке JSON-данных.
+И, конечно, вы можете использовать одну и ту же модель, настроенную на использование base64, чтобы обрабатывать и входящие данные (*валидировать*) с `val_json_bytes`, и исходящие данные (*сериализовать*) с `ser_json_bytes` при приеме и отправке JSON-данных.
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}
# Обратные вызовы в OpenAPI { #openapi-callbacks }
-Вы можете создать API с *операцией пути* (обработчиком пути), которая будет инициировать HTTP-запрос к *внешнему API*, созданному кем-то другим (скорее всего тем же разработчиком, который будет использовать ваш API).
+Вы можете создать API с *операцией пути* (обработчиком пути), которая будет инициировать HTTP-запрос к *внешнему API*, созданному кем-то другим (скорее всего тем же разработчиком, который будет *использовать* ваш API).
-Процесс, происходящий, когда ваше приложение API обращается к *внешнему API*, называется «callback» (обратный вызов). Программное обеспечение, написанное внешним разработчиком, отправляет HTTP-запрос вашему API, а затем ваш API выполняет обратный вызов, отправляя HTTP-запрос во *внешний API* (который, вероятно, тоже создал тот же разработчик).
+Процесс, происходящий, когда ваше приложение API обращается к *внешнему API*, называется «callback» (обратный вызов). Потому что программное обеспечение, написанное внешним разработчиком, отправляет HTTP-запрос вашему API, а затем ваш API выполняет обратный вызов, отправляя HTTP-запрос во *внешний API* (который, вероятно, тоже создал тот же разработчик).
-В этом случае вам может понадобиться задокументировать, как должно выглядеть это внешнее API: какую *операцию пути* оно должно иметь, какое тело запроса ожидать, какой ответ возвращать и т.д.
+В этом случае вам может понадобиться задокументировать, как это внешнее API *должно* выглядеть: какую *операцию пути* оно должно иметь, какое тело запроса ожидать, какой HTTP-ответ возвращать и т.д.
## Приложение с обратными вызовами { #an-app-with-callbacks }
Когда вы пишете код для документирования обратного вызова, полезно представить, что вы — тот самый *внешний разработчик*. И что вы сейчас реализуете *внешний API*, а не *свой API*.
-Временное принятие этой точки зрения (внешнего разработчика) поможет интуитивно понять, куда поместить параметры, какую Pydantic-модель использовать для тела запроса, для ответа и т.д. во *внешнем API*.
+Временное принятие этой точки зрения (внешнего разработчика) поможет интуитивно понять, куда поместить параметры, какую Pydantic-модель использовать для тела запроса, для HTTP-ответа и т.д. во *внешнем API*.
///
Она должна выглядеть как обычная *операция пути* FastAPI:
* Вероятно, в ней должно быть объявление тела запроса, например `body: InvoiceEvent`.
-* А также может быть объявление модели ответа, например `response_model=InvoiceEventReceived`.
+* А также может быть объявление HTTP-ответа, который она должна возвращать, например `response_model=InvoiceEventReceived`.
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}
https://yourapi.com/invoices/?callback_url=https://www.external.org/events
```
-с телом JSON:
+с телом запроса JSON:
```JSON
{
https://www.external.org/events/invoices/2expen51ve
```
-с телом JSON примерно такого вида:
+с телом запроса JSON примерно такого вида:
```JSON
{
}
```
-и будет ожидать от *внешнего API* ответ с телом JSON вида:
+и будет ожидать от *внешнего API* HTTP-ответ с JSON в теле ответа:
```JSON
{
///
-### Ð\9fодклÑ\8eÑ\87иÑ\82е маÑ\80Ñ\88Ñ\80Ñ\83Ñ\82изаÑ\82ор обратного вызова { #add-the-callback-router }
+### Ð\94обавÑ\8cÑ\82е Ñ\80оÑ\83Ñ\82ер обратного вызова { #add-the-callback-router }
-К этому моменту у вас есть необходимые *операции пути* обратного вызова (те, которые *внешний разработчик* должен реализовать во *внешнем API*) в созданном выше маршрутизаторе обратных вызовов.
+К этому моменту у вас есть необходимые *операции пути* обратного вызова (те, которые *внешний разработчик* должен реализовать во *внешнем API*) в созданном выше роутере обратных вызовов.
-Теперь используйте параметр `callbacks` в *декораторе операции пути вашего API*, чтобы передать атрибут `.routes` из этого маршрутизатора обратных вызовов:
+Теперь используйте параметр `callbacks` в *декораторе операции пути вашего API*, чтобы передать атрибут `.routes` из этого роутера обратных вызовов:
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}
/// tip | Совет
-Обратите внимание, что вы передаёте не сам маршрутизатор (`invoices_callback_router`) в `callback=`, а его атрибут `.routes`, то есть `invoices_callback_router.routes`. FastAPI будет использовать эти маршруты для генерации документации OpenAPI для обратных вызовов.
+Обратите внимание, что вы передаёте не сам роутер (`invoices_callback_router`) в `callbacks=`, а его атрибут `.routes`, то есть `invoices_callback_router.routes`. FastAPI будет использовать эти маршруты для генерации документации OpenAPI для обратных вызовов.
///
# Response - Изменение статус-кода { #response-change-status-code }
-Вы, вероятно, уже читали о том, что можно установить [статус-код ответа по умолчанию](../tutorial/response-status-code.md).
+Вы, вероятно, уже читали о том, что можно установить [статус-код ответа](../tutorial/response-status-code.md) по умолчанию.
Но в некоторых случаях нужно вернуть другой статус-код, отличный от значения по умолчанию.
## Использование параметра `Response` { #use-a-response-parameter }
-Вы можете объявить параметр типа `Response` в вашей *функции обработки пути* (как и для cookies и HTTP-заголовков).
+Вы можете объявить параметр типа `Response` в вашей *функции-обработчике пути* (как и для cookies и HTTP-заголовков).
И затем вы можете установить `status_code` в этом *временном* объекте ответа.
# Cookies в ответе { #response-cookies }
+
## Использование параметра `Response` { #use-a-response-parameter }
Вы можете объявить параметр типа `Response` в вашей функции-обработчике пути.
## Использовать параметр `Response` { #use-a-response-parameter }
-Вы можете объявить параметр типа `Response` в вашей функции-обработчике пути (как можно сделать и для cookie).
+Вы можете объявить параметр типа `Response` в вашей *функции-обработчике пути* (как можно сделать и для cookie).
А затем вы можете устанавливать HTTP-заголовки в этом *временном* объекте ответа.
**FastAPI** использует этот *временный* ответ, чтобы извлечь HTTP-заголовки (а также cookie и статус-код) и поместит их в финальный HTTP-ответ, который содержит возвращённое вами значение, отфильтрованное согласно `response_model`.
-Вы также можете объявлять параметр `Response` в зависимостях и устанавливать в них заголовки (и cookie).
+Вы также можете объявлять параметр `Response` в зависимостях и устанавливать в них HTTP-заголовки (и cookie).
## Вернуть `Response` напрямую { #return-a-response-directly }
Вы также можете добавить HTTP-заголовки, когда возвращаете `Response` напрямую.
-Создайте ответ, как описано в [Вернуть Response напрямую](response-directly.md), и передайте заголовки как дополнительный параметр:
+Создайте ответ, как описано в [Вернуть Response напрямую](response-directly.md), и передайте HTTP-заголовки как дополнительный параметр:
{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}
**FastAPI** предоставляет те же самые `starlette.responses` как `fastapi.responses` — для вашего удобства как разработчика. Но большинство доступных классов ответов поступают напрямую из Starlette.
-И поскольку `Response` часто используется для установки заголовков и cookie, **FastAPI** также предоставляет его как `fastapi.Response`.
+И поскольку `Response` часто используется для установки HTTP-заголовков и cookie, **FastAPI** также предоставляет его как `fastapi.Response`.
///
## Пользовательские HTTP-заголовки { #custom-headers }
-Помните, что собственные проприетарные заголовки можно добавлять, [используя префикс `X-`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).
+Помните, что собственные проприетарные HTTP-заголовки можно добавлять, [используя префикс `X-`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).
-Но если у вас есть пользовательские заголовки, которые вы хотите показывать клиенту в браузере, вам нужно добавить их в настройки CORS (подробнее см. в [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md)), используя параметр `expose_headers`, описанный в [документации Starlette по CORS](https://www.starlette.dev/middleware/#corsmiddleware).
+Но если у вас есть пользовательские HTTP-заголовки, которые вы хотите показывать клиенту в браузере, вам нужно добавить их в настройки CORS (подробнее см. в [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md)), используя параметр `expose_headers`, описанный в [документации Starlette по CORS](https://www.starlette.dev/middleware/#corsmiddleware).
Так как теперь мы объявляем эти scopes, они появятся в документации API при входе/авторизации.
-Ð\98 вÑ\8b Ñ\81можеÑ\82е вÑ\8bбÑ\80аÑ\82Ñ\8c, какие scopes вÑ\8b Ñ\85оÑ\82иÑ\82е вÑ\8bдать доступ: `me` и `items`.
+Ð\98 вÑ\8b Ñ\81можеÑ\82е вÑ\8bбÑ\80аÑ\82Ñ\8c, длÑ\8f какиÑ\85 scopes Ñ\85оÑ\82иÑ\82е пÑ\80едоÑ\81Ñ\82авить доступ: `me` и `items`.
Это тот же механизм, когда вы даёте разрешения при входе через Facebook, Google, GitHub и т.д.:
{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *}
-## Ð\9eбÑ\8aÑ\8fвление scopes в *обÑ\80абоÑ\82Ñ\87икаÑ\85 пÑ\83Ñ\82ей* и зависимостях { #declare-scopes-in-path-operations-and-dependencies }
+## Ð\9eбÑ\8aÑ\8fвление scopes в *опеÑ\80аÑ\86иÑ\8fÑ\85 пÑ\83Ñ\82и* и зависимостях { #declare-scopes-in-path-operations-and-dependencies }
Теперь объявим, что операция пути для `/users/me/items/` требует scope `items`.
### Создание `Settings` только один раз с помощью `lru_cache` { #creating-the-settings-only-once-with-lru-cache }
-Чтение файла с диска обычно затратная (медленная) операция, поэтому, вероятно, вы захотите сделать это один раз и затем переиспользовать один и тот же объект настроек, а не читать файл при каждом запросе.
+Чтение файла с диска обычно затратная (медленная) операция, поэтому, вероятно, вы захотите сделать это один раз и затем переиспользовать один и тот же объект настроек, а не читать файл при каждом HTTP-запросе.
Но каждый раз, когда мы делаем:
return Settings()
```
-мы бы создавали этот объект для каждого запроса и читали файл `.env` на каждый запрос. ⚠️
+мы бы создавали этот объект для каждого HTTP-запроса и читали файл `.env` на каждый HTTP-запрос. ⚠️
Но так как мы используем декоратор `@lru_cache` сверху, объект `Settings` будет создан только один раз — при первом вызове. ✔️
{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}
-Затем при любых последующих вызовах `get_settings()` в зависимостях для следующих запросов, вместо выполнения внутреннего кода `get_settings()` и создания нового объекта `Settings`, будет возвращаться тот же объект, что был возвращен при первом вызове, снова и снова.
+Затем при любых последующих вызовах `get_settings()` в зависимостях для следующих HTTP-запросов, вместо выполнения внутреннего кода `get_settings()` и создания нового объекта `Settings`, будет возвращаться тот же объект, что был возвращен при первом вызове, снова и снова.
#### Технические детали `lru_cache` { #lru-cache-technical-details }
* Используя зависимость, вы упрощаете тестирование.
* Можно использовать файлы `.env`.
-* `@lru_cache` позволяет не читать файл dotenv снова и снова для каждого запроса, при этом давая возможность переопределять его во время тестирования.
+* `@lru_cache` позволяет не читать файл dotenv снова и снова для каждого HTTP-запроса, при этом давая возможность переопределять его во время тестирования.
Если вам нужно передавать потоковые данные, которые можно представить как JSON, воспользуйтесь [стримингом JSON Lines](../tutorial/stream-json-lines.md).
-Но если вы хотите передавать в потоке чистые бинарные данные или строки, ниже показано, как это сделать.
+Но если вы хотите передавать в потоке **чистые бинарные данные** или строки, ниже показано, как это сделать.
/// note | Примечание
{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}
-Это также означает, что с `StreamingResponse` у вас есть и свобода, и ответственность — производить и кодировать байты данных ровно в том виде, в котором они должны быть отправлены, независимо от аннотаций типов. 🤓
+Это также означает, что с `StreamingResponse` у вас есть и **свобода**, и **ответственность** — производить и кодировать байты данных ровно в том виде, в котором они должны быть отправлены, независимо от аннотаций типов. 🤓
### Потоковая передача байтов { #stream-bytes }
Нужно импортировать `WSGIMiddleware` из `a2wsgi`.
-Ð\97аÑ\82ем обеÑ\80ниÑ\82е WSGIâ\80\91пÑ\80иложение (напÑ\80имеÑ\80, Flask) в middleware (Ð\9fромежуточный слой).
+Ð\97аÑ\82ем обеÑ\80ниÑ\82е WSGIâ\80\91пÑ\80иложение (напÑ\80имеÑ\80, Flask) в middleware (промежуточный слой).
После этого смонтируйте его на путь.
Вместо него рекомендуется использовать пакет `a2wsgi`. Использование остаётся таким же.
-Просто убедитесь, что пакет `a2wsgi` установлен, и импортируйте `WSGIMiddleware` из `a2wsgi`.
+Ð\9fÑ\80оÑ\81Ñ\82о Ñ\83бедиÑ\82еÑ\81Ñ\8c, Ñ\87Ñ\82о пакеÑ\82 `a2wsgi` Ñ\83Ñ\81Ñ\82ановлен, и пÑ\80авилÑ\8cно импоÑ\80Ñ\82иÑ\80Ñ\83йÑ\82е `WSGIMiddleware` из `a2wsgi`.
///
Он относительно тесно связан с реляционными базами данных (например, MySQL или PostgreSQL), поэтому использовать NoSQL-базу данных (например, Couchbase, MongoDB, Cassandra и т. п.) в качестве основного хранилища не очень просто.
-Он был создан для генерации HTML на бэкенде, а не для создания API, используемых современным фронтендом (например, React, Vue.js и Angular) или другими системами (например, устройствами <abbr title="Internet of Things – Интернет вещей">IoT</abbr>), которые с ним общаются.
+Он был создан для генерации HTML на бэкенде, а не для создания API, используемых современным фронтендом (например, React, Vue.js и Angular) или другими системами (например, устройствами <abbr title="Internet of Things - Интернет вещей">IoT</abbr>), которые с ним общаются.
### [Django REST Framework](https://www.django-rest-framework.org/) { #django-rest-framework }
response = requests.get("http://example.com/some/url")
```
-Соответствующая в FastAPI API-операция пути могла бы выглядеть так:
+Соответствующая в FastAPI API-*операция пути* могла бы выглядеть так:
```Python hl_lines="1"
@app.get("/some/url")
results = await some_library()
```
-Тогда обÑ\8aÑ\8fвлÑ\8fйÑ\82е *Ñ\84Ñ\83нкÑ\86ии-обÑ\80абоÑ\82Ñ\87иков пути* с `async def`, например:
+Тогда обÑ\8aÑ\8fвлÑ\8fйÑ\82е *Ñ\84Ñ\83нкÑ\86ии-обÑ\80абоÑ\82Ñ\87ики пути* с `async def`, например:
```Python hl_lines="2"
@app.get('/')
---
-Ð\95Ñ\81ли вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е Ñ\81Ñ\82оÑ\80оннÑ\8eÑ\8e библиоÑ\82екÑ\83, коÑ\82оÑ\80аÑ\8f взаимодейÑ\81Ñ\82вÑ\83еÑ\82 Ñ\81 Ñ\87ем-Ñ\82о (база даннÑ\8bÑ\85, API, Ñ\84айловаÑ\8f Ñ\81иÑ\81Ñ\82ема и Ñ\82.д.) и не поддеÑ\80живаеÑ\82 иÑ\81полÑ\8cзование `await` (Ñ\81ейÑ\87аÑ\81 Ñ\8dÑ\82о оÑ\82ноÑ\81иÑ\82Ñ\81Ñ\8f к болÑ\8cÑ\88инÑ\81Ñ\82вÑ\83 библиоÑ\82ек длÑ\8f Ð\91Ð\94), Ñ\82огда обÑ\8aÑ\8fвлÑ\8fйÑ\82е *Ñ\84Ñ\83нкÑ\86ии-обÑ\80абоÑ\82Ñ\87иков пути* как обычно, просто с `def`, например:
+Ð\95Ñ\81ли вÑ\8b иÑ\81полÑ\8cзÑ\83еÑ\82е Ñ\81Ñ\82оÑ\80оннÑ\8eÑ\8e библиоÑ\82екÑ\83, коÑ\82оÑ\80аÑ\8f взаимодейÑ\81Ñ\82вÑ\83еÑ\82 Ñ\81 Ñ\87ем-Ñ\82о (база даннÑ\8bÑ\85, API, Ñ\84айловаÑ\8f Ñ\81иÑ\81Ñ\82ема и Ñ\82.д.) и не поддеÑ\80живаеÑ\82 иÑ\81полÑ\8cзование `await` (Ñ\81ейÑ\87аÑ\81 Ñ\8dÑ\82о оÑ\82ноÑ\81иÑ\82Ñ\81Ñ\8f к болÑ\8cÑ\88инÑ\81Ñ\82вÑ\83 библиоÑ\82ек длÑ\8f Ð\91Ð\94), Ñ\82огда обÑ\8aÑ\8fвлÑ\8fйÑ\82е *Ñ\84Ñ\83нкÑ\86ии-обÑ\80абоÑ\82Ñ\87ики пути* как обычно, просто с `def`, например:
```Python hl_lines="2"
@app.get('/')
---
-**Ð\9fÑ\80имеÑ\87ание**: вÑ\8b можеÑ\82е Ñ\81меÑ\88иваÑ\82Ñ\8c `def` и `async def` в *Ñ\84Ñ\83нкÑ\86иÑ\8fÑ\85-обÑ\80абоÑ\82Ñ\87иков пути* столько, сколько нужно, и объявлять каждую так, как лучше для вашего случая. FastAPI сделает с ними всё как надо.
+**Ð\9fÑ\80имеÑ\87ание**: вÑ\8b можеÑ\82е Ñ\81меÑ\88иваÑ\82Ñ\8c `def` и `async def` в *Ñ\84Ñ\83нкÑ\86иÑ\8fÑ\85-обÑ\80абоÑ\82Ñ\87икаÑ\85 пути* столько, сколько нужно, и объявлять каждую так, как лучше для вашего случая. FastAPI сделает с ними всё как надо.
В любом из случаев выше FastAPI всё равно работает асинхронно и очень быстро.
Именно такая асинхронность сделала NodeJS популярным (хотя NodeJS — не параллельный), и это сильная сторона Go как языка программирования.
-Того же уровня производительности вы получаете с **FastAPI**.
+Тот же уровень производительности вы получаете с **FastAPI**.
А так как можно одновременно использовать параллелизм и асинхронность, вы получаете производительность выше, чем у большинства протестированных фреймворков на NodeJS и на уровне Go, который — компилируемый язык, ближе к C [(всё благодаря Starlette)](https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1).
---
-Итак, если вы используете библиотеку, которую можно вызывать с `await`, вам нужно создать *функцию-обработчик пути*, которая её использует, с `async def`, например:
+Итак, если вы используете библиотеку, которую можно вызывать с `await`, вам нужно создать *функции-обработчики пути*, которые её используют, с `async def`, например:
```Python hl_lines="2-3"
@app.get('/burgers')
# Развертывание FastAPI у облачных провайдеров { #deploy-fastapi-on-cloud-providers }
-Вы можете использовать практически любого облачного провайдера, чтобы развернуть свое приложение на FastAPI.
+Вы можете использовать практически **любого облачного провайдера**, чтобы развернуть свое приложение на FastAPI.
В большинстве случаев у основных облачных провайдеров есть руководства по развертыванию FastAPI на их платформе.
## Облачные провайдеры — спонсоры { #cloud-providers-sponsors }
-Некоторые другие облачные провайдеры ✨ [**спонсируют FastAPI**](../help-fastapi.md#sponsor-the-author) ✨ тоже. 🙇
+Некоторые другие облачные провайдеры ✨ [**спонсируют FastAPI**](https://github.com/sponsors/tiangolo) ✨ тоже. 🙇
Возможно, вы захотите попробовать их сервисы и воспользоваться их руководствами:
Не беспокойтесь, если некоторые пункты про **контейнеры**, Docker или Kubernetes пока кажутся неочевидными.
-Я расскажу больше про образы контейнеров, Docker, Kubernetes и т.п. в следующей главе: [FastAPI внутри контейнеров — Docker](docker.md).
+Я расскажу больше про образы контейнеров, Docker, Kubernetes и т.п. в одной из будущих глав: [FastAPI внутри контейнеров — Docker](docker.md).
///
/// tip | Совет
-Я приведу более конкретные примеры с контейнерами в следующей главе: [FastAPI внутри контейнеров — Docker](docker.md).
+Я приведу более конкретные примеры с контейнерами в одной из будущих глав: [FastAPI внутри контейнеров — Docker](docker.md).
///
Также возможен **всплеск** использования вашего API: он мог «взорваться» по популярности, или какие‑то сервисы/боты начали его активно использовать. На такие случаи стоит иметь запас ресурсов.
-Можно задать **целевое значение**, например **между 50% и 90%** использования ресурсов. Скорее всего, именно эти вещи вы будете измерять и на их основе настраивать развёртывание.
+Можно задать **произвольное число** в качестве цели, например **между 50% и 90%** использования ресурсов. Скорее всего, именно эти вещи вы будете измерять и на их основе настраивать развёртывание.
-Можно использовать простые инструменты вроде `htop`, чтобы смотреть загрузку CPU и RAM на сервере или по процессам. Или более сложные распределённые системы мониторинга.
+Можно использовать простые инструменты вроде `htop`, чтобы смотреть загрузку CPU и RAM на сервере или по процессам. Или более сложные инструменты мониторинга, которые могут быть распределены по серверам и т.п.
## Резюме { #recap }
#### За прокси-сервером TSL-терминации { #behind-a-tls-termination-proxy }
-Ð\95Ñ\81ли вÑ\8b запÑ\83Ñ\81каеÑ\82е конÑ\82ейнеÑ\80 за пÑ\80окÑ\81и-Ñ\81еÑ\80веÑ\80ом TSL-Ñ\82еÑ\80минаÑ\86ии (баланÑ\81иÑ\80овÑ\89иком нагÑ\80Ñ\83зки), Ñ\82аким как Nginx или Traefik, добавÑ\8cÑ\82е опÑ\86иÑ\8e `--proxy-headers`. ÐÑ\82о Ñ\81ообÑ\89иÑ\82 Uvicorn (Ñ\87еÑ\80ез FastAPI CLI), Ñ\87Ñ\82о пÑ\80иложение Ñ\80абоÑ\82аеÑ\82 за HTTPS и можно довеÑ\80Ñ\8fÑ\82Ñ\8c Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82вÑ\83Ñ\8eÑ\89им заголовкам.
+Ð\95Ñ\81ли вÑ\8b запÑ\83Ñ\81каеÑ\82е конÑ\82ейнеÑ\80 за пÑ\80окÑ\81и-Ñ\81еÑ\80веÑ\80ом TSL-Ñ\82еÑ\80минаÑ\86ии (баланÑ\81иÑ\80овÑ\89иком нагÑ\80Ñ\83зки), Ñ\82аким как Nginx или Traefik, добавÑ\8cÑ\82е опÑ\86иÑ\8e `--proxy-headers`. ÐÑ\82о Ñ\81ообÑ\89иÑ\82 Uvicorn (Ñ\87еÑ\80ез FastAPI CLI), Ñ\87Ñ\82о можно довеÑ\80Ñ\8fÑ\82Ñ\8c заголовкам, оÑ\82пÑ\80авленнÑ\8bм Ñ\8dÑ\82им пÑ\80окÑ\81и и Ñ\81ообÑ\89аÑ\8eÑ\89им, Ñ\87Ñ\82о пÑ\80иложение Ñ\80абоÑ\82аеÑ\82 за HTTPS, и Ñ\82.д.
```Dockerfile
CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"]
1. Копируем файл `main.py` напрямую в `/code` (без директории `./app`).
-2. Используем `fastapi run` для запуска приложения из одного файла `main.py`.
+2. Используем `fastapi run`, чтобы «отдавать» приложение из одного файла `main.py`.
-Ð\9aогда вÑ\8b пеÑ\80едаÑ\91Ñ\82е Ñ\84айл в `fastapi run`, он авÑ\82омаÑ\82иÑ\87еÑ\81ки опÑ\80еделиÑ\82, Ñ\87Ñ\82о Ñ\8dÑ\82о одиноÑ\87нÑ\8bй Ñ\84айл, а не Ñ\87аÑ\81Ñ\82Ñ\8c пакеÑ\82а, и поймÑ\91Ñ\82, как его импоÑ\80Ñ\82иÑ\80оваÑ\82Ñ\8c и запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c ваше FastAPI-приложение. 😎
+Ð\9aогда вÑ\8b пеÑ\80едаÑ\91Ñ\82е Ñ\84айл в `fastapi run`, он авÑ\82омаÑ\82иÑ\87еÑ\81ки опÑ\80еделиÑ\82, Ñ\87Ñ\82о Ñ\8dÑ\82о одиноÑ\87нÑ\8bй Ñ\84айл, а не Ñ\87аÑ\81Ñ\82Ñ\8c пакеÑ\82а, и поймÑ\91Ñ\82, как импоÑ\80Ñ\82иÑ\80оваÑ\82Ñ\8c и «оÑ\82даваÑ\82Ñ\8c» ваше FastAPI-приложение. 😎
## Концепции развертывания { #deployment-concepts }
Вы можете развёртывать на **одном сервере** (не кластере) с **Docker Compose**, и у вас не будет простого способа управлять репликацией контейнеров (в Docker Compose), сохраняя общую сеть и **балансировку нагрузки**.
-Тогда вы можете захотеть **один контейнер** с **менеджером процессов**, который запускает **несколько воркеров** внутри.
+Тогда вы можете захотеть **один контейнер** с **менеджером процессов**, который запускает **несколько воркер-процессов** внутри.
---
### Один контейнер { #single-container }
-Если у вас простая схема с **одним контейнером**, который затем запускает несколько **воркеров** (или один процесс), можно выполнить подготовительные шаги в этом же контейнере непосредственно перед запуском процесса с приложением.
+Если у вас простая схема с **одним контейнером**, который затем запускает несколько **воркер-процессов** (или один процесс), можно выполнить подготовительные шаги в этом же контейнере непосредственно перед запуском процесса с приложением.
### Базовый Docker-образ { #base-docker-image }
/// note | Технические подробности
-Этот Docker-образ был создан в то время, когда Uvicorn не умел управлять и перезапускать «упавших» воркеров, и приходилось использовать Gunicorn вместе с Uvicorn, что добавляло заметную сложность, лишь бы Gunicorn управлял и перезапускал воркеров Uvicorn.
+Этот Docker-образ был создан в то время, когда Uvicorn не умел управлять и перезапускать «упавших» воркеров, и приходилось использовать Gunicorn вместе с Uvicorn, что добавляло заметную сложность, лишь бы Gunicorn управлял и перезапускал воркер-процессы Uvicorn.
Но теперь, когда Uvicorn (и команда `fastapi`) поддерживают `--workers`, нет причин использовать базовый Docker-образ вместо сборки своего (кода получается примерно столько же 😅).
В большинстве случаев вы, вероятно, не захотите использовать какой-либо базовый образ, а вместо этого **соберёте образ контейнера с нуля** на основе официального Docker-образа Python.
-Заботясь о **порядке** инструкций в `Dockerfile` и используя **кэш Docker**, вы можете **минимизировать время сборки**, чтобы повысить продуктивность (и не скучать). 😎
+Заботясь о **порядке** инструкций в `Dockerfile` и используя **кэш Docker**, вы можете **минимизировать время сборки**, чтобы повысить продуктивность (и не скучать). 😎
/// tip | Совет
-Если вы торопитесь или вам это не важно, переходите к следующим разделам с пошаговыми инструкциями по настройке всего разными способами.
+Если вы торопитесь или вам это не важно, продолжайте со следующих разделов с пошаговыми инструкциями по настройке всего разными способами.
///
Чаще всего всё начинается с **приобретения** **имени домена**. Затем вы настраиваете его на DNS‑сервере (возможно, у того же облачного провайдера).
-СкоÑ\80ее вÑ\81его, вÑ\8b полÑ\83Ñ\87иÑ\82е облаÑ\87нÑ\8bй Ñ\81еÑ\80веÑ\80 (виÑ\80Ñ\82Ñ\83алÑ\8cнÑ\83Ñ\8e маÑ\88инÑ\83) или Ñ\87Ñ\82о-Ñ\82о подобное, и Ñ\83 него бÑ\83деÑ\82 <dfn title="Со вÑ\80еменем не менÑ\8fеÑ\82Ñ\81Ñ\8f. Не динамический.">постоянный</dfn> **публичный IP-адрес**.
+СкоÑ\80ее вÑ\81его, вÑ\8b полÑ\83Ñ\87иÑ\82е облаÑ\87нÑ\8bй Ñ\81еÑ\80веÑ\80 (виÑ\80Ñ\82Ñ\83алÑ\8cнÑ\83Ñ\8e маÑ\88инÑ\83) или Ñ\87Ñ\82о-Ñ\82о подобное, и Ñ\83 него бÑ\83деÑ\82 <dfn title="Ð\9dе менÑ\8fеÑ\82Ñ\81Ñ\8f Ñ\81о вÑ\80еменем. Не динамический.">постоянный</dfn> **публичный IP-адрес**.
На DNS‑сервере(ах) вы настроите запись («`A record`» - запись типа A), указывающую, что **ваш домен** должен указывать на публичный **IP‑адрес вашего сервера**.
Когда вы используете прокси для обработки HTTPS, ваш **сервер приложения** (например, Uvicorn через FastAPI CLI) ничего не знает о процессе HTTPS, он общается обычным HTTP с **прокси‑сервером TLS-терминации**.
-Обычно этот **прокси** на лету добавляет некоторые HTTP‑заголовки перед тем, как переслать запрос на **сервер приложения**, чтобы тот знал, что запрос был **проксирован**.
+Обычно этот **прокси** на лету добавляет некоторые HTTP‑заголовки перед тем, как переслать запрос на **сервер приложения**, чтобы тот знал, что запрос был **переслан** прокси.
/// note | Технические детали
/// tip | Совет
-Ð\9fодÑ\80обнее об Ñ\8dÑ\82ом вÑ\8b можеÑ\82е Ñ\83знаÑ\82Ñ\8c в докÑ\83менÑ\82аÑ\86ии: [Ð\97а пÑ\80окÑ\81и â\80\94 Ð\92ключить пересылаемые заголовки прокси](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers)
+Ð\9fодÑ\80обнее об Ñ\8dÑ\82ом вÑ\8b можеÑ\82е Ñ\83знаÑ\82Ñ\8c в докÑ\83менÑ\82аÑ\86ии: [Ð\97а пÑ\80окÑ\81и â\80\94 включить пересылаемые заголовки прокси](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers)
///
## Используйте команду `fastapi run` { #use-the-fastapi-run-command }
-Ð\9aоÑ\80оÑ\82ко: иÑ\81полÑ\8cзÑ\83йÑ\82е `fastapi run`, Ñ\87Ñ\82обÑ\8b запÑ\83Ñ\81Ñ\82иÑ\82Ñ\8c ваÑ\88е пÑ\80иложение FastAPI:
+Ð\9aоÑ\80оÑ\82ко: иÑ\81полÑ\8cзÑ\83йÑ\82е `fastapi run`, Ñ\87Ñ\82обÑ\8b пÑ\80едоÑ\81Ñ\82авлÑ\8fÑ\82Ñ\8c доÑ\81Ñ\82Ñ\83п к ваÑ\88емÑ\83 пÑ\80иложениÑ\8e FastAPI:
<div class="termy">
- **Развернуть в FastAPI Cloud** — развертывание вашего приложения в один клик в [FastAPI Cloud](https://fastapicloud.com/).
- **Поток логов приложения** — потоковая передача логов в реальном времени из вашего приложения, развернутого в FastAPI Cloud, с фильтрацией по уровню и текстовым поиском.
-Ð\95Ñ\81ли вÑ\8b Ñ\85оÑ\82иÑ\82е повеÑ\80Ñ\85ноÑ\81Ñ\82но ознакомиÑ\82Ñ\8cÑ\81Ñ\8f Ñ\81 возможноÑ\81Ñ\82Ñ\8fми Ñ\80аÑ\81Ñ\88иÑ\80ениÑ\8f, оÑ\82кÑ\80ойÑ\82е палиÑ\82Ñ\80Ñ\83 команд (<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd> или на macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>), вÑ\8bбеÑ\80иÑ\82е «Welcome: Open walkthrough...», а заÑ\82ем «Get started with FastAPI».
+Ð\95Ñ\81ли вÑ\8b Ñ\85оÑ\82иÑ\82е ознакомиÑ\82Ñ\8cÑ\81Ñ\8f Ñ\81 возможноÑ\81Ñ\82Ñ\8fми Ñ\80аÑ\81Ñ\88иÑ\80ениÑ\8f, вÑ\8b можеÑ\82е поÑ\81моÑ\82Ñ\80еÑ\82Ñ\8c walkthrough Ñ\80аÑ\81Ñ\88иÑ\80ениÑ\8f, оÑ\82кÑ\80Ñ\8bв палиÑ\82Ñ\80Ñ\83 команд (<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd> или на macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>) и вÑ\8bбÑ\80ав «Welcome: Open walkthrough...», а заÑ\82ем walkthrough «Get started with FastAPI».
////
-## Чтение переменных окружения в python { #read-env-vars-in-python }
+## Чтение переменных окружения в Python { #read-env-vars-in-python }
-Так же существует возможность создания переменных окружения **вне** Python, в терминале (или любым другим способом), а затем **чтения их в Python**.
+Также существует возможность создания переменных окружения **вне** Python, в терминале (или любым другим способом), а затем **чтения их в Python**.
Например, у вас есть файл `main.py`:
Второй аргумент [`os.getenv()`](https://docs.python.org/3.8/library/os.html#os.getenv) - это возвращаемое по умолчанию значение.
-Если значение не указано, то по умолчанию оно равно `None`. В данном случае мы указываем `«World»` в качестве значения по умолчанию.
+Если значение не указано, то по умолчанию оно равно `None`. В данном случае мы указываем `"World"` в качестве значения по умолчанию.
///
///
-## Типизация и Валидация { #types-and-validation }
+## Типы и валидация { #types-and-validation }
Эти переменные окружения могут работать только с **текстовыми строками**, поскольку они являются внешними по отношению к Python и должны быть совместимы с другими программами и остальной системой (и даже с различными операционными системами, такими как Linux, Windows, macOS).
Это означает, что **любое значение**, считанное в Python из переменной окружения, **будет `str`**, и любое преобразование к другому типу или любая валидация должны быть выполнены в коде.
-Ð\9fодÑ\80обнее об иÑ\81полÑ\8cзовании пеÑ\80еменнÑ\8bÑ\85 окÑ\80Ñ\83жениÑ\8f длÑ\8f Ñ\80абоÑ\82Ñ\8b Ñ\81 **наÑ\81Ñ\82Ñ\80ойками пÑ\80иложениÑ\8f** вÑ\8b Ñ\83знаеÑ\82е в [РаÑ\81Ñ\88иÑ\80енное Ñ\80Ñ\83ководÑ\81Ñ\82во полÑ\8cзоваÑ\82елÑ\8f - Ð\9dаÑ\81Ñ\82Ñ\80ойки и пеÑ\80еменнÑ\8bе Ñ\81Ñ\80едÑ\8b](./advanced/settings.md).
+Ð\9fодÑ\80обнее об иÑ\81полÑ\8cзовании пеÑ\80еменнÑ\8bÑ\85 окÑ\80Ñ\83жениÑ\8f длÑ\8f Ñ\80абоÑ\82Ñ\8b Ñ\81 **наÑ\81Ñ\82Ñ\80ойками пÑ\80иложениÑ\8f** вÑ\8b Ñ\83знаеÑ\82е в [РаÑ\81Ñ\88иÑ\80енном Ñ\80Ñ\83ководÑ\81Ñ\82ве полÑ\8cзоваÑ\82елÑ\8f - Ð\9dаÑ\81Ñ\82Ñ\80ойки и пеÑ\80еменнÑ\8bе окÑ\80Ñ\83жениÑ\8f](./advanced/settings.md).
## Переменная окружения `PATH` { #path-environment-variable }
////
-ÐÑ\82а инÑ\84оÑ\80маÑ\86иÑ\8f бÑ\83деÑ\82 полезна пÑ\80и изÑ\83Ñ\87ении [Ð\92иртуальных окружений](virtual-environments.md).
+ÐÑ\82а инÑ\84оÑ\80маÑ\86иÑ\8f бÑ\83деÑ\82 полезна пÑ\80и изÑ\83Ñ\87ении [виртуальных окружений](virtual-environments.md).
## Вывод { #conclusion }
Благодаря этому вы должны иметь базовое представление о том, что такое **переменные окружения** и как использовать их в Python.
-Ð\9fодÑ\80обнее о ниÑ\85 вÑ\8b Ñ\82акже можеÑ\82е пÑ\80оÑ\87иÑ\82аÑ\82Ñ\8c в [Ñ\81Ñ\82аÑ\82Ñ\8cе о пеÑ\80еменнÑ\8bÑ\85 окÑ\80Ñ\83жениÑ\8f на википедии](https://en.wikipedia.org/wiki/Environment_variable).
+Ð\9fодÑ\80обнее о ниÑ\85 вÑ\8b Ñ\82акже можеÑ\82е пÑ\80оÑ\87иÑ\82аÑ\82Ñ\8c в [Ñ\81Ñ\82аÑ\82Ñ\8cе о пеÑ\80еменнÑ\8bÑ\85 окÑ\80Ñ\83жениÑ\8f на Ð\92икипедии](https://en.wikipedia.org/wiki/Environment_variable).
Во многих случаях не всегда очевидно, как переменные окружения могут быть полезны и применимы. Но они постоянно появляются в различных сценариях разработки, поэтому знать о них полезно.
-Ð\9dапÑ\80имеÑ\80, Ñ\8dÑ\82а инÑ\84оÑ\80маÑ\86иÑ\8f понадобиÑ\82Ñ\81Ñ\8f вам в Ñ\81ледÑ\83Ñ\8eÑ\89ем Ñ\80азделе, поÑ\81вÑ\8fÑ\89енном [Ð\92иртуальным окружениям](virtual-environments.md).
+Ð\9dапÑ\80имеÑ\80, Ñ\8dÑ\82а инÑ\84оÑ\80маÑ\86иÑ\8f понадобиÑ\82Ñ\81Ñ\8f вам в Ñ\81ледÑ\83Ñ\8eÑ\89ем Ñ\80азделе, поÑ\81вÑ\8fÑ\89енном [виртуальным окружениям](virtual-environments.md).
* [**Swagger UI**](https://github.com/swagger-api/swagger-ui), с интерактивным исследованием, вызовом и тестированием вашего API прямо из браузера.
-
+
* Альтернативная документация API в [**ReDoc**](https://github.com/Rebilly/ReDoc).
from pydantic import BaseModel
-# Ð\9eбÑ\8aÑ\8fвлÑ\8fем паÑ\80амеÑ\82Ñ\80 как `str`
+# Ð\9eбÑ\8aÑ\8fвлÑ\8fем пеÑ\80еменнÑ\83Ñ\8e как `str`
# и получаем поддержку редактора кода внутри функции
def main(user_id: str):
return user_id
///
-### Поддержка редакторов { #editor-support }
+### Поддержка редакторов кода { #editor-support }
-Весь фреймворк был продуман так, чтобы быть простым и интуитивно понятным в использовании, все решения были проверены на множестве редакторов еще до начала разработки, чтобы обеспечить наилучшие условия при написании кода.
+Ð\92еÑ\81Ñ\8c Ñ\84Ñ\80еймвоÑ\80к бÑ\8bл пÑ\80одÑ\83ман Ñ\82ак, Ñ\87Ñ\82обÑ\8b бÑ\8bÑ\82Ñ\8c пÑ\80оÑ\81Ñ\82Ñ\8bм и инÑ\82Ñ\83иÑ\82ивно понÑ\8fÑ\82нÑ\8bм в иÑ\81полÑ\8cзовании, вÑ\81е Ñ\80еÑ\88ениÑ\8f бÑ\8bли пÑ\80овеÑ\80енÑ\8b на множеÑ\81Ñ\82ве Ñ\80едакÑ\82оÑ\80ов кода еÑ\89е до наÑ\87ала Ñ\80азÑ\80абоÑ\82ки, Ñ\87Ñ\82обÑ\8b обеÑ\81пеÑ\87иÑ\82Ñ\8c наилÑ\83Ñ\87Ñ\88ие Ñ\83Ñ\81ловиÑ\8f пÑ\80и напиÑ\81ании кода.
В опросах Python‑разработчиков видно, [что одной из самых часто используемых функций является «автозавершение»](https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features).
Вам редко нужно будет возвращаться к документации.
-Вот как ваш редактор может вам помочь:
+Ð\92оÑ\82 как ваÑ\88 Ñ\80едакÑ\82оÑ\80 кода можеÑ\82 вам помоÑ\87Ñ\8c:
* в [Visual Studio Code](https://code.visualstudio.com/):
-
+
* в [PyCharm](https://www.jetbrains.com/pycharm/):
-
+
Вы будете получать автозавершение кода даже там, где вы считали это невозможным раньше. Как пример, ключ `price` внутри тела JSON (который может быть вложенным), приходящего в запросе.
Любая интеграция разработана настолько простой в использовании (с зависимостями), что вы можете создать «плагин» для своего приложения в пару строк кода, используя ту же структуру и синтаксис, что и для ваших *операций пути*.
-### Проверен { #tested }
+### Протестирован { #tested }
-* 100% <dfn title="Количество автоматически проверяемого кода">покрытие тестами</dfn>.
+* 100% <dfn title="Количество автоматически протестированного кода">покрытие тестами</dfn>.
* 100% <dfn title="Аннотации типов Python, благодаря которым ваш редактор кода и внешние инструменты могут обеспечить вам лучшую поддержку">аннотирование типов</dfn> в кодовой базе.
-* Ð\98Ñ\81полÑ\8cзÑ\83еÑ\82Ñ\81Ñ\8f в пÑ\80одакÑ\88нâ\80\91пÑ\80иложениÑ\8fÑ\85.
+* Ð\98Ñ\81полÑ\8cзÑ\83еÑ\82Ñ\81Ñ\8f в пÑ\80иложениÑ\8fÑ\85 в пÑ\80одакÑ\88н.
## Возможности Starlette { #starlette-features }
* **Никакой нервотрёпки**:
* Не нужно изучать новые схемы в микроязыках.
* Если вы знаете типы в Python, вы знаете, как использовать Pydantic.
-* Ð\9fÑ\80екÑ\80аÑ\81но Ñ\81оÑ\87еÑ\82аеÑ\82Ñ\81Ñ\8f Ñ\81 ваÑ\88им **<abbr title="Integrated Development Environment - Ð\98нÑ\82егÑ\80иÑ\80ованнаÑ\8f Ñ\81Ñ\80еда Ñ\80азÑ\80абоÑ\82ки: поÑ\85оже на редактор кода">IDE</abbr>/<dfn title="Программа, которая проверяет код на ошибки">линтер</dfn>/мозгом**:
+* Ð\9fÑ\80екÑ\80аÑ\81но Ñ\81оÑ\87еÑ\82аеÑ\82Ñ\81Ñ\8f Ñ\81 ваÑ\88им **<abbr title="Integrated Development Environment - Ð\98нÑ\82егÑ\80иÑ\80ованнаÑ\8f Ñ\81Ñ\80еда Ñ\80азÑ\80абоÑ\82ки: поÑ\85ожаÑ\8f на редактор кода">IDE</abbr>/<dfn title="Программа, которая проверяет код на ошибки">линтер</dfn>/мозгом**:
* Потому что структуры данных pydantic — это всего лишь экземпляры классов, определённых вами; автозавершение, проверка кода, mypy и ваша интуиция — всё будет работать с вашими валидированными данными.
* Валидация **сложных структур**:
* Использование иерархических моделей Pydantic; `List`, `Dict` и т.п. из модуля `typing`.
## Подписаться на автора { #follow-the-author }
-Вы можете подписаться на [меня (Sebastián Ramírez / `tiangolo`)](https://tiangolo.com) в нескольких местах, чтобы узнавать новости о FastAPI и друзьях:
+Вы можете подписаться на [меня (Sebastián Ramírez / `tiangolo`)](https://tiangolo.com), автора, в нескольких местах, чтобы узнавать новости о FastAPI и друзьях:
* [@tiangolo в **GitHub**](https://github.com/tiangolo).
* [@tiangolo в **X (Twitter)**](https://x.com/tiangolo)
## Изменить тему { #change-the-theme }
-Аналогично вы можете задать тему подсветки синтаксиса с ключом "syntaxHighlight.theme" (обратите внимание, что посередине стоит точка):
+Аналогично вы можете задать тему подсветки синтаксиса с ключом `"syntaxHighlight.theme"` (обратите внимание, что посередине стоит точка):
{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}
Некоторые сценарии:
-* Преобразование тел запросов, не в формате JSON, в JSON (например, [`msgpack`](https://msgpack.org/index.html)).
+* Преобразование тел запросов не в формате JSON в JSON (например, [`msgpack`](https://msgpack.org/index.html)).
* Распаковка тел запросов, сжатых с помощью gzip.
* Автоматическое логирование всех тел запросов.
## Обработка пользовательского кодирования тела запроса { #handling-custom-request-body-encodings }
-Посмотрим как использовать пользовательский подкласс `Request` для распаковки gzip-запросов.
+Посмотрим, как использовать пользовательский подкласс `Request` для распаковки gzip-запросов.
И подкласс `APIRoute`, чтобы использовать этот пользовательский класс запроса.
Сначала создадим класс `GzipRequest`, который переопределит метод `Request.body()` и распакует тело запроса при наличии соответствующего HTTP-заголовка.
-Если в заголовке нет `gzip`, он не будет пытаться распаковывать тело.
+Если в HTTP-заголовке нет `gzip`, он не будет пытаться распаковывать тело.
-Таким образом, один и тот же класс маршрута сможет обрабатывать как gzip-сжатые, так и несжатые запросы.
+Таким образом, один и тот же класс маршрута сможет обрабатывать как gzip-сжатые, так и несжатые HTTP-запросы.
{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}
Тем же подходом можно воспользоваться, чтобы получить доступ к телу запроса в обработчике исключений.
-Нужно лишь обработать запрос внутри блока `try`/`except`:
+Нужно лишь обработать HTTP-запрос внутри блока `try`/`except`:
{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *}
{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}
-В этом примере *операции пути*, объявленные в `router`, будут использовать пользовательский класс `TimedRoute` и получат дополнительный HTTP-заголовок `X-Response-Time` в ответе с временем, затраченным на формирование ответа:
+В этом примере *операции пути*, объявленные в `router`, будут использовать пользовательский класс `TimedRoute` и получат дополнительный HTTP-заголовок `X-Response-Time` в HTTP-ответе с временем, затраченным на формирование HTTP-ответа:
{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}
# GraphQL { #graphql }
+
Так как **FastAPI** основан на стандарте **ASGI**, очень легко интегрировать любую библиотеку **GraphQL**, также совместимую с ASGI.
Вы можете комбинировать обычные *операции пути* FastAPI с GraphQL в одном приложении.
FastAPI 0.126.0 убрал поддержку Pydantic v1, при этом ещё некоторое время продолжал поддерживать `pydantic.v1`.
+FastAPI 0.128.0 также убрал поддержку `pydantic.v1`, так что последние версии FastAPI требуют Pydantic v2.
+
/// warning | Предупреждение
Команда Pydantic прекратила поддержку Pydantic v1 для последних версий Python, начиная с **Python 3.14**.
### Поддержка FastAPI для Pydantic v1 внутри v2 { #fastapi-support-for-pydantic-v1-in-v2 }
+/// warning | Предупреждение
+
+Эта поддержка FastAPI для моделей `pydantic.v1` была добавлена в **FastAPI 0.119.0** и удалена в **FastAPI 0.128.0**. Она задумывалась как временная помощь при миграции на Pydantic v2.
+
+В текущих версиях FastAPI использование модели `pydantic.v1` в вашем приложении вызовет ошибку.
+
+Остальная часть этого раздела описывает временную поддержку, доступную только в этих старых версиях.
+
+///
+
Начиная с FastAPI 0.119.0, есть также частичная поддержка Pydantic v1 изнутри Pydantic v2, чтобы упростить миграцию на v2.
Таким образом, вы можете обновить Pydantic до последней версии 2 и сменить импорты на подмодуль `pydantic.v1` — во многих случаях всё просто заработает.
### Мигрируйте по шагам { #migrate-in-steps }
+/// warning | Предупреждение
+
+Постепенная миграция с использованием моделей Pydantic v1 и v2 в одном приложении, описанная ниже, работает только в **FastAPI 0.119.0 до 0.127.x**. Она была удалена в **FastAPI 0.128.0**, последние версии требуют модели **Pydantic v2**.
+
+///
+
/// tip | Совет
Сначала попробуйте `bump-pydantic`: если тесты проходят и всё работает, вы справились одной командой. ✨
# Разделять схемы OpenAPI для входа и выхода или нет { #separate-openapi-schemas-for-input-and-output-or-not }
-Ð\9fÑ\80и иÑ\81полÑ\8cзовании **Pydantic v2** сгенерированный OpenAPI становится чуть более точным и **корректным**, чем раньше. 😎
+С моменÑ\82а вÑ\8bÑ\85ода **Pydantic v2** сгенерированный OpenAPI становится чуть более точным и **корректным**, чем раньше. 😎
На самом деле, в некоторых случаях в OpenAPI будет даже **две JSON-схемы** для одной и той же Pydantic‑модели: для входа и для выхода — в зависимости от наличия **значений по умолчанию**.
<!-- sponsors -->
-### Ключевой-спонсор { #keystone-sponsor }
+### Ключевой спонсор { #keystone-sponsor }
<div class="fastapi-sponsors fastapi-sponsors--keystone">
{% for sponsor in sponsors.keystone -%}
В конце 2025 года вышел [мини-документальный фильм о FastAPI](https://www.youtube.com/watch?v=mpR8ngthqiE), вы можете посмотреть его онлайн:
-<a class="fastapi-feature-banner" href="https://www.youtube.com/watch?v=mpR8ngthqiE"><img src="https://fastapi.tiangolo.com/img/fastapi-documentary.jpg" alt="FastAPI Mini Documentary"></a>
+<a class="fastapi-feature-banner" href="https://www.youtube.com/watch?v=mpR8ngthqiE"><img src="https://fastapi.tiangolo.com/img/fastapi-documentary.jpg" alt="Мини-документальный фильм о FastAPI"></a>
## **Typer**, FastAPI для CLI { #typer-the-fastapi-of-clis }
* Нажмите кнопку «Try it out», это позволит вам заполнить параметры и напрямую взаимодействовать с API:
-
+
* Затем нажмите кнопку «Execute», интерфейс свяжется с вашим API, отправит параметры, получит результаты и отобразит их на экране:
-
+
### Обновление альтернативной документации API { #alternative-api-docs-upgrade }
...и посмотрите, как ваш редактор кода будет автоматически дополнять атрибуты и знать их типы:
-
+
Более полный пример с дополнительными возможностями см. в <a href="https://fastapi.tiangolo.com/ru/tutorial/">Учебник - Руководство пользователя</a>.
#### Развертывание у других облачных провайдеров { #deploy-to-other-cloud-providers }
-FastAPI — это open source и стандартизированный фреймворк. Вы можете развернуть приложения FastAPI у любого облачного провайдера на ваш выбор.
+FastAPI — это проект с открытым исходным кодом, основанный на стандартах. Вы можете развернуть приложения FastAPI у любого облачного провайдера на ваш выбор.
Следуйте руководствам вашего облачного провайдера по развертыванию приложений FastAPI. 🤓
Используется Pydantic:
-* [`email-validator`](https://github.com/JoshData/python-email-validator) â\80\94 длÑ\8f пÑ\80овеÑ\80ки адресов электронной почты.
+* [`email-validator`](https://github.com/JoshData/python-email-validator) â\80\94 длÑ\8f валидаÑ\86ии адресов электронной почты.
Используется Starlette:
- 🦇 Поддержка тёмной темы.
- 🐋 [Docker Compose](https://www.docker.com) для разработки и продакшн.
- 🔒 Безопасное хэширование паролей по умолчанию.
-- 🔑 Аутентификация по JWT‑токенам.
+- 🔑 Аутентификация JWT (JSON Web Token).
- 📫 Восстановление пароля по электронной почте.
- ✅ Тесты с [Pytest](https://pytest.org).
- 📞 [Traefik](https://traefik.io) в роли обратного прокси / балансировщика нагрузки.
- 🚢 Инструкции по развёртыванию с использованием Docker Compose, включая настройку фронтенд‑прокси Traefik для автоматического получения сертификатов HTTPS.
-- 🏭 CI (continuous integration) и CD (continuous deployment) на основе GitHub Actions.
+- 🏭 CI (непрерывная интеграция) и CD (непрерывное развертывание) на основе GitHub Actions.
# Введение в типы Python { #python-types-intro }
-Python поддеÑ\80живаеÑ\82 необÑ\8fзаÑ\82елÑ\8cнÑ\8bе «подÑ\81казки Ñ\82ипов» (иÑ\85 Ñ\82акже назÑ\8bваÑ\8eÑ\82 «анноÑ\82аÑ\86иÑ\8fми типов»).
+Python поддеÑ\80живаеÑ\82 необÑ\8fзаÑ\82елÑ\8cнÑ\8bе «анноÑ\82аÑ\86ии Ñ\82ипов» (Ñ\82акже назÑ\8bваемÑ\8bе «подÑ\81казками типов»).
-ÐÑ\82и **«подÑ\81казки Ñ\82ипов»** или анноÑ\82аÑ\86ии — это специальный синтаксис, позволяющий объявлять <dfn title="например: str, int, float, bool">тип</dfn> переменной.
+ÐÑ\82и **«анноÑ\82аÑ\86ии Ñ\82ипов»**, или пÑ\80оÑ\81Ñ\82о анноÑ\82аÑ\86ии, — это специальный синтаксис, позволяющий объявлять <dfn title="например: str, int, float, bool">тип</dfn> переменной.
Объявляя типы для ваших переменных, редакторы кода и инструменты смогут лучше вас поддерживать.
-Это всего лишь **краткое руководство / напоминание** о подсказках типов в Python. Оно охватывает только минимум, необходимый для их использования с **FastAPI**... что на самом деле очень мало.
+Это всего лишь **краткое руководство / напоминание** об аннотациях типов в Python. Оно охватывает только минимум, необходимый для их использования с **FastAPI**... что на самом деле очень мало.
-**FastAPI** Ñ\86еликом оÑ\81нован на Ñ\8dÑ\82иÑ\85 подÑ\81казках типов — они дают ему множество преимуществ и выгод.
+**FastAPI** Ñ\86еликом оÑ\81нован на Ñ\8dÑ\82иÑ\85 анноÑ\82аÑ\86иÑ\8fх типов — они дают ему множество преимуществ и выгод.
Но даже если вы никогда не используете **FastAPI**, вам будет полезно немного узнать о них.
/// note | Примечание
-Если вы являетесь экспертом в Python и уже знаете всё о подсказках типов, переходите к следующей главе.
+Если вы являетесь экспертом в Python и уже знаете всё об аннотациях типов, переходите к следующей главе.
///
Вот и всё.
-ÐÑ\82о и еÑ\81Ñ\82Ñ\8c «подÑ\81казки типов»:
+ÐÑ\82о и еÑ\81Ñ\82Ñ\8c «анноÑ\82аÑ\86ии типов»:
{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}
Здесь мы используем двоеточия (`:`), а не знак равенства (`=`).
-Ð\98 добавление подÑ\81казок типов обычно не меняет поведение программы по сравнению с вариантом без них.
+Ð\98 добавление анноÑ\82аÑ\86ий типов обычно не меняет поведение программы по сравнению с вариантом без них.
-Ð\9dо Ñ\82епеÑ\80Ñ\8c пÑ\80едÑ\81Ñ\82авÑ\8cÑ\82е, Ñ\87Ñ\82о вÑ\8b Ñ\81нова поÑ\81еÑ\80едине напиÑ\81аниÑ\8f Ñ\8dÑ\82ой Ñ\84Ñ\83нкÑ\86ии, Ñ\82олÑ\8cко Ñ\83же Ñ\81 подÑ\81казками типов.
+Ð\9dо Ñ\82епеÑ\80Ñ\8c пÑ\80едÑ\81Ñ\82авÑ\8cÑ\82е, Ñ\87Ñ\82о вÑ\8b Ñ\81нова поÑ\81еÑ\80едине напиÑ\81аниÑ\8f Ñ\8dÑ\82ой Ñ\84Ñ\83нкÑ\86ии, Ñ\82олÑ\8cко Ñ\83же Ñ\81 анноÑ\82аÑ\86иÑ\8fми типов.
В тот же момент вы пробуете вызвать автозавершение с помощью `Ctrl+Space` — и видите:
## Больше мотивации { #more-motivation }
-Ð\9fоÑ\81моÑ\82Ñ\80иÑ\82е на Ñ\8dÑ\82Ñ\83 Ñ\84Ñ\83нкÑ\86иÑ\8e â\80\94 Ñ\83 неÑ\91 Ñ\83же еÑ\81Ñ\82Ñ\8c подÑ\81казки типов:
+Ð\9fоÑ\81моÑ\82Ñ\80иÑ\82е на Ñ\8dÑ\82Ñ\83 Ñ\84Ñ\83нкÑ\86иÑ\8e â\80\94 Ñ\83 неÑ\91 Ñ\83же еÑ\81Ñ\82Ñ\8c анноÑ\82аÑ\86ии типов:
{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}
## Объявление типов { #declaring-types }
-Ð\92Ñ\8b Ñ\82олÑ\8cко Ñ\87Ñ\82о Ñ\83видели оÑ\81новное меÑ\81Ñ\82о, где обÑ\8aÑ\8fвлÑ\8fÑ\8eÑ\82 подÑ\81казки типов — параметры функции.
+Ð\92Ñ\8b Ñ\82олÑ\8cко Ñ\87Ñ\82о Ñ\83видели оÑ\81новное меÑ\81Ñ\82о, где обÑ\8aÑ\8fвлÑ\8fÑ\8eÑ\82 анноÑ\82аÑ\86ии типов — параметры функции.
Это также основное место, где вы будете использовать их с **FastAPI**.
Вы увидите намного больше всего этого на практике в [Учебник - Руководство пользователя](tutorial/index.md).
-## Ð\9fодÑ\81казки типов с аннотациями метаданных { #type-hints-with-metadata-annotations }
+## Ð\90нноÑ\82аÑ\86ии типов с аннотациями метаданных { #type-hints-with-metadata-annotations }
-Ð\92 Python Ñ\82акже еÑ\81Ñ\82Ñ\8c возможноÑ\81Ñ\82Ñ\8c добавлÑ\8fÑ\82Ñ\8c **дополниÑ\82елÑ\8cнÑ\8bе <dfn title="Ð\94аннÑ\8bе о даннÑ\8bÑ\85, в данном Ñ\81лÑ\83Ñ\87ае â\80\94 инÑ\84оÑ\80маÑ\86иÑ\8f о Ñ\82ипе, напÑ\80имеÑ\80 опиÑ\81ание.">меÑ\82аданнÑ\8bе</dfn>** к подÑ\81казкам типов с помощью `Annotated`.
+Ð\92 Python Ñ\82акже еÑ\81Ñ\82Ñ\8c возможноÑ\81Ñ\82Ñ\8c добавлÑ\8fÑ\82Ñ\8c **дополниÑ\82елÑ\8cнÑ\8bе <dfn title="Ð\94аннÑ\8bе о даннÑ\8bÑ\85, в данном Ñ\81лÑ\83Ñ\87ае â\80\94 инÑ\84оÑ\80маÑ\86иÑ\8f о Ñ\82ипе, напÑ\80имеÑ\80 опиÑ\81ание.">меÑ\82аданнÑ\8bе</dfn>** к анноÑ\82аÑ\86иÑ\8fм типов с помощью `Annotated`.
Вы можете импортировать `Annotated` из `typing`.
## Аннотации типов в **FastAPI** { #type-hints-in-fastapi }
-**FastAPI** иÑ\81полÑ\8cзÑ\83еÑ\82 Ñ\8dÑ\82и подÑ\81казки типов для выполнения нескольких задач.
+**FastAPI** иÑ\81полÑ\8cзÑ\83еÑ\82 Ñ\8dÑ\82и анноÑ\82аÑ\86ии типов для выполнения нескольких задач.
-С **FastAPI** вÑ\8b обÑ\8aÑ\8fвлÑ\8fеÑ\82е паÑ\80амеÑ\82Ñ\80Ñ\8b Ñ\81 подÑ\81казками типов и получаете:
+С **FastAPI** вÑ\8b обÑ\8aÑ\8fвлÑ\8fеÑ\82е паÑ\80амеÑ\82Ñ\80Ñ\8b Ñ\81 анноÑ\82аÑ\86иÑ\8fми типов и получаете:
* **Поддержку редактора кода**.
* **Проверки типов**.
...и **FastAPI** использует эти же объявления для:
-* **Определения требований**: из path-параметров пути запроса, query-параметров, HTTP-заголовков, тел запросов, зависимостей и т.д.
+* **Определения требований**: из path-параметров HTTP-запроса, query-параметров, HTTP-заголовков, тел запросов, зависимостей и т.д.
* **Преобразования данных**: из HTTP-запроса к требуемому типу.
* **Валидации данных**: приходящих с каждого HTTP-запроса:
* Генерации **автоматических ошибок**, возвращаемых клиенту, когда данные некорректны.
```
.
├── app
-│ ├── __init__.py
-│ ├── main.py
-│ ├── dependencies.py
-│ └── routers
-│ │ ├── __init__.py
-│ │ ├── items.py
-│ │ └── users.py
-│ └── internal
-│ ├── __init__.py
-│ └── admin.py
+│ ├── __init__.py
+│ ├── main.py
+│ ├── dependencies.py
+│ └── routers
+│ │ ├── __init__.py
+│ │ ├── items.py
+│ │ └── users.py
+│ └── internal
+│ ├── __init__.py
+│ └── admin.py
```
/// tip | Подсказка
```bash
.
-├── app # "app" пакет
+├── app # "app" — Python-пакет
│ ├── __init__.py # этот файл превращает "app" в "Python-пакет"
│ ├── main.py # модуль "main", напр.: import app.main
│ ├── dependencies.py # модуль "dependencies", напр.: import app.dependencies
-│ └── routers # подпакет "routers"
-│ │ ├── __init__.py # превращает "routers" в подпакет
+│ └── routers # "routers" — "Python-подпакет"
+│ │ ├── __init__.py # превращает "routers" в "Python-подпакет"
│ │ ├── items.py # подмодуль "items", напр.: import app.routers.items
│ │ └── users.py # подмодуль "users", напр.: import app.routers.users
-│ └── internal # подпакет "internal"
-│ ├── __init__.py # превращает "internal" в подпакет
+│ └── internal # "internal" — "Python-подпакет"
+│ ├── __init__.py # превращает "internal" в "Python-подпакет"
│ └── admin.py # подмодуль "admin", напр.: import app.internal.admin
```
/// tip | Подсказка
-Для простоты мы воспользовались выдуманным заголовком.
+Для простоты мы воспользовались выдуманным HTTP-заголовком.
В реальных случаях для получения наилучших результатов используйте интегрированные [утилиты безопасности](security/index.md).
В нашем случае префиксом является `/items`.
-Мы также можем добавить список `tags` и дополнительные `responses`, которые будут применяться ко всем *операциям пути*, включённым в этот маршрутизатор.
+Мы также можем добавить список `tags` и дополнительные `responses`, которые будут применяться ко всем *операциям пути*, включённым в этот роутер.
-И ещё мы можем добавить список `dependencies`, которые будут добавлены ко всем *операциям пути* в маршрутизаторе и будут выполняться/разрешаться для каждого HTTP-запроса к ним.
+И ещё мы можем добавить список `dependencies`, которые будут добавлены ко всем *операциям пути* в роутере и будут выполняться/разрешаться для каждого HTTP-запроса к ним.
/// tip | Подсказка
* Все они будут включать предопределённые `responses`.
* Все эти *операции пути* будут иметь список `dependencies`, вычисляемых/выполняемых перед ними.
* Если вы также объявите зависимости в конкретной *операции пути*, **они тоже будут выполнены**.
- * Сначала выполняются зависимости маршрутизатора, затем [`dependencies` в декораторе](dependencies/dependencies-in-path-operation-decorators.md), и затем обычные параметрические зависимости.
+ * Сначала выполняются зависимости роутера, затем [`dependencies` в декораторе](dependencies/dependencies-in-path-operation-decorators.md), и затем обычные параметрические зависимости.
* Вы также можете добавить [`Security`-зависимости с `scopes`](../advanced/security/oauth2-scopes.md).
/// tip | Подсказка
то это бы означало:
-* Начать в том же пакете, в котором находится этот модуль (файл `app/routers/items.py`) расположен в (каталоге `app/routers/`)...
+* Начать в том же пакете, в котором находится этот модуль (файл `app/routers/items.py`) (каталог `app/routers/`)...
* перейти в родительский пакет (каталог `app/`)...
* затем перейти в родительский пакет этого пакета (родительского пакета нет, `app` — верхний уровень 😱)...
* и там найти модуль `dependencies` (файл `app/dependencies.py`)...
Эта последняя операция пути будет иметь комбинацию тегов: `["items", "custom"]`.
-И в документации у неё будут оба ответа: один для `404` и один для `403`.
+И в документации у неё будут оба HTTP-ответа: один для `404` и один для `403`.
///
означает:
-* Начать в том же пакете, в котором находится этот модуль (файл `app/main.py`) расположен в (каталоге `app/`)...
+* Начать в том же пакете, в котором находится этот модуль (файл `app/main.py`) (каталог `app/`)...
* найти подпакет `routers` (каталог `app/routers/`)...
* и импортировать из него подмодули `items` (файл `app/routers/items.py`) и `users` (файл `app/routers/users.py`)...
С помощью `app.include_router()` мы можем добавить каждый `APIRouter` в основное приложение `FastAPI`.
-Он включит все маршруты этого маршрутизатора как часть приложения.
+Он включит все маршруты этого роутера как часть приложения.
/// note | Технические детали
-FastAPI сохраняет исходный `APIRouter` и его `APIRoute` активными, когда маршрутизатор включается в основное приложение.
+FastAPI сохраняет исходный `APIRouter` и его `APIRoute` активными, когда роутер включается в основное приложение.
-Это означает, что пользовательские подклассы `APIRouter` и `APIRoute` по-прежнему участвуют после подключения маршрутизатора.
+Это означает, что пользовательские подклассы `APIRouter` и `APIRoute` по-прежнему участвуют после подключения роутера.
///
/// tip | Подсказка
-При подключении маршрутизаторов не нужно беспокоиться о производительности.
+При подключении роутеров не нужно беспокоиться о производительности.
Это сделано максимально лёгким и не добавляет накладных расходов на каждый запрос.
* Префикс `/admin`.
* Тег `admin`.
* Зависимость `get_token_header`.
-* Ответ `418`. 🍵
+* HTTP-ответ `418`. 🍵
Но это повлияет только на этот `APIRouter` в нашем приложении, а не на любой другой код, который его использует.
Это потому, что мы хотим включить их *операции пути* в схему OpenAPI и пользовательские интерфейсы.
-FastAPI сохраняет исходные маршрутизаторы и операции пути активными и комбинирует префиксы маршрутизаторов, зависимости, теги, ответы и другие метаданные при обработке запросов и генерации OpenAPI.
+FastAPI сохраняет исходные роутеры и операции пути активными и комбинирует префиксы роутеров, зависимости, теги, HTTP-ответы и другие метаданные при обработке HTTP-запросов и генерации OpenAPI.
///
<img src="/img/tutorial/bigger-applications/image01.png">
-## Подключение одного и того же маршрутизатора несколько раз с разными `prefix` { #include-the-same-router-multiple-times-with-different-prefix }
+## Подключение одного и того же роутера несколько раз с разными `prefix` { #include-the-same-router-multiple-times-with-different-prefix }
-Вы можете использовать `.include_router()` несколько раз с *одним и тем же* маршрутизатором, используя разные префиксы.
+Вы можете использовать `.include_router()` несколько раз с *одним и тем же* роутером, используя разные префиксы.
Это может быть полезно, например, чтобы предоставить доступ к одному и тому же API с разными префиксами, например `/api/v1` и `/api/latest`.
Вы можете сделать это до или после подключения `router` к приложению `FastAPI`. FastAPI всё равно включит *операции пути* из `other_router` в маршрутизацию и OpenAPI.
-То же относится к *операциям пути*, добавленным позже в маршрутизаторы. Они также будут видны через более раннее включение.
+То же относится к *операциям пути*, добавленным позже в роутеры. Они также будут видны через более раннее включение.
/// warning | Технические детали
-Избегайте прямой мутации `router.routes` после включения маршрутизатора. FastAPI рассматривает включение маршрутизатора как «живое», поэтому исходный маршрутизатор и его маршруты остаются частью маршрутизации и генерации OpenAPI.
+Избегайте прямой мутации `router.routes` после включения роутера. FastAPI рассматривает включение роутера как «живое», поэтому исходный роутер и его маршруты остаются частью маршрутизации и генерации OpenAPI.
-Используйте документированные API, такие как декораторы операций пути и `.include_router()`, чтобы добавлять маршруты и маршрутизаторы.
+Используйте документированные API, такие как декораторы операций пути и `.include_router()`, чтобы добавлять маршруты и роутеры.
-Считайте `router.routes` низкоуровневым деревом маршрутов, которое может содержать определения маршрутов и включённые маршрутизаторы, и избегайте воспринимать его как плоский список итоговых операций пути.
+Считайте `router.routes` низкоуровневым деревом маршрутов, которое может содержать определения маршрутов и включённые роутеры, и избегайте воспринимать его как плоский список итоговых операций пути.
///
## Поля-списки с параметром типа { #list-fields-with-type-parameter }
-Ð\92 Python есть специальный способ объявлять списки с внутренними типами, или «параметрами типа»:
+Ð\9dо в Python есть специальный способ объявлять списки с внутренними типами, или «параметрами типа»:
### Объявите `list` с параметром типа { #declare-a-list-with-a-type-parameter }
{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}
-ТакаÑ\8f Ñ\80еализаÑ\86иÑ\8f бÑ\83деÑ\82 ожидаÑ\82Ñ\8c (конвеÑ\80Ñ\82иÑ\80оваÑ\82Ñ\8c, валидиÑ\80оваÑ\82Ñ\8c, докÑ\83менÑ\82иÑ\80оваÑ\82Ñ\8c и Ñ\82.д.) JSON-Ñ\81одеÑ\80жимое в следующем формате:
+ТакаÑ\8f Ñ\80еализаÑ\86иÑ\8f бÑ\83деÑ\82 ожидаÑ\82Ñ\8c (конвеÑ\80Ñ\82иÑ\80оваÑ\82Ñ\8c, валидиÑ\80оваÑ\82Ñ\8c, докÑ\83менÑ\82иÑ\80оваÑ\82Ñ\8c и Ñ\82.д.) JSON-Ñ\82ело запÑ\80оÑ\81а в следующем формате:
```JSON hl_lines="11"
{
///
-## Тела с чистыми списками элементов { #bodies-of-pure-lists }
+## Тела запросов с чистыми списками элементов { #bodies-of-pure-lists }
-Если верхний уровень значения тела JSON-объекта представляет собой JSON `array` (в Python — `list`), вы можете объявить тип в параметре функции, так же как в моделях Pydantic:
+Если верхний уровень значения JSON-тела запроса представляет собой JSON `array` (в Python — `list`), вы можете объявить тип в параметре функции, так же как в моделях Pydantic:
```Python
images: list[Image]
С помощью **FastAPI** вы получаете максимальную гибкость, предоставляемую моделями Pydantic, сохраняя при этом простоту, краткость и элегантность вашего кода.
-Ð\98 дополниÑ\82елÑ\8cно вÑ\8b полÑ\83Ñ\87аеÑ\82е:
+Ð\9dо Ñ\81о вÑ\81еми пÑ\80еимÑ\83Ñ\89еÑ\81Ñ\82вами:
* Поддержку редактора кода (автозавершение доступно везде!)
* Преобразование данных (также известно как парсинг / сериализация)
* Считает тело запроса как JSON.
* Приведёт данные к соответствующим типам (если потребуется).
* Проведёт валидацию данных.
- * Если данные некорректны, вернёт понятную и наглядную ошибку, указывающую, где именно и что было некорректно.
+ * Если данные некорректны, вернёт понятную и наглядную ошибку, указывающую, где именно and что было некорректно.
* Передаст полученные данные в параметр `item`.
* Поскольку внутри функции вы объявили его с типом `Item`, у вас будет поддержка со стороны редактора кода (автозавершение и т.п.) для всех атрибутов и их типов.
* Сгенерирует определения [JSON Schema](https://json-schema.org) для вашей модели; вы можете использовать их и в других местах, если это имеет смысл для вашего проекта.
# Отладка { #debugging }
-Вы можете подключить отладчик в своем редакторе, например, в Visual Studio Code или PyCharm.
+Вы можете подключить отладчик в своем редакторе кода, например, в Visual Studio Code или PyCharm.
## Вызов `uvicorn` { #call-uvicorn }
-Ð\92 ваÑ\88ем FastAPI пÑ\80иложении, импоÑ\80Ñ\82иÑ\80Ñ\83йÑ\82е и вÑ\8bзовите `uvicorn` напрямую:
+Ð\92 ваÑ\88ем FastAPI пÑ\80иложении, импоÑ\80Ñ\82иÑ\80Ñ\83йÑ\82е и запÑ\83Ñ\81Ñ\82ите `uvicorn` напрямую:
{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}
# Еще немного кода
```
-Ñ\82о авÑ\82омаÑ\82иÑ\87еÑ\81каÑ\8f Ñ\81оздаваемаÑ\8f внÑ\83Ñ\82Ñ\80и Ñ\84айла `myapp.py` пеÑ\80еменнаÑ\8f `__name__` бÑ\83деÑ\82 имеÑ\82Ñ\8c знаÑ\87ение отличающееся от `"__main__"`.
+Ñ\82о авÑ\82омаÑ\82иÑ\87еÑ\81ки Ñ\81оздаваемаÑ\8f внÑ\83Ñ\82Ñ\80и Ñ\84айла `myapp.py` пеÑ\80еменнаÑ\8f `__name__` бÑ\83деÑ\82 имеÑ\82Ñ\8c знаÑ\87ение, отличающееся от `"__main__"`.
Следовательно, строка:
## Запуск вашего кода с помощью отладчика { #run-your-code-with-your-debugger }
-Так как вÑ\8b запÑ\83Ñ\81каеÑ\82е Ñ\81еÑ\80веÑ\80 Uvicorn непоÑ\81Ñ\80едÑ\81Ñ\82венно из ваÑ\88его кода, вÑ\8b можеÑ\82е вÑ\8bзвать Python программу (ваше FastAPI приложение) напрямую из отладчика.
+Так как вÑ\8b запÑ\83Ñ\81каеÑ\82е Ñ\81еÑ\80веÑ\80 Uvicorn непоÑ\81Ñ\80едÑ\81Ñ\82венно из ваÑ\88его кода, вÑ\8b можеÑ\82е запÑ\83Ñ\81Ñ\82ить Python программу (ваше FastAPI приложение) напрямую из отладчика.
---
### Всегда делайте `raise` в зависимостях с `yield` и `except` { #always-raise-in-dependencies-with-yield-and-except }
-Если вы ловите исключение в зависимости с `yield`, то, если вы не вызываете другой `HTTPException` или что-то подобное, вам следует повторно вызвать исходное исключение.
+Если вы ловите исключение в зависимости с `yield`, то, если вы не вызываете другой `HTTPException` или что-то подобное, **вам следует повторно вызвать исходное исключение**.
Вы можете повторно вызвать то же самое исключение с помощью `raise`:
Зависимости с `yield` со временем эволюционировали, чтобы покрыть разные сценарии и исправить некоторые проблемы.
Если вы хотите посмотреть, что менялось в разных версиях FastAPI, вы можете прочитать об этом подробнее в продвинутом руководстве: [Продвинутые зависимости — зависимости с `yield`, `HTTPException`, `except` и фоновыми задачами](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks).
+
## Контекстные менеджеры { #context-managers }
### Что такое «контекстные менеджеры» { #what-are-context-managers }
При этом у вас останутся те же возможности, что и до сих пор:
* Отличная поддержка редактора кода.
-* Преобразование данных из входящих запросов.
+* Преобразование данных из входящих HTTP-запросов.
* Преобразование данных для ответа.
* Валидация данных.
* Автоматическая аннотация и документация.
* `UUID`:
* Стандартный "Универсальный уникальный идентификатор", используемый в качестве идентификатора во многих базах данных и системах.
- * В запросах и ответах будет представлен как `str`.
+ * В HTTP-запросах и HTTP-ответах будет представлен как `str`.
* `datetime.datetime`:
* Встроенный в Python `datetime.datetime`.
- * В запросах и ответах будет представлен как `str` в формате ISO 8601, например: `2008-09-15T15:53:00+05:00`.
+ * В HTTP-запросах и HTTP-ответах будет представлен как `str` в формате ISO 8601, например: `2008-09-15T15:53:00+05:00`.
* `datetime.date`:
* Встроенный в Python `datetime.date`.
- * В запросах и ответах будет представлен как `str` в формате ISO 8601, например: `2008-09-15`.
+ * В HTTP-запросах и HTTP-ответах будет представлен как `str` в формате ISO 8601, например: `2008-09-15`.
* `datetime.time`:
* Встроенный в Python `datetime.time`.
- * В запросах и ответах будет представлен как `str` в формате ISO 8601, например: `14:23:55.003`.
+ * В HTTP-запросах и HTTP-ответах будет представлен как `str` в формате ISO 8601, например: `14:23:55.003`.
* `datetime.timedelta`:
* Встроенный в Python `datetime.timedelta`.
- * В запросах и ответах будет представлен в виде общего количества секунд типа `float`.
+ * В HTTP-запросах и HTTP-ответах будет представлен в виде общего количества секунд типа `float`.
* Pydantic также позволяет представить его как "Кодировку разницы во времени ISO 8601", [см. документацию для получения дополнительной информации](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers).
* `frozenset`:
- * В запросах и ответах обрабатывается так же, как и `set`:
- * В запросах будет прочитан список, исключены дубликаты и преобразован в `set`.
- * В ответах `set` будет преобразован в `list`.
+ * В HTTP-запросах и HTTP-ответах обрабатывается так же, как и `set`:
+ * В HTTP-запросах будет прочитан список, исключены дубликаты и преобразован в `set`.
+ * В HTTP-ответах `set` будет преобразован в `list`.
* В сгенерированной схеме будет указано, что значения `set` уникальны (с помощью JSON-схемы `uniqueItems`).
* `bytes`:
* Встроенный в Python `bytes`.
- * В запросах и ответах будет рассматриваться как `str`.
- * В сгенерированной схеме будет указано, что это `str` в формате `binary`.
+ * В HTTP-запросах и HTTP-ответах будет рассматриваться как `str`.
+ * В сгенерированной схеме будет указано, что это `str` в "формате" `binary`.
* `Decimal`:
* Встроенный в Python `Decimal`.
- * В запросах и ответах обрабатывается так же, как и `float`.
+ * В HTTP-запросах и HTTP-ответах обрабатывается так же, как и `float`.
* Вы можете проверить все допустимые типы данных Pydantic здесь: [Типы данных Pydantic](https://docs.pydantic.dev/latest/usage/types/types/).
## Пример { #example }
Используйте несколько Pydantic-моделей и свободно применяйте наследование для каждого случая.
-Вам не обязательно иметь единственную модель данных для каждой сущности, если эта сущность должна иметь возможность быть в разных "состояниях". Как в случае с "сущностью" пользователя, у которого есть состояние, включающее `password`, `password_hash` и отсутствие пароля.
+Вам не обязательно иметь единственную модель данных для каждой сущности, если эта сущность должна иметь возможность быть в разных "состояниях". **Пользователь** — пример такой "сущности", с состояниями, которые включают `password`, `password_hash` или отсутствие пароля.
Это будет основная точка взаимодействия для создания всего вашего API.
-### Шаг 3: создайте *операцию пути (path operation)* { #step-3-create-a-path-operation }
+### Шаг 3: создайте *операцию пути* { #step-3-create-a-path-operation }
-#### Путь (path) { #path }
+#### Путь { #path }
Здесь «путь» — это последняя часть URL, начиная с первого символа `/`.
При создании API «путь» — это основной способ разделения «задач» и «ресурсов».
-#### Операция (operation) { #operation }
+#### Операция { #operation }
«Операция» здесь — это один из HTTP-«методов».
Таким образом, в OpenAPI каждый HTTP-метод называется «операцией».
-Мы тоже будем называть их «операциями».
+Мы тоже будем называть их «**операциями**».
-#### Определите *декоратор операции пути (path operation decorator)* { #define-a-path-operation-decorator }
+#### Определите *декоратор операции пути* { #define-a-path-operation-decorator }
{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}
-`@app.get("/")` сообщает **FastAPI**, что функция прямо под ним отвечает за обработку запросов, поступающих:
+`@app.get("/")` сообщает **FastAPI**, что функция прямо под ним отвечает за обработку HTTP-запросов, поступающих:
* по пути `/`
-* с использованием <dfn title="метод HTTP GET"><code>get</code> операции</dfn>
+* с использованием <dfn title="HTTP-метод GET">операции <code>get</code></dfn>
/// note | Информация о `@decorator`
///
-### Шаг 4: определите **функцию операции пути** { #step-4-define-the-path-operation-function }
+### Шаг 4: определите **функцию-обработчик пути** { #step-4-define-the-path-operation-function }
-Вот наша «функция операции пути»:
+Вот наша «**функция-обработчик пути**»:
* **путь**: `/`.
* **операция**: `get`.
Это функция на Python.
-**FastAPI** будет вызывать её каждый раз, когда получает запрос к URL «`/`» с операцией `GET`.
+**FastAPI** будет вызывать её каждый раз, когда получает HTTP-запрос к URL «`/`» с операцией `GET`.
В данном случае это асинхронная (`async`) функция.
Он переносит тот же **опыт разработчика** при создании приложений с FastAPI на их **развертывание** в облаке. 🎉
-FastAPI Cloud — основной спонсор и источник финансирования для open-source проектов «FastAPI и друзья». ✨
+FastAPI Cloud — основной спонсор и источник финансирования для open-source проектов *FastAPI и друзья*. ✨
#### Развертывание у других облачных провайдеров { #deploy-to-other-cloud-providers }
* Импортируйте `FastAPI`.
* Создайте экземпляр `app`.
* Напишите **декоратор операции пути**, например `@app.get("/")`.
-* Определите **функцию операции пути**; например, `def root(): ...`.
+* Определите **функцию-обработчик пути**; например, `def root(): ...`.
* Запустите сервер разработки командой `fastapi dev`.
* При желании разверните приложение командой `fastapi deploy`.
В таких случаях обычно возвращают **HTTP статус-код** в диапазоне **400** (от 400 до 499).
-Они похожи на двухсотые HTTP статус-коды (от 200 до 299), которые означают, что запрос обработан успешно.
+Они похожи на двухсотые HTTP статус-коды (от 200 до 299). Эти статус-коды "200" означают, что в HTTP-запросе в каком-то смысле был "успех".
-Четырёхсотые статус-коды означают, что ошибка произошла по вине клиента.
+HTTP статус-коды в диапазоне 400 означают, что произошла ошибка со стороны клиента.
-Ð\9fомниÑ\82е ли оÑ\88ибки **"404 Not Found "** (и Ñ\88Ñ\83Ñ\82ки) ?
+Ð\9fомниÑ\82е вÑ\81е Ñ\8dÑ\82и оÑ\88ибки **"404 Not Found"** (и Ñ\88Ñ\83Ñ\82ки)?
## Использование `HTTPException` { #use-httpexception }
`HTTPException` - это обычное исключение Python с дополнительными данными, актуальными для API.
-Поскольку это исключение Python, то его не `возвращают`, а `вызывают`.
+Поскольку это исключение Python, то его не `return`, а `raise`.
-Это также означает, что если вы находитесь внутри функции, которая вызывается внутри вашей *функции операции пути*, и вы поднимаете `HTTPException` внутри этой функции, то она не будет выполнять остальной код в *функции операции пути*, а сразу завершит запрос и отправит HTTP-ошибку из `HTTPException` клиенту.
+Это также означает, что если вы находитесь внутри вспомогательной функции, которая вызывается внутри вашей *функции-обработчика пути*, и вы вызываете `HTTPException` изнутри этой вспомогательной функции, то остальной код в *функции-обработчике пути* выполняться не будет, запрос сразу завершится, а HTTP-ошибка из `HTTPException` будет отправлена клиенту.
-Ð\9e Ñ\82ом, наÑ\81колÑ\8cко вÑ\8bгоднее `вÑ\8bзÑ\8bваÑ\82Ñ\8c` иÑ\81клÑ\8eÑ\87ение, Ñ\87ем `возвÑ\80аÑ\89аÑ\82Ñ\8c` знаÑ\87ение, бÑ\83деÑ\82 Ñ\80аÑ\81Ñ\81казано в Ñ\80азделе, поÑ\81вÑ\8fÑ\89енном завиÑ\81имоÑ\81Ñ\82Ñ\8fм и безопасности.
+Ð\9fÑ\80еимÑ\83Ñ\89еÑ\81Ñ\82во вÑ\8bзова иÑ\81клÑ\8eÑ\87ениÑ\8f пеÑ\80ед возвÑ\80аÑ\82ом знаÑ\87ениÑ\8f Ñ\81Ñ\82анеÑ\82 более оÑ\87евиднÑ\8bм в Ñ\80азделе о завиÑ\81имоÑ\81Ñ\82Ñ\8fÑ\85 и безопасности.
-В данном примере, когда клиент запрашивает элемент по несуществующему ID, возникает исключение со статус-кодом `404`:
+В данном примере, когда клиент запрашивает элемент по несуществующему ID, вызовите исключение со статус-кодом `404`:
{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}
### Возвращаемый ответ { #the-resulting-response }
-Если клиент запросит `http://example.com/items/foo` (`item_id` `"foo"`), то он получит статус-код 200 и ответ в формате JSON:
+Если клиент запросит `http://example.com/items/foo` (`item_id` `"foo"`), то он получит HTTP статус-код 200 и ответ в формате JSON:
```JSON
{
}
```
-Но если клиент запросит `http://example.com/items/bar` (несуществующий `item_id` `"bar"`), то он получит статус-код 404 (ошибка "не найдено") и JSON-ответ в виде:
+Но если клиент запросит `http://example.com/items/bar` (несуществующий `item_id` `"bar"`), то он получит HTTP статус-код 404 (ошибка "не найдено") и JSON-ответ в виде:
```JSON
{
///
-## Добавление пользовательских заголовков { #add-custom-headers }
+## Добавление пользовательских HTTP-заголовков { #add-custom-headers }
-В некоторых ситуациях полезно иметь возможность добавлять пользовательские HTTP-заголовки к ошибке HTTP. Например, для некоторых типов безопасности.
+В некоторых ситуациях полезно иметь возможность добавлять пользовательские HTTP-заголовки к HTTP-ошибке. Например, для некоторых типов безопасности.
-Скорее всего, вам не потребуется использовать его непосредственно в коде.
+Скорее всего, вам не потребуется использовать это непосредственно в коде.
-Но в случае, если это необходимо для продвинутого сценария, можно добавить пользовательские заголовки:
+Но в случае, если это необходимо для продвинутого сценария, можно добавить пользовательские HTTP-заголовки:
{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}
Вы можете добавить пользовательские обработчики исключений с помощью [тех же утилит обработки исключений из Starlette](https://www.starlette.dev/exceptions/).
-Допустим, у вас есть пользовательское исключение `UnicornException`, которое вы (или используемая вами библиотека) можете `вызвать`.
+Допустим, у вас есть пользовательское исключение `UnicornException`, которое вы (или используемая вами библиотека) можете вызвать с помощью `raise`.
И вы хотите обрабатывать это исключение глобально с помощью FastAPI.
Но оно будет обработано `unicorn_exception_handler`.
-Таким образом, вы получите чистую ошибку с кодом состояния HTTP `418` и содержимым JSON:
+Таким образом, вы получите чистую ошибку с HTTP статус-кодом `418` и содержимым JSON:
```JSON
{"message": "Oops! yolo did something. There goes a rainbow..."}
**FastAPI** имеет некоторые обработчики исключений по умолчанию.
-Эти обработчики отвечают за возврат стандартных JSON-ответов при `вызове` `HTTPException` и при наличии в запросе недопустимых данных.
+Эти обработчики отвечают за возврат стандартных JSON-ответов при вызове `HTTPException` с помощью `raise` и при наличии в HTTP-запросе недопустимых данных.
Вы можете переопределить эти обработчики исключений на свои собственные.
-### Ð\9fеÑ\80еопÑ\80еделение обÑ\80абоÑ\82Ñ\87ика иÑ\81клÑ\8eÑ\87ений пÑ\80овеÑ\80ки запроса { #override-request-validation-exceptions }
+### Ð\9fеÑ\80еопÑ\80еделение иÑ\81клÑ\8eÑ\87ений валидаÑ\86ии запроса { #override-request-validation-exceptions }
-Когда запрос содержит недопустимые данные, **FastAPI** внутренне вызывает ошибку `RequestValidationError`.
+Когда HTTP-запрос содержит недопустимые данные, **FastAPI** внутренне вызывает `RequestValidationError`.
-А также включает в себя обработчик исключений по умолчанию.
+А также включает в себя обработчик исключений по умолчанию для него.
-Чтобы переопределить его, импортируйте `RequestValidationError` и используйте его с `@app.exception_handler(RequestValidationError)` для создания обработчика исключений.
+Чтобы переопределить его, импортируйте `RequestValidationError` и используйте его с `@app.exception_handler(RequestValidationError)`, чтобы декорировать обработчик исключений.
Обработчик исключения получит объект `Request` и исключение.
}
```
-вы получите текстовую версию:
+вы получите текстовую версию с:
```
Validation errors:
/// warning | Внимание
-Имейте в виду, что `RequestValidationError` содержит информацию об имени файла и строке, где произошла ошибка валидации, чтобы вы могли при желании отобразить её в логах с релевантными данными.
+Имейте в виду, что `RequestValidationError` содержит информацию об имени файла и строке, где происходит ошибка валидации, чтобы вы могли при желании отобразить её в логах вместе с релевантной информацией.
Но это означает, что если вы просто преобразуете её в строку и вернёте эту информацию напрямую, вы можете допустить небольшую утечку информации о своей системе, поэтому здесь код извлекает и показывает каждую ошибку отдельно.
### Используйте тело `RequestValidationError` { #use-the-requestvalidationerror-body }
-Ошибка `RequestValidationError` содержит полученное `тело` с недопустимыми данными.
+Ошибка `RequestValidationError` содержит `body` (тело запроса), которое она получила с недопустимыми данными.
-Вы можете использовать его при разработке приложения для регистрации тела и его отладки, возврата пользователю и т.д.
+Вы можете использовать его при разработке приложения для логирования тела запроса и его отладки, возврата пользователю и т.д.
{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}
-ТепеÑ\80Ñ\8c попÑ\80обÑ\83йÑ\82е оÑ\82пÑ\80авиÑ\82Ñ\8c недейÑ\81Ñ\82виÑ\82елÑ\8cный элемент, например:
+ТепеÑ\80Ñ\8c попÑ\80обÑ\83йÑ\82е оÑ\82пÑ\80авиÑ\82Ñ\8c недопÑ\83Ñ\81Ñ\82имый элемент, например:
```JSON
{
}
```
-Ð\92Ñ\8b полÑ\83Ñ\87иÑ\82е оÑ\82веÑ\82 о Ñ\82ом, Ñ\87Ñ\82о даннÑ\8bе недейÑ\81Ñ\82виÑ\82елÑ\8cнÑ\8b, Ñ\81одеÑ\80жаÑ\89ий Ñ\81ледÑ\83Ñ\8eÑ\89ее Ñ\82ело:
+Ð\92Ñ\8b полÑ\83Ñ\87иÑ\82е оÑ\82веÑ\82 о Ñ\82ом, Ñ\87Ñ\82о даннÑ\8bе недопÑ\83Ñ\81Ñ\82имÑ\8b, Ñ\81одеÑ\80жаÑ\89ий полÑ\83Ñ\87енное Ñ\82ело запÑ\80оÑ\81а:
```JSON hl_lines="12-15"
{
}
```
-#### `HTTPException` в FastAPI или в Starlette { #fastapis-httpexception-vs-starlettes-httpexception }
+#### `HTTPException` в FastAPI и `HTTPException` в Starlette { #fastapis-httpexception-vs-starlettes-httpexception }
**FastAPI** имеет собственный `HTTPException`.
Но когда вы регистрируете обработчик исключений, вы должны зарегистрировать его для `HTTPException` от Starlette.
-Таким образом, если какая-либо часть внутреннего кодa Starlette, расширение или плагин Starlette вызовет исключение Starlette `HTTPException`, ваш обработчик сможет перехватить и обработать его.
+Таким образом, если какая-либо часть внутреннего кода Starlette, расширение или плагин Starlette вызовет исключение Starlette `HTTPException`, ваш обработчик сможет перехватить и обработать его.
-В данном примере, чтобы иметь возможность использовать оба `HTTPException` в одном коде, исключения Starlette переименованы в `StarletteHTTPException`:
+В данном примере, чтобы иметь возможность использовать оба `HTTPException` в одном коде, исключение Starlette переименовано в `StarletteHTTPException`:
```Python
from starlette.exceptions import HTTPException as StarletteHTTPException
{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}
-В этом примере вы просто `выводите в терминал` ошибку с очень выразительным сообщением, но идея вам понятна. Вы можете использовать исключение, а затем просто повторно использовать стандартные обработчики исключений.
+В этом примере вы просто выводите ошибку с очень выразительным сообщением, но идея вам понятна. Вы можете использовать исключение, а затем просто повторно использовать стандартные обработчики исключений.
# Учебник - Руководство пользователя { #tutorial-user-guide }
+
В этом руководстве шаг за шагом показано, как использовать **FastAPI** с большинством его функций.
Каждый раздел постепенно основывается на предыдущих, но структура разделяет темы, так что вы можете сразу перейти к нужной теме для решения ваших конкретных задач по API.
| `title` | `str` | Заголовок API. |
| `summary` | `str` | Краткое резюме API. <small>Доступно начиная с OpenAPI 3.1.0, FastAPI 0.99.0.</small> |
| `description` | `str` | Краткое описание API. Может быть использован Markdown. |
-| `version` | `string` | Версия API. Версия вашего собственного приложения, а не OpenAPI. К примеру `2.5.0`. |
-| `terms_of_service` | `str` | СÑ\81Ñ\8bлка к Ñ\83Ñ\81ловиÑ\8fм пользования API. Если указано, то это должен быть URL-адрес. |
-| `contact` | `dict` | Контактная информация для открытого API. Может содержать несколько полей. <details><summary>поля <code>contact</code></summary><table><thead><tr><th>Параметр</th><th>Тип</th><th>Описание</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>Идентификационное имя контактного лица/организации.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>URL указывающий на контактную информацию. ДОЛЖЕН быть в формате URL.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>Email адрес контактного лица/организации. ДОЛЖЕН быть в формате email адреса.</td></tr></tbody></table></details> |
-| `license_info` | `dict` | Информация о лицензии открытого API. Может содержать несколько полей. <details><summary>поля <code>license_info</code></summary><table><thead><tr><th>Параметр</th><th>Тип</th><th>Описание</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>ОБЯЗАТЕЛЬНО</strong> (если установлен параметр <code>license_info</code>). Название лицензии, используемой для API.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>Выражение лицензии [SPDX](https://spdx.org/licenses/) для API. Поле <code>identifier</code> взаимоисключающее с полем <code>url</code>. <small>Доступно начиная с OpenAPI 3.1.0, FastAPI 0.99.0.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>URL, указывающий на лицензию, используемую для API. ДОЛЖЕН быть в формате URL.</td></tr></tbody></table></details> |
+| `version` | `str` | Версия API. Версия вашего собственного приложения, а не OpenAPI. К примеру `2.5.0`. |
+| `terms_of_service` | `str` | СÑ\81Ñ\8bлка на Ñ\83Ñ\81ловиÑ\8f пользования API. Если указано, то это должен быть URL-адрес. |
+| `contact` | `dict` | Контактная информация для открытого API. Может содержать несколько полей. <details><summary>поля <code>contact</code></summary><table><thead><tr><th>Параметр</th><th>Тип</th><th>Описание</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>Идентификационное имя контактного лица/организации.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>URL, указывающий на контактную информацию. ДОЛЖЕН быть в формате URL.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>Email-адрес контактного лица/организации. ДОЛЖЕН быть в формате email-адреса.</td></tr></tbody></table></details> |
+| `license_info` | `dict` | Информация о лицензии открытого API. Может содержать несколько полей. <details><summary>поля <code>license_info</code></summary><table><thead><tr><th>Параметр</th><th>Тип</th><th>Описание</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>ОБЯЗАТЕЛЬНО</strong> (если установлен параметр <code>license_info</code>). Название лицензии, используемой для API.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>Выражение лицензии [SPDX](https://spdx.org/licenses/) для API. Поле <code>identifier</code> является взаимоисключающим с полем <code>url</code>. <small>Доступно начиная с OpenAPI 3.1.0, FastAPI 0.99.0.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>URL, указывающий на лицензию, используемую для API. ДОЛЖЕН быть в формате URL.</td></tr></tbody></table></details> |
Вы можете задать их следующим образом:
* `name` (**обязательно**): `str`-значение с тем же именем тега, которое вы используете в параметре `tags` в ваших *операциях пути* и `APIRouter`ах.
* `description`: `str`-значение с кратким описанием для тега. Может содержать Markdown и будет отображаться в UI документации.
-* `externalDocs`: `dict`-значение описывающее внешнюю документацию. Включает в себя:
+* `externalDocs`: `dict`-значение, описывающее внешнюю документацию. Включает в себя:
* `description`: `str`-значение с кратким описанием для внешней документации.
* `url` (**обязательно**): `str`-значение с URL-адресом для внешней документации.
/// tip | Подсказка
-Вам необязательно добавлять метаданные для всех используемых тегов
+Вам необязательно добавлять метаданные для всех используемых тегов.
///
## URL-адрес OpenAPI { #openapi-url }
-Ð\9fо Ñ\83молÑ\87аниÑ\8e Ñ\81Ñ\85ема OpenAPI оÑ\82обÑ\80ажена по адресу `/openapi.json`.
+Ð\9fо Ñ\83молÑ\87аниÑ\8e Ñ\81Ñ\85ема OpenAPI оÑ\82даÑ\91Ñ\82Ñ\81Ñ\8f по адресу `/openapi.json`.
Но вы можете изменить это с помощью параметра `openapi_url`.
-Ð\9a пÑ\80имеÑ\80Ñ\83, Ñ\87Ñ\82обÑ\8b задаÑ\82Ñ\8c еÑ\91 оÑ\82обÑ\80ажение по адресу `/api/v1/openapi.json`:
+Ð\9a пÑ\80имеÑ\80Ñ\83, Ñ\87Ñ\82обÑ\8b задаÑ\82Ñ\8c еÑ\91 оÑ\82даÑ\87Ñ\83 по адресу `/api/v1/openapi.json`:
{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}
## URL-адреса документации { #docs-urls }
-Ð\92Ñ\8b можеÑ\82е измениÑ\82Ñ\8c конÑ\84игÑ\83Ñ\80аÑ\86иÑ\8e двÑ\83Ñ\85 полÑ\8cзоваÑ\82елÑ\8cÑ\81киÑ\85 инÑ\82еÑ\80Ñ\84ейÑ\81ов докÑ\83менÑ\82аÑ\86ии, коÑ\82оÑ\80Ñ\8bе вклÑ\8eÑ\87енÑ\8b:
+Ð\92Ñ\8b можеÑ\82е измениÑ\82Ñ\8c конÑ\84игÑ\83Ñ\80аÑ\86иÑ\8e двÑ\83Ñ\85 вклÑ\8eÑ\87Ñ\91ннÑ\8bÑ\85 полÑ\8cзоваÑ\82елÑ\8cÑ\81киÑ\85 инÑ\82еÑ\80Ñ\84ейÑ\81ов докÑ\83менÑ\82аÑ\86ии:
-* **Swagger UI**: оÑ\82обÑ\80ажаемÑ\8bй по адресу `/docs`.
+* **Swagger UI**: оÑ\82даÑ\91Ñ\82Ñ\81Ñ\8f по адресу `/docs`.
* Вы можете задать его URL с помощью параметра `docs_url`.
* Вы можете отключить это с помощью настройки `docs_url=None`.
-* **ReDoc**: оÑ\82обÑ\80ажаемÑ\8bй по адресу `/redoc`.
+* **ReDoc**: оÑ\82даÑ\91Ñ\82Ñ\81Ñ\8f по адресу `/redoc`.
* Вы можете задать его URL с помощью параметра `redoc_url`.
* Вы можете отключить это с помощью настройки `redoc_url=None`.
-Ð\9a пÑ\80имеÑ\80Ñ\83, Ñ\87Ñ\82обÑ\8b задаÑ\82Ñ\8c оÑ\82обÑ\80ажение Swagger UI по адресу `/documentation` и отключить ReDoc:
+Ð\9a пÑ\80имеÑ\80Ñ\83, Ñ\87Ñ\82обÑ\8b наÑ\81Ñ\82Ñ\80оиÑ\82Ñ\8c оÑ\82даÑ\87Ñ\83 Swagger UI по адресу `/documentation` и отключить ReDoc:
{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}
-# Ð\9aонÑ\84игÑ\83Ñ\80аÑ\86иÑ\8f опеÑ\80аÑ\86ий пути { #path-operation-configuration }
+# Ð\9aонÑ\84игÑ\83Ñ\80аÑ\86иÑ\8f опеÑ\80аÑ\86ии пути { #path-operation-configuration }
-СÑ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 неÑ\81колÑ\8cко паÑ\80амеÑ\82Ñ\80ов, коÑ\82оÑ\80Ñ\8bе вÑ\8b можеÑ\82е пеÑ\80едаÑ\82Ñ\8c ваÑ\88емÑ\83 *декоÑ\80аÑ\82оÑ\80Ñ\83 опеÑ\80аÑ\86ий пути* для его настройки.
+СÑ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 неÑ\81колÑ\8cко паÑ\80амеÑ\82Ñ\80ов, коÑ\82оÑ\80Ñ\8bе вÑ\8b можеÑ\82е пеÑ\80едаÑ\82Ñ\8c ваÑ\88емÑ\83 *декоÑ\80аÑ\82оÑ\80Ñ\83 опеÑ\80аÑ\86ии пути* для его настройки.
/// warning | Внимание
-Ð\9fомниÑ\82е, Ñ\87Ñ\82о Ñ\8dÑ\82и паÑ\80амеÑ\82Ñ\80Ñ\8b пеÑ\80едаÑ\8eÑ\82Ñ\81Ñ\8f непоÑ\81Ñ\80едÑ\81Ñ\82венно *декоÑ\80аÑ\82оÑ\80Ñ\83 опеÑ\80аÑ\86ий пути*, а не вашей *функции-обработчику пути*.
+Ð\9fомниÑ\82е, Ñ\87Ñ\82о Ñ\8dÑ\82и паÑ\80амеÑ\82Ñ\80Ñ\8b пеÑ\80едаÑ\8eÑ\82Ñ\81Ñ\8f непоÑ\81Ñ\80едÑ\81Ñ\82венно *декоÑ\80аÑ\82оÑ\80Ñ\83 опеÑ\80аÑ\86ии пути*, а не вашей *функции-обработчику пути*.
///
## Теги { #tags }
-Ð\92Ñ\8b можеÑ\82е добавлÑ\8fÑ\82Ñ\8c Ñ\82еги к ваÑ\88им *опеÑ\80аÑ\86иÑ\8fм пÑ\83Ñ\82и*, добавив паÑ\80амеÑ\82Ñ\80 `tags` Ñ\81 `list` заполненнÑ\8bм `str`-знаÑ\87ениÑ\8fми (обычно в нём только одна строка):
+Ð\92Ñ\8b можеÑ\82е добавлÑ\8fÑ\82Ñ\8c Ñ\82еги к ваÑ\88ей *опеÑ\80аÑ\86ии пÑ\83Ñ\82и*, пеÑ\80едав паÑ\80амеÑ\82Ñ\80 `tags` Ñ\81 `list` из `str` (обычно в нём только одна строка):
{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}
-Ð\9eни бÑ\83дÑ\83Ñ\82 добавленÑ\8b в Ñ\81Ñ\85емÑ\83 OpenAPI и бÑ\83дÑ\83Ñ\82 иÑ\81полÑ\8cзованÑ\8b в авÑ\82омаÑ\82иÑ\87еÑ\81кой докÑ\83менÑ\82аÑ\86ии инÑ\82еÑ\80Ñ\84ейÑ\81а:
+Ð\9eни бÑ\83дÑ\83Ñ\82 добавленÑ\8b в Ñ\81Ñ\85емÑ\83 OpenAPI и бÑ\83дÑ\83Ñ\82 иÑ\81полÑ\8cзованÑ\8b авÑ\82омаÑ\82иÑ\87еÑ\81кими инÑ\82еÑ\80Ñ\84ейÑ\81ами докÑ\83менÑ\82аÑ\86ии:
<img src="/img/tutorial/path-operation-configuration/image01.png">
## Описание из строк документации { #description-from-docstring }
-Так как опиÑ\81аниÑ\8f обÑ\8bÑ\87но длиннÑ\8bе и Ñ\81одеÑ\80жаÑ\82 много Ñ\81Ñ\82Ñ\80ок, вÑ\8b можеÑ\82е обÑ\8aÑ\8fвиÑ\82Ñ\8c опиÑ\81ание *опеÑ\80аÑ\86ии пÑ\83Ñ\82и* в <dfn title="многоÑ\81Ñ\82Ñ\80оÑ\87наÑ\8f Ñ\81Ñ\82Ñ\80ока, пеÑ\80вое вÑ\8bÑ\80ажение внÑ\83Ñ\82Ñ\80и Ñ\84Ñ\83нкÑ\86ии (не пÑ\80иÑ\81военное какой-либо пеÑ\80еменной), иÑ\81полÑ\8cзÑ\83емаÑ\8f для документации">строке документации</dfn> функции, и **FastAPI** прочитает её оттуда.
+Так как опиÑ\81аниÑ\8f обÑ\8bÑ\87но длиннÑ\8bе и Ñ\81одеÑ\80жаÑ\82 много Ñ\81Ñ\82Ñ\80ок, вÑ\8b можеÑ\82е обÑ\8aÑ\8fвиÑ\82Ñ\8c опиÑ\81ание *опеÑ\80аÑ\86ии пÑ\83Ñ\82и* в <dfn title="многоÑ\81Ñ\82Ñ\80оÑ\87наÑ\8f Ñ\81Ñ\82Ñ\80ока, пеÑ\80вое вÑ\8bÑ\80ажение внÑ\83Ñ\82Ñ\80и Ñ\84Ñ\83нкÑ\86ии (не пÑ\80иÑ\81военное какой-либо пеÑ\80еменной), иÑ\81полÑ\8cзÑ\83емое для документации">строке документации</dfn> функции, и **FastAPI** прочитает её оттуда.
Вы можете использовать [Markdown](https://en.wikipedia.org/wiki/Markdown) в строке документации, и он будет интерпретирован и отображён корректно (с учетом отступа в строке документации).
{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}
-Он будет четко помечен как устаревший в интерактивной документации:
+Она будет четко помечена как устаревшая в интерактивной документации:
<img src="/img/tutorial/path-operation-configuration/image04.png">
Теперь FastAPI будет:
* **валидировать** данные, удостоверяясь, что максимальная длина — 50 символов;
-* показÑ\8bвать **понятную ошибку** клиенту, если данные невалидны;
-* **докÑ\83менÑ\82иÑ\80оваÑ\82Ñ\8c** паÑ\80амеÑ\82Ñ\80 в *опеÑ\80аÑ\86ии пÑ\83Ñ\82и* Ñ\81Ñ\85емÑ\8b OpenAPI (он бÑ\83деÑ\82 показан в **UI автоматической документации**).
+* оÑ\82обÑ\80ажать **понятную ошибку** клиенту, если данные невалидны;
+* **докÑ\83менÑ\82иÑ\80оваÑ\82Ñ\8c** паÑ\80амеÑ\82Ñ\80 в *опеÑ\80аÑ\86ии пÑ\83Ñ\82и* Ñ\81Ñ\85емÑ\8b OpenAPI (он бÑ\83деÑ\82 оÑ\82обÑ\80ажаÑ\82Ñ\8cÑ\81Ñ\8f в **UI автоматической документации**).
## Альтернатива (устаревшее): `Query` как значение по умолчанию { #alternative-old-query-as-the-default-value }
q: str | None = Query(default=None, max_length=50)
```
-ÐÑ\82о пÑ\80овалидиÑ\80Ñ\83еÑ\82 даннÑ\8bе, покажет понятную ошибку, если данные невалидны, и задокументирует параметр в *операции пути* схемы OpenAPI.
+ÐÑ\82о пÑ\80овалидиÑ\80Ñ\83еÑ\82 даннÑ\8bе, оÑ\82обÑ\80азит понятную ошибку, если данные невалидны, и задокументирует параметр в *операции пути* схемы OpenAPI.
### `Query` как значение по умолчанию или внутри `Annotated` { #query-as-the-default-value-or-in-annotated }
q: Annotated[str, Query()] = "rick"
```
-...или в старой кодовой базе вы увидите:
+...или в старых кодовых базах вы увидите:
```Python
q: str = Query(default="rick")
**Значение по умолчанию** у **параметра функции** — это **настоящее значение по умолчанию**, что более интуитивно для Python. 😌
-Вы можете **вызвать** эту же функцию в **других местах** без FastAPI, и она будет **работать как ожидается**. Если есть **обязательный** параметр (без значения по умолчанию), ваш **редактор** сообщит об ошибке, **Python** тоже пожалуется, если вы запустите её без передачи обязательного параметра.
+Вы можете **вызвать** эту же функцию в **других местах** без FastAPI, и она будет **работать как ожидается**. Если есть **обязательный** параметр (без значения по умолчанию), ваш **редактор кода** сообщит об ошибке, **Python** тоже пожалуется, если вы запустите её без передачи обязательного параметра.
-Если вы не используете `Annotated`, а применяете **(устаревший) стиль со значением по умолчанию**, то при вызове этой функции без FastAPI в **других местах** вам нужно **помнить** о том, что надо передать аргументы, чтобы всё работало корректно, иначе значения будут не такими, как вы ожидаете (например, вместо `str` будет `QueryInfo` или что-то подобное). И ни редактор, ни Python не будут ругаться при самом вызове функции — ошибка проявится лишь при операциях внутри.
+Если вы не используете `Annotated`, а применяете **(устаревший) стиль со значением по умолчанию**, то при вызове этой функции без FastAPI в **других местах** вам нужно **помнить** о том, что надо передать аргументы, чтобы всё работало корректно, иначе значения будут не такими, как вы ожидаете (например, вместо `str` будет `QueryInfo` или что-то подобное). И ни редактор кода, ни Python не будут ругаться при самом вызове функции — ошибка проявится лишь при операциях внутри.
Так как `Annotated` может содержать больше одной аннотации метаданных, теперь вы можете использовать ту же функцию и с другими инструментами, например с [Typer](https://typer.tiangolo.com/). 🚀
-## Ð\91ольше валидаций { #add-more-validations }
+## Ð\94обавим больше валидаций { #add-more-validations }
Можно также добавить параметр `min_length`:
{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}
-## Ð егулярные выражения { #add-regular-expressions }
+## Ð\94обавим Ñ\80егулярные выражения { #add-regular-expressions }
Вы можете определить <dfn title="Регулярное выражение (regex, regexp) — это последовательность символов, задающая шаблон поиска для строк.">регулярное выражение</dfn> `pattern`, которому должен соответствовать параметр:
Данный шаблон регулярного выражения проверяет, что полученное значение параметра:
-* `^`: начинается с следующих символов, до них нет символов.
+* `^`: начинается со следующих символов, до них нет символов.
* `fixedquery`: имеет точное значение `fixedquery`.
* `$`: заканчивается здесь, после `fixedquery` нет никаких символов.
/// note | Примечание
-Наличие значения по умолчанию любого типа, включая `None`, делает параметр необязательным.
+Наличие значения по умолчанию любого типа, включая `None`, делает параметр необязательным (не обязательным).
///
вы получите множественные значения *query-параметров* `q` (`foo` и `bar`) в виде Python-`list` внутри вашей *функции-обработчика пути*, в *параметре функции* `q`.
-Таким образом, ответ на этот URL будет:
+Таким образом, HTTP-ответом на этот URL будет:
```JSON
{
http://localhost:8000/items/
```
-значение по умолчанию для `q` будет: `["foo", "bar"]`, и ответом будет:
+знаÑ\87ение по Ñ\83молÑ\87аниÑ\8e длÑ\8f `q` бÑ\83деÑ\82: `["foo", "bar"]`, и ваÑ\88им HTTP-оÑ\82веÑ\82ом бÑ\83деÑ\82:
```JSON
{
///
-## Ð\91олÑ\8cÑ\88е метаданных { #declare-more-metadata }
+## Ð\9eбÑ\8aÑ\8fвление дополниÑ\82елÑ\8cнÑ\8bÑ\85 метаданных { #declare-more-metadata }
Можно добавить больше информации о параметре.
В таких случаях можно использовать **кастомную функцию-валидатор**, которая применяется после обычной валидации (например, после проверки, что значение — это `str`).
-Этого можно добиться, используя [`AfterValidator` Pydantic](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) внутри `Annotated`.
+Этого можно добиться, используя [Pydantic `AfterValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) внутри `Annotated`.
/// tip | Совет
///
-Ð\9dапÑ\80имеÑ\80, Ñ\8dÑ\82а каÑ\81Ñ\82омнаÑ\8f пÑ\80овеÑ\80ка Ñ\83беждаеÑ\82Ñ\81Ñ\8f, Ñ\87Ñ\82о ID Ñ\8dлеменÑ\82а наÑ\87инаеÑ\82Ñ\81Ñ\8f Ñ\81 `isbn-` длÑ\8f номеÑ\80а книги <abbr title="International Standard Book Number - Ð\9cеждÑ\83наÑ\80однÑ\8bй Ñ\81Ñ\82андаÑ\80Ñ\82нÑ\8bй книжнÑ\8bй номеÑ\80">ISBN</abbr> или Ñ\81 `imdb-` длÑ\8f ID URL Ñ\84илÑ\8cма на <abbr title="Internet Movie Database - Ð\98нÑ\82еÑ\80неÑ\82наÑ\8f база данных фильмов: веб‑сайт с информацией о фильмах">IMDB</abbr>:
+Ð\9dапÑ\80имеÑ\80, Ñ\8dÑ\82а каÑ\81Ñ\82омнаÑ\8f пÑ\80овеÑ\80ка Ñ\83беждаеÑ\82Ñ\81Ñ\8f, Ñ\87Ñ\82о ID Ñ\8dлеменÑ\82а наÑ\87инаеÑ\82Ñ\81Ñ\8f Ñ\81 `isbn-` длÑ\8f номеÑ\80а книги <abbr title="International Standard Book Number - Ð\9cеждÑ\83наÑ\80однÑ\8bй Ñ\81Ñ\82андаÑ\80Ñ\82нÑ\8bй книжнÑ\8bй номеÑ\80">ISBN</abbr> или Ñ\81 `imdb-` длÑ\8f ID URL Ñ\84илÑ\8cма в <abbr title="Internet Movie Database - Ð\98нÑ\82еÑ\80неÑ\82-база данных фильмов: веб‑сайт с информацией о фильмах">IMDB</abbr>:
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
Если вам нужна валидация, требующая общения с каким‑либо **внешним компонентом** — базой данных или другим API — вместо этого используйте **Зависимости FastAPI**, вы познакомитесь с ними позже.
-Эти кастомные валидаторы предназначены для проверок, которые можно выполнить, имея **только** те же **данные**, что пришли в запросе.
+Эти кастомные валидаторы предназначены для проверок, которые можно выполнить, имея **только** те же **данные**, что пришли в HTTP-запросе.
///
Вы можете объявлять дополнительные проверки и метаданные для параметров.
-Ð\9eбÑ\89ие меÑ\82аданнÑ\8bе и наÑ\81Ñ\82Ñ\80ойки:
+Ð\9eбÑ\89ие пÑ\80овеÑ\80ки и меÑ\82аданнÑ\8bе:
* `alias`
* `title`
# Query-параметры { #query-parameters }
-Когда вы объявляете параметры функции, которые не являются параметрами пути, они автоматически интерпретируются как "query"-параметры.
+Когда вы объявляете параметры функции, которые не являются частью path-параметров, они автоматически интерпретируются как "query"-параметры.
{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}
-Query-параметры представляют из себя набор пар ключ-значение, которые идут после знака `?` в URL-адресе, разделенные символами `&`.
+Query — это набор пар ключ-значение, которые идут после знака `?` в URL-адресе, разделенные символами `&`.
Например, в этом URL-адресе:
http://127.0.0.1:8000/items/?skip=0&limit=10
```
-...параметры запроса такие:
+...query-параметры такие:
* `skip`: со значением `0`
* `limit`: со значением `10`
-Ð\91Ñ\83дÑ\83Ñ\87и Ñ\87аÑ\81Ñ\82Ñ\8cÑ\8e URL-адÑ\80еÑ\81а, они "по Ñ\83молÑ\87аниÑ\8e" являются строками.
+Ð\91Ñ\83дÑ\83Ñ\87и Ñ\87аÑ\81Ñ\82Ñ\8cÑ\8e URL-адÑ\80еÑ\81а, они "еÑ\81Ñ\82еÑ\81Ñ\82веннÑ\8bм обÑ\80азом" являются строками.
Но когда вы объявляете их с использованием типов Python (в примере выше, как `int`), они конвертируются в указанный тип данных и проходят проверку на соответствие ему.
-Ð\92Ñ\81е Ñ\82е же пÑ\80авила, коÑ\82оÑ\80Ñ\8bе пÑ\80именÑ\8fÑ\8eÑ\82Ñ\81Ñ\8f к path-паÑ\80амеÑ\82Ñ\80ам, Ñ\82акже пÑ\80именÑ\8fÑ\8eÑ\82Ñ\81Ñ\8f и query-параметрам:
+Ð\92Ñ\81е Ñ\82е же пÑ\80оÑ\86еÑ\81Ñ\81Ñ\8b, коÑ\82оÑ\80Ñ\8bе пÑ\80именÑ\8fÑ\8eÑ\82Ñ\81Ñ\8f к path-паÑ\80амеÑ\82Ñ\80ам, Ñ\82акже пÑ\80именÑ\8fÑ\8eÑ\82Ñ\81Ñ\8f и к query-параметрам:
* Поддержка от редактора кода (очевидно)
-* <dfn title="преобразование строки, полученной из HTTP-запроса в данные Python">"Парсинг"</dfn> данных
-* Ð\9fÑ\80овеÑ\80ка на Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82вие даннÑ\8bÑ\85 (Ð\92алидаÑ\86иÑ\8f)
+* <dfn title="преобразование строки, полученной из HTTP-запроса, в данные Python">"Парсинг"</dfn> данных
+* Ð\92алидаÑ\86иÑ\8f даннÑ\8bÑ\85
* Автоматическая документация
## Значения по умолчанию { #defaults }
-Поскольку query-параметры не являются фиксированной частью пути, они могут быть не обязательными и иметь значения по умолчанию.
+Поскольку query-параметры не являются фиксированной частью пути, они могут быть необязательными и иметь значения по умолчанию.
В примере выше значения по умолчанию равны `skip=0` и `limit=10`.
http://127.0.0.1:8000/items/
```
-бÑ\83деÑ\82 Ñ\82аким же, как еÑ\81ли пеÑ\80ейÑ\82и иÑ\81полÑ\8cзÑ\83Ñ\8f паÑ\80амеÑ\82Ñ\80Ñ\8b по Ñ\83молÑ\87аниÑ\8e:
+бÑ\83деÑ\82 Ñ\82аким же, как еÑ\81ли пеÑ\80ейÑ\82и по:
```
http://127.0.0.1:8000/items/?skip=0&limit=10
```
-Ð\9dо еÑ\81ли вÑ\8b введÑ\91Ñ\82е, напÑ\80имеÑ\80:
+Ð\9dо еÑ\81ли вÑ\8b пеÑ\80ейдÑ\91Ñ\82е, напÑ\80имеÑ\80, по:
```
http://127.0.0.1:8000/items/?skip=20
Значения параметров в вашей функции будут:
* `skip=20`: потому что вы установили это в URL-адресе
-* `limit=10`: т.к это было значение по умолчанию
+* `limit=10`: потому что это было значение по умолчанию
## Необязательные параметры { #optional-parameters }
{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}
-В этом случае, параметр `q` будет не обязательным и будет иметь значение `None` по умолчанию.
+В этом случае параметр функции `q` будет необязательным и будет иметь значение `None` по умолчанию.
/// tip | Подсказка
-Также обратите внимание, что **FastAPI** достаточно умён чтобы заметить, что параметр `item_id` является path-параметром, а `q` нет, поэтому, это параметр запроса.
+Также обратите внимание, что **FastAPI** достаточно умён, чтобы заметить, что path-параметр `item_id` является path-параметром, а `q` — нет, поэтому это query-параметр.
///
-## Преобразование типа параметра запроса { #query-parameter-type-conversion }
+## Преобразование типа query-параметра { #query-parameter-type-conversion }
-Вы также можете объявлять параметры с типом `bool`, которые будут преобразованы соответственно:
+Вы также можете объявлять типы `bool`, и они будут преобразованы:
{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}
-В этом случае, если вы сделаете запрос:
+В этом случае, если вы перейдёте по:
```
http://127.0.0.1:8000/items/foo?short=1
http://127.0.0.1:8000/items/foo?short=yes
```
-или в любом другом варианте написания (в верхнем регистре, с заглавной буквой, и т.п), внутри вашей функции параметр `short` будет иметь значение `True` типа данных `bool` . В противном случае - `False`.
+или в любом другом варианте написания (в верхнем регистре, с заглавной буквой и т.п.), внутри вашей функции параметр `short` будет иметь значение `True` типа данных `bool`. В противном случае — `False`.
-## Смешивание query-параметров и path-параметров { #multiple-path-and-query-parameters }
-Вы можете объявлять несколько query-параметров и path-параметров одновременно, **FastAPI** сам разберётся, что чем является.
+## Несколько path-параметров и query-параметров { #multiple-path-and-query-parameters }
+
+Вы можете объявлять несколько path-параметров и query-параметров одновременно, **FastAPI** знает, что чем является.
И вы не обязаны объявлять их в каком-либо определенном порядке.
Когда вы объявляете значение по умолчанию для параметра, который не является path-параметром (в этом разделе мы пока что рассмотрели только query-параметры), то он не является обязательным.
-Если вы не хотите задавать конкретное значение, но хотите сделать параметр необязательным, вы можете установить значение по умолчанию равным `None`.
+Если вы не хотите задавать конкретное значение, но хотите просто сделать параметр необязательным, установите значение по умолчанию равным `None`.
Но если вы хотите сделать query-параметр обязательным, вы можете просто не указывать значение по умолчанию:
{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}
-Здесь параметр запроса `needy` является обязательным параметром с типом данных `str`.
+Здесь query-параметр `needy` является обязательным query-параметром с типом данных `str`.
-Если вы откроете в браузере URL-адрес, например:
+Если вы откроете в браузере URL-адрес вроде:
```
http://127.0.0.1:8000/items/foo-item
```
-...без добавлениÑ\8f обÑ\8fзаÑ\82елÑ\8cного паÑ\80амеÑ\82Ñ\80а `needy`, вÑ\8b Ñ\83видиÑ\82е подобного Ñ\80ода оÑ\88ибкÑ\83:
+...без добавлениÑ\8f обÑ\8fзаÑ\82елÑ\8cного паÑ\80амеÑ\82Ñ\80а `needy`, вÑ\8b Ñ\83видиÑ\82е оÑ\88ибкÑ\83 вÑ\80оде:
```JSON
{
}
```
-Ð\9aонечно, вы можете определить некоторые параметры как обязательные, некоторые — со значением по умолчанию, а некоторые — полностью необязательные:
+Ð\98, конечно, вы можете определить некоторые параметры как обязательные, некоторые — со значением по умолчанию, а некоторые — полностью необязательные:
{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}
-В этом примере, у нас есть 3 параметра запроса:
+В этом случае есть 3 query-параметра:
* `needy`, обязательный `str`.
-* `skip`, типа `int` и со значением по умолчанию `0`.
+* `skip`, `int` со значением по умолчанию `0`.
* `limit`, необязательный `int`.
/// tip | Подсказка
-Вы можете использовать класс `Enum` также, как ранее применяли его с [Path-параметрами](path-params.md#predefined-values).
+Вы можете использовать `Enum` так же, как ранее применяли его с [Path-параметрами](path-params.md#predefined-values).
///
/// tip | Подсказка
-Ð\94лÑ\8f обÑ\8aÑ\8fвлениÑ\8f Ñ\82ела Ñ\84айла необÑ\85одимо иÑ\81полÑ\8cзоваÑ\82Ñ\8c `File`, поÑ\81колÑ\8cкÑ\83 в пÑ\80оÑ\82ивном Ñ\81лÑ\83Ñ\87ае паÑ\80амеÑ\82Ñ\80Ñ\8b бÑ\83дÑ\83Ñ\82 инÑ\82еÑ\80пÑ\80еÑ\82иÑ\80оваÑ\82Ñ\8cÑ\81Ñ\8f как паÑ\80амеÑ\82Ñ\80Ñ\8b запÑ\80оÑ\81а или паÑ\80амеÑ\82Ñ\80Ñ\8b Ñ\82ела (JSON).
+ЧÑ\82обÑ\8b обÑ\8aÑ\8fвиÑ\82Ñ\8c Ñ\84айлÑ\8b в Ñ\82еле запÑ\80оÑ\81а, необÑ\85одимо иÑ\81полÑ\8cзоваÑ\82Ñ\8c `File`, поÑ\81колÑ\8cкÑ\83 инаÑ\87е паÑ\80амеÑ\82Ñ\80Ñ\8b бÑ\83дÑ\83Ñ\82 инÑ\82еÑ\80пÑ\80еÑ\82иÑ\80оваÑ\82Ñ\8cÑ\81Ñ\8f как паÑ\80амеÑ\82Ñ\80Ñ\8b запÑ\80оÑ\81а или body-паÑ\80амеÑ\82Ñ\80Ñ\8b (JSON).
///
Файлы будут загружены как данные формы.
-Если вы объявите тип параметра у *функции операции пути* как `bytes`, то **FastAPI** прочитает файл за вас, и вы получите его содержимое в виде `bytes`.
+Если вы объявите тип параметра у *функции-обработчика пути* как `bytes`, то **FastAPI** прочитает файл за вас, и вы получите его содержимое в виде `bytes`.
Следует иметь в виду, что все содержимое будет храниться в памяти. Это хорошо подходит для небольших файлов.
* Это означает, что он будет хорошо работать с большими файлами, такими как изображения, видео, большие бинарные файлы и т.д., не потребляя при этом всю память.
* Из загруженного файла можно получить метаданные.
* Он реализует [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) `async` интерфейс.
-* Он предоставляет реальный объект Python [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile), который вы можете передать непосредственно другим библиотекам, которые ожидают файл в качестве объекта.
+* Он предоставляет реальный объект Python [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile), который вы можете передать непосредственно другим библиотекам, которые ожидают file-like объект.
### `UploadFile` { #uploadfile }
`UploadFile` имеет следующие атрибуты:
* `filename`: Строка `str` с исходным именем файла, который был загружен (например, `myimage.jpg`).
-* `content_type`: Строка `str` с типом содержимого (MIME type / media type) (например, `image/jpeg`).
-* `file`: [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) (a [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) объект). Это фактический файл Python, который можно передавать непосредственно другим функциям или библиотекам, ожидающим файл в качестве объекта.
+* `content_type`: Строка `str` с типом содержимого (MIME-тип / тип содержимого) (например, `image/jpeg`).
+* `file`: [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) ([file-like](https://docs.python.org/3/glossary.html#term-file-like-object) объект). Это фактический файл Python, который можно передавать непосредственно другим функциям или библиотекам, ожидающим file-like объект.
`UploadFile` имеет следующие методы `async`. Все они вызывают соответствующие файловые методы (используя внутренний `SpooledTemporaryFile`).
Поскольку все эти методы являются `async` методами, вам следует использовать "await" вместе с ними.
-Например, внутри `async` *функции операции пути* можно получить содержимое с помощью:
+Например, внутри `async` *функции-обработчика пути* можно получить содержимое с помощью:
```Python
contents = await myfile.read()
```
-Если вы находитесь внутри обычной `def` *функции операции пути*, можно получить прямой доступ к файлу `UploadFile.file`, например:
+Если вы находитесь внутри обычной `def` *функции-обработчика пути*, можно получить прямой доступ к файлу `UploadFile.file`, например:
```Python
contents = myfile.file.read()
```
-
/// note | Технические детали `async`
При использовании методов `async` **FastAPI** запускает файловые методы в пуле потоков и ожидает их.
/// note | Технические детали Starlette
-**FastAPI** наследует `UploadFile` непосредственно из **Starlette**, но добавляет некоторые детали для совместимости с **Pydantic** и другими частями FastAPI.
+`UploadFile` из **FastAPI** наследуется непосредственно от `UploadFile` из **Starlette**, но добавляет некоторые необходимые части для совместимости с **Pydantic** и другими частями FastAPI.
///
/// note | Технические детали
-Данные из форм обычно кодируются с использованием "media type" `application/x-www-form-urlencoded` когда он не включает файлы.
+Данные из форм обычно кодируются с использованием типа содержимого `application/x-www-form-urlencoded`, когда они не включают файлы.
-Но когда форма включает файлы, она кодируется как `multipart/form-data`. Если вы используете `File`, **FastAPI** будет знать, что ему нужно получить файлы из нужной части тела.
+Но когда форма включает файлы, она кодируется как `multipart/form-data`. Если вы используете `File`, **FastAPI** будет знать, что ему нужно получить файлы из нужной части тела запроса.
-Ð\95Ñ\81ли вÑ\8b Ñ\85оÑ\82иÑ\82е Ñ\83знаÑ\82Ñ\8c болÑ\8cÑ\88е об Ñ\8dÑ\82иÑ\85 кодиÑ\80овкаÑ\85 и полÑ\8fÑ\85 Ñ\84оÑ\80м, пеÑ\80ейдиÑ\82е по Ñ\81Ñ\81Ñ\8bлке [<abbr title="Mozilla Developer Network - СеÑ\82Ñ\8c Ñ\80азÑ\80абоÑ\82Ñ\87иков Mozilla">MDN</abbr> web docs for `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).
+Ð\95Ñ\81ли вÑ\8b Ñ\85оÑ\82иÑ\82е Ñ\83знаÑ\82Ñ\8c болÑ\8cÑ\88е об Ñ\8dÑ\82иÑ\85 кодиÑ\80овкаÑ\85 и полÑ\8fÑ\85 Ñ\84оÑ\80м, пеÑ\80ейдиÑ\82е к [веб-докÑ\83менÑ\82аÑ\86ии <abbr title="Mozilla Developer Network - СеÑ\82Ñ\8c Ñ\80азÑ\80абоÑ\82Ñ\87иков Mozilla">MDN</abbr> по `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).
///
/// warning | Внимание
-В операции *функции операции пути* можно объявить несколько параметров `File` и `Form`, но нельзя также объявлять поля `Body`, которые предполагается получить в виде JSON, поскольку тело запроса будет закодировано с помощью `multipart/form-data`, а не `application/json`.
+В *операции пути* можно объявить несколько параметров `File` и `Form`, но нельзя также объявлять поля `Body`, которые предполагается получить в виде JSON, поскольку HTTP-запрос будет иметь тело, закодированное с помощью `multipart/form-data`, а не `application/json`.
Это не является ограничением **FastAPI**, это часть протокола HTTP.
## Резюме { #recap }
-Используйте `File`, `bytes` и `UploadFile` для работы с файлами, которые будут загружаться и передаваться в виде данных формы.
+Используйте `File`, `bytes` и `UploadFile`, чтобы объявлять файлы для загрузки в HTTP-запросе, передаваемые как данные формы.
# Данные формы { #form-data }
+
Когда вам нужно получить поля формы вместо JSON, вы можете использовать `Form`.
/// note | Примечание
# Статус-код ответа { #response-status-code }
-Подобно тому, как вы можете задать модель/схему ответа, вы можете объявить HTTP статус-код, используемый для ответа, с помощью параметра `status_code` в любой из *операций пути*:
+Подобно тому, как вы можете задать модель ответа, вы можете объявить HTTP статус-код, используемый для ответа, с помощью параметра `status_code` в любой из *операций пути*:
* `@app.get()`
* `@app.post()`
Это позволит:
-* Возвращать указанный код статуса в ответе.
-* Документировать его как код статуса ответа в OpenAPI схеме (а значит, и в пользовательских интерфейсах):
+* Возвращать указанный статус-код в ответе.
+* Документировать его как статус-код ответа в OpenAPI схеме (а значит, и в пользовательских интерфейсах):
<img src="/img/tutorial/response-status-code/image01.png">
///
-В протоколе HTTP числовой код состояния из 3 цифр отправляется как часть ответа.
+В протоколе HTTP числовой статус-код из 3 цифр отправляется как часть ответа.
-У кодов статуса есть названия, чтобы упростить их распознавание, но важны именно числовые значения.
+У статус-кодов есть названия, чтобы упростить их распознавание, но важны именно числовые значения.
Кратко:
-* `100 - 199` – статус-коды информационного типа. Они редко используются разработчиками напрямую. Ответы с этими кодами не могут иметь тела.
+* `100 - 199` – статус-коды информационного типа. Они редко используются разработчиками напрямую. Ответы с этими статус-кодами не могут иметь тела.
* **`200 - 299`** – статус-коды, сообщающие об успешной обработке запроса. Они используются чаще всего.
- * `200` – это код статуса ответа по умолчанию, который означает, что все прошло "OK".
+ * `200` – это статус-код по умолчанию, который означает, что все прошло "OK".
* Другим примером может быть статус `201`, "Created". Он обычно используется после создания новой записи в базе данных.
* Особый случай – `204`, "No Content". Этот статус ответа используется, когда нет содержимого для возврата клиенту, и поэтому ответ не должен иметь тела.
-* **`300 - 399`** – статус-коды, сообщающие о перенаправлениях. Ответы с этими кодами статуса могут иметь или не иметь тело, за исключением ответов со статусом `304`, "Not Modified", у которых не должно быть тела.
+* **`300 - 399`** – статус-коды, сообщающие о перенаправлениях. Ответы с этими статус-кодами могут иметь или не иметь тело, за исключением ответов со статусом `304`, "Not Modified", у которых не должно быть тела.
* **`400 - 499`** – статус-коды, сообщающие о клиентской ошибке. Это ещё одна наиболее часто используемая категория.
* Пример – код `404` для статуса "Not Found".
* Для общих ошибок со стороны клиента можно просто использовать код `400`.
-* `500 - 599` – статус-коды, сообщающие о серверной ошибке. Они почти никогда не используются разработчиками напрямую. Когда что-то идет не так в какой-то части кода вашего приложения или на сервере, он автоматически вернёт один из этих кодов статуса.
+* `500 - 599` – статус-коды, сообщающие о серверной ошибке. Они почти никогда не используются разработчиками напрямую. Когда что-то идет не так в какой-то части кода вашего приложения или на сервере, он автоматически вернёт один из этих статус-кодов.
/// tip | Подсказка
-Чтобы узнать больше о HTTP кодах статуса и о том, для чего каждый из них предназначен, ознакомьтесь с [<abbr title="Mozilla Developer Network - Сеть разработчиков Mozilla">MDN</abbr> документацией об HTTP статус-кодах](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status).
+Чтобы узнать больше о HTTP статус-кодах и о том, для чего каждый из них предназначен, ознакомьтесь с [<abbr title="Mozilla Developer Network - Сеть разработчиков Mozilla">MDN</abbr> документацией об HTTP статус-кодах](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status).
///
{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}
-`201` – это код статуса "Создано".
+`201` – это статус-код для "Created".
Но вам не обязательно запоминать, что означает каждый из этих кодов.
{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}
-Они содержат те же числовые значения, но позволяют использовать автозавершение редактора кода для выбора кода статуса:
+Они существуют только для удобства, содержат те же числовые значения, но позволяют использовать автозавершение редактора кода для выбора статус-кода:
<img src="/img/tutorial/response-status-code/image02.png">
-# Объявление примеров данных запроса { #declare-request-example-data }
+# Объявление примеров данных HTTP-запроса { #declare-request-example-data }
Вы можете объявлять примеры данных, которые ваше приложение может получать.
Эта дополнительная информация будет добавлена как есть в выходную **JSON Schema** этой модели и будет использоваться в документации API.
-Ð\92Ñ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c аÑ\82Ñ\80ибÑ\83Ñ\82 `model_config`, коÑ\82оÑ\80Ñ\8bй пÑ\80инимаеÑ\82 `dict`, как опиÑ\81ано в [Ð\94окÑ\83менÑ\82аÑ\86иÑ\8f Pydantic: Конфигурация](https://docs.pydantic.dev/latest/api/config/).
+Ð\92Ñ\8b можеÑ\82е иÑ\81полÑ\8cзоваÑ\82Ñ\8c аÑ\82Ñ\80ибÑ\83Ñ\82 `model_config`, коÑ\82оÑ\80Ñ\8bй пÑ\80инимаеÑ\82 `dict`, как опиÑ\81ано в [докÑ\83менÑ\82аÑ\86ии Pydantic: Конфигурация](https://docs.pydantic.dev/latest/api/config/).
Вы можете задать `"json_schema_extra"` с `dict`, содержащим любые дополнительные данные, которые вы хотите видеть в сгенерированной JSON Schema, включая `examples`.
/// note | Примечание
-OpenAPI 3.1.0 (используется начиная с FastAPI 0.99.0) добавил поддержку `examples`, который является частью стандарта **JSON Schema**.
+OpenAPI 3.1.0 (используется начиная с FastAPI 0.99.0) добавил поддержку `examples`, которое является частью стандарта **JSON Schema**.
До этого поддерживалось только ключевое слово `example` с одним примером. Оно всё ещё поддерживается в OpenAPI 3.1.0, но помечено как устаревшее и не является частью стандарта JSON Schema. Поэтому рекомендуется мигрировать `example` на `examples`. 🤓
Ещё до того как **JSON Schema** поддержала `examples`, в OpenAPI была поддержка другого поля, также называемого `examples`.
-ÐÑ\82и **Ñ\81пеÑ\86иÑ\84иÑ\87еÑ\81кие длÑ\8f OpenAPI** `examples` наÑ\85одÑ\8fÑ\82Ñ\81Ñ\8f в дÑ\80Ñ\83гой Ñ\81екÑ\86ии Ñ\81пеÑ\86иÑ\84икаÑ\86ии OpenAPI. Ð\9eни наÑ\85одÑ\8fÑ\82Ñ\81Ñ\8f в **подÑ\80обноÑ\81Ñ\82Ñ\8fÑ\85 длÑ\8f каждой опеÑ\80аÑ\86ии пÑ\83Ñ\82и (обÑ\80абоÑ\82Ñ\87ика пÑ\83Ñ\82и)**, а не внÑ\83Ñ\82Ñ\80и каждого обÑ\8aекÑ\82а Schema.
+ÐÑ\82и **Ñ\81пеÑ\86иÑ\84иÑ\87еÑ\81кие длÑ\8f OpenAPI** `examples` наÑ\85одÑ\8fÑ\82Ñ\81Ñ\8f в дÑ\80Ñ\83гой Ñ\81екÑ\86ии Ñ\81пеÑ\86иÑ\84икаÑ\86ии OpenAPI. Ð\9eни наÑ\85одÑ\8fÑ\82Ñ\81Ñ\8f в **подÑ\80обноÑ\81Ñ\82Ñ\8fÑ\85 каждой *опеÑ\80аÑ\86ии пÑ\83Ñ\82и***, а не внÑ\83Ñ\82Ñ\80и каждой JSON Schema.
И Swagger UI уже какое‑то время поддерживает именно это поле `examples`. Поэтому вы можете использовать его, чтобы **отобразить** разные **примеры в UI документации**.
Структура этого специфичного для OpenAPI поля `examples` — это `dict` с **несколькими примерами** (вместо `list`), каждый с дополнительной информацией, которая также будет добавлена в **OpenAPI**.
-ÐÑ\82о не помеÑ\89аеÑ\82Ñ\81Ñ\8f внÑ\83Ñ\82Ñ\80Ñ\8c каждого обÑ\8aекÑ\82а Schema в OpenAPI, это находится снаружи, непосредственно на уровне самой *операции пути*.
+ÐÑ\82о не помеÑ\89аеÑ\82Ñ\81Ñ\8f внÑ\83Ñ\82Ñ\80Ñ\8c каждой JSON Schema, Ñ\81одеÑ\80жаÑ\89ейÑ\81Ñ\8f в OpenAPI, это находится снаружи, непосредственно на уровне самой *операции пути*.
### Использование параметра `openapi_examples` { #using-the-openapi-examples-parameter }
## Что он делает { #what-it-does }
-Он будет искать в запросе HTTP-заголовок `Authorization`, проверять, что его значение — это `Bearer ` плюс некоторый токен, и вернет токен как `str`.
+Он будет искать в HTTP-запросе HTTP-заголовок `Authorization`, проверять, что его значение — это `Bearer ` плюс некоторый токен, и вернет токен как `str`.
-Если заголовок `Authorization` отсутствует или его значение не содержит токен `Bearer `, он сразу ответит ошибкой со статус-кодом 401 (`UNAUTHORIZED`).
+Если HTTP-заголовок `Authorization` отсутствует или его значение не содержит токен `Bearer `, он сразу ответит ошибкой со статус-кодом 401 (`UNAUTHORIZED`).
Вам даже не нужно проверять наличие токена, чтобы вернуть ошибку. Вы можете быть уверены: если ваша функция была выполнена, в этом токене будет `str`.
Точно так же, как мы используем Pydantic для объявления тел запросов, мы можем использовать его где угодно:
-{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}
+{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:16] *}
## Создать зависимость `get_current_user` { #create-a-get-current-user-dependency }
/// tip | Подсказка
-То, как устроена эта система зависимостей, позволяет иметь разные зависимости, которые возвращают модель `User`.
+То, как устроена эта система зависимостей, позволяет иметь разные зависимости (разные "dependables"), которые все возвращают модель `User`.
Мы не ограничены наличием только одной зависимости, которая может возвращать такой тип данных.
## Установка `PyJWT` { #install-pyjwt }
-Нам необходимо установить `pyjwt` для генерации и проверки JWT-токенов на языке Python.
+Нам необходимо установить `PyJWT` для генерации и проверки JWT-токенов на языке Python.
Убедитесь, что вы создали [виртуальное окружение](../../virtual-environments.md), активируйте его, а затем установите `pyjwt`:
</div>
-/// note | Ð\94ополниÑ\82елÑ\8cнаÑ\8f инÑ\84оÑ\80маÑ\86иÑ\8f
+/// note | Ð\9fÑ\80имеÑ\87ание
Если вы планируете использовать алгоритмы цифровой подписи, такие как RSA или ECDSA, вам следует установить зависимость библиотеки криптографии `pyjwt[crypto]`.
///
-Создайте служебную функцию для хэширования пароля, поступающего от пользователя.
+Создайте вспомогательную функцию для хэширования пароля, поступающего от пользователя.
-А затем создайте другую — для проверки соответствия полученного пароля и хранимого хэша.
+А затем создайте другую вспомогательную функцию — для проверки соответствия полученного пароля и хранимого хэша.
И еще одну — для аутентификации и возврата пользователя.
Когда `authenticate_user` вызывается с именем пользователя, которого нет в базе данных, мы все равно запускаем `verify_password` с использованием фиктивного хэша.
-Это гарантирует, что эндпоинт отвечает примерно за одно и то же время вне зависимости от того, существует имя пользователя или нет, предотвращая тайминговые атаки (атака по времени), с помощью которых можно было бы перечислять существующие имена пользователей.
+Это гарантирует, что эндпоинт отвечает примерно за одно и то же время вне зависимости от того, существует имя пользователя или нет, предотвращая **тайминговые атаки** (атаки по времени), с помощью которых можно было бы перечислять существующие имена пользователей.
-/// note | ТеÑ\85ниÑ\87еÑ\81кие деÑ\82али
+/// note | Ð\9fÑ\80имеÑ\87ание
Если проверить новую (фальшивую) базу данных `fake_users_db`, то можно увидеть, как теперь выглядит хэшированный пароль: `"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc"`.
///
-## Работа с JWT токенами { #handle-jwt-tokens }
+## Работа с JWT-токенами { #handle-jwt-tokens }
Импортируйте установленные модули.
Определите Pydantic-модель, которая будет использоваться для формирования ответа на запрос на получение токена.
-Создайте служебную функцию для генерации нового токена доступа.
+Создайте вспомогательную функцию для генерации нового токена доступа.
{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}
Создайте `timedelta` со временем истечения срока действия токена.
-Создайте реальный токен доступа JWT и верните его
+Создайте реальный токен доступа JWT и верните его.
{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}
Затем вы могли бы добавить права доступа к этой сущности, например "управлять" (для автомобиля) или "редактировать" (для блога).
-Затем вы могли бы передать этот JWT-токен пользователю (или боту), и они использовали бы его для выполнения определенных действий (управление автомобилем или редактирование запись в блоге), даже не имея учетной записи, просто используя JWT-токен, сгенерированный вашим API.
+Затем вы могли бы передать этот JWT-токен пользователю (или боту), и они использовали бы его для выполнения определенных действий (управление автомобилем или редактирование записи в блоге), даже не имея учетной записи, просто используя JWT-токен, сгенерированный вашим API.
Используя эти идеи, JWT можно применять для гораздо более сложных сценариев.
В отдельных случаях несколько сущностей могут иметь один и тот же идентификатор, скажем, `foo` (пользователь `foo`, автомобиль `foo` и запись в блоге `foo`).
-Поэтому, чтобы избежать коллизий идентификаторов, при создании JWT-токена для пользователя можно добавить префикс `username` к значению ключа `sub`. Таким образом, в данном примере значение `sub` было бы `username:johndoe`.
+Поэтому, чтобы избежать коллизий идентификаторов, при создании JWT-токена для пользователя можно добавить префикс `username:` к значению ключа `sub`. Таким образом, в данном примере значение `sub` могло бы быть: `username:johndoe`.
Важно помнить, что ключ `sub` должен иметь уникальный идентификатор для всего приложения и представлять собой строку.
<img src="/img/tutorial/security/image10.png">
-/// note | ТеÑ\85ниÑ\87еÑ\81каÑ\8f инÑ\84оÑ\80маÑ\86иÑ\8f
+/// note | Ð\9fÑ\80имеÑ\87ание
Обратите внимание на HTTP-заголовок `Authorization`, значение которого начинается с `Bearer `.
А ваши модели баз данных могут использовать любые другие имена.
-Но для логин-операции пути нам нужно использовать именно эти имена, чтобы быть совместимыми со спецификацией (и иметь возможность, например, использовать встроенную систему документации API).
+Но для *операции пути* входа в систему нам нужно использовать именно эти имена, чтобы быть совместимыми со спецификацией (и иметь возможность, например, использовать встроенную систему документации API).
В спецификации также указано, что `username` и `password` должны передаваться в виде данных формы (так что никакого JSON здесь нет).
Теперь получим данные о пользователе из (ненастоящей) базы данных, используя `username` из поля формы.
-Если такого пользователя нет, то мы возвращаем ошибку "Incorrect username or password" (неверное имя пользователя или пароль).
+Если такого пользователя нет, то мы возвращаем ошибку "Incorrect username or password".
Для ошибки используем исключение `HTTPException`:
```
/// note | Примечание
-Более полное объяснение `**user_dict` можно найти в [документации к **Дополнительным моделям**](../extra-models.md#about-user-in-dict).
+Более полное объяснение `**user_dict` можно найти в [документации к **Дополнительным моделям**](../extra-models.md#about-user-in-model-dump).
///
## Возврат токена { #return-the-token }
-Ответ операции пути `/token` должен быть объектом JSON.
+Ответ эндпоинта `token` должен быть объектом JSON.
В нём должен быть `token_type`. В нашем случае, поскольку мы используем токены типа "Bearer", тип токена должен быть `bearer`.
В этом простом примере мы намеренно поступим небезопасно и вернём тот же `username` в качестве токена.
/// tip | Подсказка
-В следующей главе вы увидите реальную защищённую реализацию с хешированием паролей и токенами <abbr title="JSON Web Tokens – JSON веб-токены">JWT</abbr>.
+В следующей главе вы увидите реальную защищённую реализацию с хешированием паролей и токенами <abbr title="JSON Web Tokens - JSON веб-токены">JWT</abbr>.
Но пока давайте сосредоточимся на необходимых нам деталях.
///
Теперь у вас есть инструменты для реализации полноценной системы безопасности на основе `username` и `password` для вашего API.
-Ð\98Ñ\81полÑ\8cзÑ\83Ñ\8f Ñ\8dÑ\82и Ñ\81Ñ\80едÑ\81Ñ\82ва, можно Ñ\81делаÑ\82Ñ\8c Ñ\81иÑ\81Ñ\82емÑ\83 безопаÑ\81ноÑ\81Ñ\82и Ñ\81овмеÑ\81Ñ\82имой Ñ\81 лÑ\8eбой базой даннÑ\8bÑ\85 и Ñ\81 лÑ\8eбой полÑ\8cзоваÑ\82елÑ\8cÑ\81кой или моделью данных.
+Ð\98Ñ\81полÑ\8cзÑ\83Ñ\8f Ñ\8dÑ\82и Ñ\81Ñ\80едÑ\81Ñ\82ва, можно Ñ\81делаÑ\82Ñ\8c Ñ\81иÑ\81Ñ\82емÑ\83 безопаÑ\81ноÑ\81Ñ\82и Ñ\81овмеÑ\81Ñ\82имой Ñ\81 лÑ\8eбой базой даннÑ\8bÑ\85 и Ñ\81 лÑ\8eбой моделÑ\8cÑ\8e полÑ\8cзоваÑ\82елÑ\8f или моделью данных.
Единственная деталь, которой не хватает, — система пока ещё не "защищена" по-настоящему.
-В следующей главе вы увидите, как использовать библиотеку безопасного хеширования паролей и токены <abbr title="JSON Web Tokens – JSON веб-токены">JWT</abbr>.
+В следующей главе вы увидите, как использовать библиотеку безопасного хеширования паролей и токены <abbr title="JSON Web Tokens - JSON веб-токены">JWT</abbr>.
# SQL (реляционные) базы данных { #sql-relational-databases }
-**FastAPI** не требует использовать SQL (реляционную) базу данных. Но вы можете использовать любую базу данных, которую хотите.
+**FastAPI** не требует использовать SQL (реляционную) базу данных. Но вы можете использовать **любую базу данных**, которую хотите.
Здесь мы рассмотрим пример с использованием [SQLModel](https://sqlmodel.tiangolo.com/).
/// tip | Подсказка
-Вы можете использовать любую другую библиотеку для работы с SQL или NoSQL базами данных (иногда их называют <abbr title="Object Relational Mapper - Объектно-реляционный маппер: термин для библиотеки, где некоторые классы представляют SQL-таблицы, а экземпляры представляют строки в этих таблицах">"ORMs"</abbr>), FastAPI ничего не навязывает. 😎
+Вы можете использовать любую другую библиотеку для работы с SQL или NoSQL базами данных (иногда их называют <abbr title="Object Relational Mapper - Объектно-реляционный маппер: красивый термин для библиотеки, где некоторые классы представляют SQL-таблицы, а экземпляры представляют строки в этих таблицах">"ORMs"</abbr>), FastAPI ничего не навязывает. 😎
///
Так как каждая модель SQLModel также является моделью Pydantic, вы можете использовать её в тех же **аннотациях типов**, в которых используете модели Pydantic.
-Например, если вы объявите параметр типа `Hero`, он будет прочитан из **JSON body (тела запроса)**.
+Например, если вы объявите параметр типа `Hero`, он будет прочитан из **JSON-тела запроса**.
Аналогично вы можете объявить её как **тип возвращаемого значения** функции, и тогда форма данных отобразится в автоматически сгенерированном UI документации API.
Вы можете предоставлять статические файлы автоматически из директории, используя `StaticFiles`.
+/// tip | Совет
+
+Если вам нужно разместить фронтенд, используйте вместо этого `app.frontend()`, подробнее читайте в разделе [Фронтенд](frontend.md).
+
+`app.frontend()` использует `StaticFiles` под капотом, с несколькими дополнительными преимуществами для фронтендов, такими как обработка маршрутизации на стороне клиента.
+
+///
+
## Использование `StaticFiles` { #use-staticfiles }
* Импортируйте `StaticFiles`.
"Монтирование" означает добавление полноценного "независимого" приложения на определённый путь, которое затем обрабатывает все подпути.
-Это отличается от использования `APIRouter`, так как примонтированное приложение является полностью независимым.
-OpenAPI и документация из вашего главного приложения не будут содержать ничего из примонтированного приложения, и т.д.
+Это отличается от использования `APIRouter`, так как примонтированное приложение является полностью независимым. OpenAPI и документация из вашего главного приложения не будут содержать ничего из примонтированного приложения, и т.д.
Вы можете прочитать больше об этом в [Расширенном руководстве пользователя](../advanced/index.md).
│ └── test_main.py
```
-Так как оба файла находятся в одной директории, для импорта объекта приложения из файла `main` в файл `test_main` Вы можете использовать относительный импорт:
+Так как этот файл находится в том же пакете, для импорта объекта `app` из модуля `main` (`main.py`) Вы можете использовать относительный импорт:
{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}
│ └── test_main.py
```
-Предположим, что в файле `main.py` с приложением **FastAPI** есть несколько **операций пути**.
+Предположим, что теперь в файле `main.py` с приложением **FastAPI** есть несколько других **операций пути**.
В нём описана операция `GET`, которая может вернуть ошибку.
### Расширенный файл тестов { #extended-testing-file }
-ТепеÑ\80Ñ\8c обновим Ñ\84айл `test_main.py`, добавив в него Ñ\82еÑ\81Ñ\82ов:
+ТепеÑ\80Ñ\8c можно обновиÑ\82Ñ\8c Ñ\84айл `test_main.py`, добавив в него Ñ\80аÑ\81Ñ\88иÑ\80еннÑ\8bе Ñ\82еÑ\81Ñ\82Ñ\8b:
{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *}
-Ð\95Ñ\81ли Ð\92Ñ\8b не знаеÑ\82е, как пеÑ\80едаÑ\82Ñ\8c инÑ\84оÑ\80маÑ\86иÑ\8e в запÑ\80оÑ\81е, можеÑ\82е воÑ\81полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f поиÑ\81ковиком (погÑ\83глиÑ\82Ñ\8c) и задать вопрос: "Как передать информацию в запросе с помощью `httpx`", можно даже спросить: "Как передать информацию в запросе с помощью `requests`", поскольку дизайн HTTPX основан на дизайне Requests.
+Ð\95Ñ\81ли Ð\92Ñ\8b не знаеÑ\82е, как пеÑ\80едаÑ\82Ñ\8c инÑ\84оÑ\80маÑ\86иÑ\8e в запÑ\80оÑ\81е, можеÑ\82е воÑ\81полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f поиÑ\81ком (Google) и задать вопрос: "Как передать информацию в запросе с помощью `httpx`", можно даже спросить: "Как передать информацию в запросе с помощью `requests`", поскольку дизайн HTTPX основан на дизайне Requests.
Затем Вы просто применяете найденные ответы в тестах.
Например:
-* Ð\9fеÑ\80едаÑ\91Ñ\82е *path*-паÑ\80амеÑ\82Ñ\80Ñ\8b или *query*-паÑ\80амеÑ\82Ñ\80Ñ\8b, впиÑ\81ав иÑ\85 непоÑ\81Ñ\80едÑ\81Ñ\82венно в Ñ\81Ñ\82Ñ\80окÑ\83 URL.
+* ЧÑ\82обÑ\8b пеÑ\80едаÑ\82Ñ\8c *path*-паÑ\80амеÑ\82Ñ\80 или *query*-паÑ\80амеÑ\82Ñ\80, добавÑ\8cÑ\82е его непоÑ\81Ñ\80едÑ\81Ñ\82венно в URL.
* Передаёте JSON в теле запроса, передав Python-объект (например: `dict`) через именованный параметр `json`.
-* Если же Вам необходимо отправить *форму с данными* вместо JSON, то используйте параметр `data` вместо `json`.
+* Если же Вам необходимо отправить *данные формы* вместо JSON, то используйте параметр `data` вместо `json`.
* Для передачи *HTTP-заголовков*, передайте объект `dict` через параметр `headers`.
* Для передачи *cookies* также передайте `dict`, но через параметр `cookies`.
$ python main.py
-// Error importing sirius, it's not installed 😱
+// Ошибка при импорте sirius, он не установлен 😱
Traceback (most recent call last):
File "main.py", line 1, in <module>
import sirius