Например, вы можете добавить дополнительный тип содержимого `image/png`, объявив, что ваша операция пути может возвращать JSON‑объект (с типом содержимого `application/json`) или PNG‑изображение:
### Фоновые задачи и зависимости с `yield`, технические детали { #background-tasks-and-dependencies-with-yield-technical-details }
До FastAPI 0.106.0 вызывать исключения после `yield` было невозможно: код после `yield` в зависимостях выполнялся уже после отправки ответа, поэтому [Обработчики исключений](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} к тому моменту уже отработали.
До FastAPI 0.106.0 вызывать исключения после `yield` было невозможно: код после `yield` в зависимостях выполнялся уже после отправки ответа, поэтому [Обработчики исключений](../tutorial/handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} к тому моменту уже отработали.
Так было сделано в основном для того, чтобы можно было использовать те же объекты, «отданные» зависимостями через `yield`, внутри фоновых задач, потому что код после `yield` выполнялся после завершения фоновых задач.
Свойство `servers` в спецификации OpenAPI является необязательным.
Если вы не укажете параметр `servers`, а `root_path` равен `/`, то свойство `servers` в сгенерированной схеме OpenAPI по умолчанию будет опущено. Это эквивалентно серверу со значением `url` равным `/`.
///
### Отключить автоматическое добавление сервера из `root_path` { #disable-automatic-server-from-root-path }
Если вы не хотите, чтобы FastAPI добавлял автоматический сервер, используя `root_path`, укажите параметр `root_path_in_servers=False`:
@ -4,7 +4,7 @@ FastAPI построен поверх **Pydantic**, и я показывал в
Но FastAPI также поддерживает использование <ahref="https://docs.python.org/3/library/dataclasses.html"class="external-link"target="_blank">`dataclasses`</a> тем же способом:
Это по-прежнему поддерживается благодаря **Pydantic**, так как в нём есть <ahref="https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel"class="external-link"target="_blank">встроенная поддержка `dataclasses`</a>.
@ -32,7 +32,7 @@ FastAPI построен поверх **Pydantic**, и я показывал в
Вы также можете использовать `dataclasses` в параметре `response_model`:
Этот dataclass будет автоматически преобразован в Pydantic dataclass.
@ -48,7 +48,7 @@ FastAPI построен поверх **Pydantic**, и я показывал в
В таком случае вы можете просто заменить стандартные `dataclasses` на `pydantic.dataclasses`, которая является полностью совместимой заменой (drop-in replacement):
Теперь используйте параметр `callbacks` в *декораторе операции пути вашего API*, чтобы передать атрибут `.routes` (это, по сути, просто `list` маршрутов/*операций пути*) из этого маршрутизатора обратных вызовов:
**<ahref="https://fastapicloud.com"class="external-link"target="_blank">FastAPI Cloud</a>** создан тем же автором и командой, стоящими за **FastAPI**.
Он упрощает процесс **создания образа**, **развертывания** и **доступа** к API с минимальными усилиями.
Некоторые облачные провайдеры ✨ [**спонсируют FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨ — это обеспечивает непрерывное и здоровое развитие FastAPI и его экосистемы.
Он переносит тот же **опыт разработчика** создания приложений с FastAPI на их **развертывание** в облаке. 🎉
FastAPI Cloud — основной спонсор и источник финансирования для open source проектов *FastAPI and friends*. ✨
И это показывает их искреннюю приверженность FastAPI и его сообществу (вам): они не только хотят предоставить вам хороший сервис, но и стремятся гарантировать, что у вас будет хороший и стабильный фреймворк — FastAPI. 🙇
Некоторые другие облачные провайдеры ✨ [**спонсируют FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨ тоже. 🙇
Возможно, вы захотите попробовать их сервисы и воспользоваться их руководствами:
В зависимости от вашего конкретного случая, есть несколько способов сделать это.
Есть несколько способов сделать это, в зависимости от вашего конкретного случая и используемых вами инструментов.
Вы можете **развернуть сервер** самостоятельно, используя различные инструменты. Например, можно использовать **облачный сервис**, который выполнит часть работы за вас. Также возможны и другие варианты.
Например, мы, команда, стоящая за FastAPI, создали <ahref="https://fastapicloud.com"class="external-link"target="_blank">**FastAPI Cloud**</a>, чтобы сделать развёртывание приложений FastAPI в облаке как можно более простым и прямолинейным, с тем же удобством для разработчика, что и при работе с FastAPI.
В этом блоке я покажу вам некоторые из основных концепций, которые вы, вероятно, должны иметь в виду при развертывании приложения **FastAPI** (хотя большинство из них применимо к любому другому типу веб-приложений).
В последующих разделах вы узнаете больше деталей и методов, необходимых для этого. ✨
Если произойдёт исключение, экземпляр `Request` всё ещё будет в области видимости, поэтому мы сможем прочитать тело запроса и использовать его при обработке ошибки:
В этом примере *операции пути*, объявленные в `router`, будут использовать пользовательский класс `TimedRoute` и получат дополнительный HTTP-заголовок `X-Response-Time` в ответе с временем, затраченным на формирование ответа:
При желании вы можете развернуть своё приложение FastAPI в <ahref="https://fastapicloud.com"class="external-link"target="_blank">FastAPI Cloud</a>, присоединяйтесь к списку ожидания, если ещё не сделали этого. 🚀
Если у вас уже есть аккаунт **FastAPI Cloud** (мы пригласили вас из списка ожидания 😉), вы можете развернуть ваше приложение одной командой.
Перед развертыванием убедитесь, что вы вошли в систему:
<divclass="termy">
```console
$ fastapi login
You are logged in to FastAPI Cloud 🚀
```
</div>
Затем разверните приложение:
<divclass="termy">
```console
$ fastapi deploy
Deploying to FastAPI Cloud...
✅ Deployment successful!
🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev
```
</div>
Вот и всё! Теперь вы можете открыть ваше приложение по этой ссылке. ✨
#### О FastAPI Cloud { #about-fastapi-cloud }
**<ahref="https://fastapicloud.com"class="external-link"target="_blank">FastAPI Cloud</a>** создан тем же автором и командой, что и **FastAPI**.
Он упрощает процесс **создания образа**, **развертывания** и **доступа** к API при минимальных усилиях.
Он переносит тот же **опыт разработчика**, что и при создании приложений на FastAPI, на их **развертывание** в облаке. 🎉
FastAPI Cloud — основной спонсор и источник финансирования для проектов с открытым исходным кодом из экосистемы *FastAPI and friends*. ✨
#### Развертывание у других облачных провайдеров { #deploy-to-other-cloud-providers }
FastAPI — это open source и стандартизированный фреймворк. Вы можете развернуть приложения FastAPI у любого облачного провайдера на ваш выбор.
Следуйте руководствам вашего облачного провайдера по развертыванию приложений FastAPI. 🤓
## Производительность { #performance }
Независимые бенчмарки TechEmpower показывают приложения **FastAPI**, работающие под управлением Uvicorn, как <ahref="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7"class="external-link"target="_blank">один из самых быстрых доступных фреймворков Python</a>, уступающий только самим Starlette и Uvicorn (используются внутри FastAPI). (*)
#### Как работает относительный импорт? { #how-relative-imports-work }
@ -313,9 +277,7 @@ from ...dependencies import get_token_header
Но помимо этого мы можем добавить новые теги для каждого отдельного *эндпоинта*, а также некоторые дополнительные ответы (`responses`), характерные для данного *эндпоинта*:
@ -341,17 +303,13 @@ from ...dependencies import get_token_header
Мы даже можем объявить [глобальные зависимости](dependencies/global-dependencies.md){.internal-link target=_blank}, которые будут объединены с зависимостями для каждого отдельного маршрутизатора:
Так как файлы `app/routers/users.py` и `app/routers/items.py` являются суб-модулями одного и того же Python-пакета `app`, то мы сможем их импортировать, воспользовавшись операцией относительного импорта `.`.
@ -414,17 +372,13 @@ from .routers.users import router
Поэтому, для того чтобы использовать обе эти переменные в одном файле, мы импортировали соответствующие суб-модули:
Но, несмотря на это, мы хотим использовать кастомный префикс (`prefix`) для подключенного маршрутизатора (`APIRouter`), в результате чего, каждая *операция пути* будет начинаться с `/admin`. Также мы хотим защитить наш маршрутизатор с помощью зависимостей, созданных для нашего проекта. И ещё мы хотим включить теги (`tags`) и ответы (`responses`).
Мы можем применить все вышеперечисленные настройки, не изменяя начальный `APIRouter`. Нам всего лишь нужно передать нужные параметры в `app.include_router()`.
Таким образом, оригинальный `APIRouter` не будет модифицирован, и мы сможем использовать файл `app/internal/admin.py` сразу в нескольких проектах организации.
@ -496,9 +446,7 @@ from .routers.users import router
Здесь мы это делаем ... просто, чтобы показать, что это возможно 🤷:
@ -143,6 +143,42 @@ OpenAPI определяет схему API для вашего API. И эта
Вы также можете использовать её для автоматической генерации кода для клиентов, которые взаимодействуют с вашим API. Например, для фронтенд-, мобильных или IoT-приложений.
При желании вы можете развернуть своё приложение FastAPI в <ahref="https://fastapicloud.com"class="external-link"target="_blank">FastAPI Cloud</a>, перейдите и присоединитесь к списку ожидания, если ещё не сделали этого. 🚀
Если у вас уже есть аккаунт **FastAPI Cloud** (мы пригласили вас из списка ожидания 😉), вы можете развернуть приложение одной командой.
Перед развертыванием убедитесь, что вы вошли в систему:
<divclass="termy">
```console
$ fastapi login
You are logged in to FastAPI Cloud 🚀
```
</div>
Затем разверните приложение:
<divclass="termy">
```console
$ fastapi deploy
Deploying to FastAPI Cloud...
✅ Deployment successful!
🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev
```
</div>
Готово! Теперь вы можете открыть своё приложение по этому URL. ✨
Многие другие объекты и модели будут автоматически преобразованы в JSON (включая ORM и т. п.). Попробуйте использовать те, что вам привычнее, с высокой вероятностью они уже поддерживаются.
Разверните приложение в **<ahref="https://fastapicloud.com"class="external-link"target="_blank">FastAPI Cloud</a>** одной командой: `fastapi deploy`. 🎉
#### О FastAPI Cloud { #about-fastapi-cloud }
**<ahref="https://fastapicloud.com"class="external-link"target="_blank">FastAPI Cloud</a>** создан тем же автором и командой, что и **FastAPI**.
Он упрощает процесс **создания образа**, **развертывания** и **доступа** к API с минимальными усилиями.
Он переносит тот же **опыт разработчика** при создании приложений с FastAPI на их **развертывание** в облаке. 🎉
FastAPI Cloud — основной спонсор и источник финансирования для open-source проектов «FastAPI и друзья». ✨
#### Развертывание у других облачных провайдеров { #deploy-to-other-cloud-providers }
FastAPI — open-source и основан на стандартах. Вы можете развернуть приложения FastAPI у любого облачного провайдера по вашему выбору.
Следуйте руководствам вашего облачного провайдера, чтобы развернуть приложения FastAPI у них. 🤓
## Резюме { #recap }
* Импортируйте `FastAPI`.
@ -321,3 +377,4 @@ https://example.com/items/foo
* Напишите **декоратор операции пути**, например `@app.get("/")`.
* Определите **функцию операции пути**; например, `def root(): ...`.
* Запустите сервер разработки командой `fastapi dev`.
* При желании разверните приложение командой `fastapi deploy`.
## Установка пользовательских обработчиков исключений { #install-custom-exception-handlers }
Вы можете добавить пользовательские обработчики исключений с помощью <ahref="https://www.starlette.dev/exceptions/"class="external-link"target="_blank">то же самое исключение - утилиты от Starlette</a>.
Вы можете добавить пользовательские обработчики исключений с помощью <ahref="https://www.starlette.dev/exceptions/"class="external-link"target="_blank">тех же утилит обработки исключений из Starlette</a>.
Допустим, у вас есть пользовательское исключение `UnicornException`, которое вы (или используемая вами библиотека) можете `вызвать`.
@ -117,7 +117,7 @@
Вы можете переопределить эти обработчики исключений на свои собственные.
Теперь, если перейти к `/items/foo`, то вместо стандартной JSON-ошибки с:
@ -149,36 +149,17 @@
вы получите текстовую версию:
```
1 validation error
path -> item_id
value is not a valid integer (type=type_error.integer)
Validation errors:
Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer
```
#### `RequestValidationError` или `ValidationError` { #requestvalidationerror-vs-validationerror }
/// warning | Внимание
Это технические детали, которые можно пропустить, если они не важны для вас сейчас.
///
`RequestValidationError` является подклассом Pydantic <ahref="https://docs.pydantic.dev/latest/concepts/models/#error-handling"class="external-link"target="_blank">`ValidationError`</a>.
**FastAPI** использует его для того, чтобы, если вы используете Pydantic-модель в `response_model`, и ваши данные содержат ошибку, вы увидели ошибку в журнале.
Но клиент/пользователь этого не увидит. Вместо этого клиент получит сообщение "Internal Server Error" с кодом состояния HTTP `500`.
Так и должно быть, потому что если в вашем *ответе* или где-либо в вашем коде (не в *запросе* клиента) возникает Pydantic `ValidationError`, то это действительно ошибка в вашем коде.
И пока вы не устраните ошибку, ваши клиенты/пользователи не должны иметь доступа к внутренней информации о ней, так как это может привести к уязвимости в системе безопасности.
Имейте в виду, что `RequestValidationError` содержит информацию об имени файла и строке, где произошла ошибка валидации, чтобы вы могли при желании отобразить её в логах с релевантными данными.
Но это означает, что если вы просто преобразуете её в строку и вернёте эту информацию напрямую, вы можете допустить небольшую утечку информации о своей системе, поэтому здесь код извлекает и показывает каждую ошибку отдельно.
///
### Используйте тело `RequestValidationError` { #use-the-requestvalidationerror-body }
Ошибка `RequestValidationError` содержит полученное `тело` с недопустимыми данными.
Существует множество способов обеспечения безопасности, аутентификации и авторизации.
@ -10,11 +10,11 @@
Но сначала давайте рассмотрим некоторые небольшие концепции.
## Куда-то торопишься?
## Куда-то торопишься? { #in-a-hurry }
Если вам не нужна информация о каких-либо из следующих терминов и вам просто нужно добавить защиту с аутентификацией на основе логина и пароля *прямо сейчас*, переходите к следующим главам.
## OAuth2
## OAuth2 { #oauth2 }
OAuth2 - это протокол, который определяет несколько способов обработки аутентификации и авторизации.
@ -24,7 +24,7 @@ OAuth2 включает в себя способы аутентификации
Это то, что используют под собой все кнопки "вход с помощью Facebook, Google, X (Twitter), GitHub" на страницах авторизации.
### OAuth 1
### OAuth 1 { #oauth-1 }
Ранее использовался протокол OAuth 1, который сильно отличается от OAuth2 и является более сложным, поскольку он включал прямые описания того, как шифровать сообщение.
@ -34,11 +34,11 @@ OAuth2 не указывает, как шифровать сообщение, о
/// tip | Подсказка
В разделе **Развертывание** вы увидите [как настроить протокол HTTPS бесплатно, используя Traefik и Let's Encrypt.](https://fastapi.tiangolo.com/ru/deployment/https/)
В разделе **Развертывание** вы увидите как настроить протокол HTTPS бесплатно, используя Traefik и Let's Encrypt.
///
## OpenID Connect
## OpenID Connect { #openid-connect }
OpenID Connect - это еще один протокол, основанный на **OAuth2**.
@ -48,7 +48,7 @@ OpenID Connect - это еще один протокол, основанный
Но вход в Facebook не поддерживает OpenID Connect. У него есть собственная вариация OAuth2.
### OpenID (не "OpenID Connect")
### OpenID (не "OpenID Connect") { #openid-not-openid-connect }
Также ранее использовался стандарт "OpenID", который пытался решить ту же проблему, что и **OpenID Connect**, но не был основан на OAuth2.
@ -56,7 +56,7 @@ OpenID Connect - это еще один протокол, основанный
В настоящее время не очень популярен и не используется.
## OpenAPI
## OpenAPI { #openapi }
OpenAPI (ранее известный как Swagger) - это открытая спецификация для создания API (в настоящее время является частью Linux Foundation).
@ -97,7 +97,7 @@ OpenAPI может использовать следующие схемы авт
Fast API предоставляет несколько инструментов для каждой из этих схем безопасности в модуле `fastapi.security`, которые упрощают использование этих механизмов безопасности.
* `table=True` сообщает SQLModel, что это *модель-таблица*, она должна представлять **таблицу** в SQL базе данных, это не просто *модель данных* (как обычный класс Pydantic).
* `Field(primary_key=True)` сообщает SQLModel, что `id` — это **первичный ключ** в SQL базе данных (подробнее о первичных ключах можно узнать в документации SQLModel).
* `Field(primary_key=True)` сообщает SQLModel, что `id` — это **первичный ключ** в SQL базе данных (подробнее о первичных ключах SQL можно узнать в документации SQLModel).
Благодаря типу `int | None`, SQLModel будет знать, что этот столбец должен быть `INTEGER` в SQL базе данных и должен допускать значение `NULL`.
**Примечание:** Мы используем `int | None` для поля первичного ключа, чтобы в Python-коде можно было *создать объект без `id`* (`id=None`), предполагая, что база данных *сгенерирует его при сохранении*. SQLModel понимает, что база данных предоставит `id`, и *определяет столбец как `INTEGER` (не `NULL`)* в схеме базы данных. См. <ahref="https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id"class="external-link"target="_blank">документацию SQLModel о первичных ключах</a> для подробностей.
* `Field(index=True)` сообщает SQLModel, что нужно создать **SQL индекс** для этого столбца, что позволит быстрее выполнять выборки при чтении данных, отфильтрованных по этому столбцу.
@ -107,7 +107,7 @@ $ pip install sqlmodel
Здесь мы создаём таблицы в обработчике события запуска приложения.
Для продакшна вы, вероятно, будете использовать скрипт миграций, который выполняется до запуска приложения. 🤓
Для продакшн вы, вероятно, будете использовать скрипт миграций, который выполняется до запуска приложения. 🤓
Если Вы не знаете, как передать информацию в запросе, можете воспользоваться поисковиком (погуглить) и задать вопрос: "Как передать информацию в запросе с помощью `httpx`", можно даже спросить: "Как передать информацию в запросе с помощью `requests`", поскольку дизайн HTTPX основан на дизайне Requests.
Иногда при попытке обновить pip вы можете получить ошибку **`No module named pip`**.
Если это произошло, установите и обновите pip с помощью команды ниже:
<divclass="termy">
```console
$ python -m ensurepip --upgrade
---> 100%
```
</div>
Эта команда установит pip, если он ещё не установлен, а также гарантирует, что установленная версия pip будет не старее, чем версия, доступная в `ensurepip`.
///
## Добавление `.gitignore` { #add-gitignore }
Если вы используете **Git** (а вам стоит его использовать), добавьте файл `.gitignore`, чтобы исключить из Git всё, что находится в вашей `.venv`.
@ -834,7 +854,7 @@ I solemnly swear 🐺
* Управлять **виртуальным окружением** ваших проектов
* Устанавливать **пакеты**
* Управлять **зависимостями и версиями** пакетов вашего проекта
* Обеспечивать наличие **точного** набора пакетов и версий к установке, включая их зависимости, чтобы вы были уверены, что сможете запускать проект в продакшне точно так же, как и на компьютере при разработке — это называется **locking**
* Обеспечивать наличие **точного** набора пакетов и версий к установке, включая их зависимости, чтобы вы были уверены, что сможете запускать проект в продакшн точно так же, как и на компьютере при разработке — это называется **locking**