Compare commits

...

4 Commits

Author SHA1 Message Date
github-actions[bot]
6fa573ce0b 📝 Update release notes
[skip ci]
2026-02-12 19:58:08 +00:00
Motov Yurii
55a9eee13a 🌐 Update translations for ru (update-outdated) (#14909)
* Update all

* Reflect latest changes in `docs/en/docs/tutorial/security/oauth2-jwt.md`
2026-02-12 20:57:34 +01:00
github-actions[bot]
c206f19b5d 📝 Update release notes
[skip ci]
2026-02-12 18:10:57 +00:00
Sebastián Ramírez
d11f820ac3 📝 Update docs for JWT to prevent timing attacks (#14908) 2026-02-12 19:10:35 +01:00
96 changed files with 577 additions and 624 deletions

View File

@@ -7,6 +7,14 @@ hide:
## Latest Changes
### Docs
* 📝 Update docs for JWT to prevent timing attacks. PR [#14908](https://github.com/fastapi/fastapi/pull/14908) by [@tiangolo](https://github.com/tiangolo).
### Translations
* 🌐 Update translations for ru (update-outdated). PR [#14909](https://github.com/fastapi/fastapi/pull/14909) by [@YuriiMotov](https://github.com/YuriiMotov).
## 0.129.0
### Breaking Changes

View File

@@ -116,7 +116,11 @@ And another utility to verify if a received password matches the hash stored.
And another one to authenticate and return a user.
{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *}
{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}
When `authenticate_user` is called with a username that doesn't exist in the database, we still run `verify_password` against a dummy hash.
This ensures the endpoint takes roughly the same amount of time to respond whether the username is valid or not, preventing **timing attacks** that could be used to enumerate existing usernames.
/// note
@@ -152,7 +156,7 @@ Define a Pydantic Model that will be used in the token endpoint for the response
Create a utility function to generate a new access token.
{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *}
{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}
## Update the dependencies { #update-the-dependencies }
@@ -162,7 +166,7 @@ Decode the received token, verify it, and return the current user.
If the token is invalid, return an HTTP error right away.
{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *}
{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}
## Update the `/token` *path operation* { #update-the-token-path-operation }
@@ -170,7 +174,7 @@ Create a `timedelta` with the expiration time of the token.
Create a real JWT access token and return it.
{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *}
{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}
### Technical details about the JWT "subject" `sub` { #technical-details-about-the-jwt-subject-sub }

View File

@@ -26,7 +26,7 @@
Например, чтобы объявить ещё один ответ со статус-кодом `404` и Pydantic-моделью `Message`, можно написать:
{* ../../docs_src/additional_responses/tutorial001_py39.py hl[18,22] *}
{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}
/// note | Примечание
@@ -203,7 +203,7 @@
А также ответ со статус-кодом `200`, который использует ваш `response_model`, но включает пользовательский `example`:
{* ../../docs_src/additional_responses/tutorial003_py39.py hl[20:31] *}
{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}
Всё это будет объединено и включено в ваш OpenAPI и отображено в документации API:

View File

@@ -18,7 +18,7 @@
Для этого объявляем метод `__call__`:
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[12] *}
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}
В этом случае именно `__call__` **FastAPI** использует для проверки дополнительных параметров и подзависимостей, и именно он будет вызван, чтобы позже передать значение параметру в вашей *функции-обработчике пути*.
@@ -26,7 +26,7 @@
Теперь мы можем использовать `__init__`, чтобы объявить параметры экземпляра, с помощью которых будем «параметризовать» зависимость:
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[9] *}
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}
В этом случае **FastAPI** вовсе не трогает `__init__` и не зависит от него — мы используем его напрямую в нашем коде.
@@ -34,7 +34,7 @@
Мы можем создать экземпляр этого класса так:
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[18] *}
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}
Так мы «параметризуем» нашу зависимость: теперь внутри неё хранится "bar" в атрибуте `checker.fixed_content`.
@@ -50,7 +50,7 @@ checker(q="somequery")
…и передаст возвращённое значение как значение зависимости в параметр `fixed_content_included` нашей *функции-обработчика пути*:
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[22] *}
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}
/// tip | Совет

View File

@@ -0,0 +1,61 @@
# Продвинутые типы Python { #advanced-python-types }
Ниже несколько дополнительных идей, которые могут быть полезны при работе с типами Python.
## Использование `Union` или `Optional` { #using-union-or-optional }
Если по какой-то причине ваш код не может использовать `|`, например, если это не аннотация типов, а что-то вроде `response_model=`, вместо вертикальной черты (`|`) можно использовать `Union` из `typing`.
Например, вы можете объявить, что значение может быть `str` или `None`:
```python
from typing import Union
def say_hi(name: Union[str, None]):
print(f"Hi {name}!")
```
В `typing` также есть сокращение, чтобы объявить, что значение может быть `None`, — `Optional`.
Вот совет с моей очень субъективной точки зрения:
- 🚨 Избегайте использования `Optional[SomeType]`
- Вместо этого ✨ используйте **`Union[SomeType, None]`** ✨.
Оба варианта эквивалентны и под капотом это одно и то же, но я бы рекомендовал `Union` вместо `Optional`, потому что слово «optional» может наводить на мысль, что значение необязательное, тогда как на самом деле это означает «значение может быть `None`», даже если оно не является необязательным и по-прежнему требуется.
По-моему, `Union[SomeType, None]` более явно передаёт смысл.
Речь только о словах и названиях. Но эти слова могут влиять на то, как вы и ваша команда думаете о коде.
В качестве примера возьмём такую функцию:
```python
from typing import Optional
def say_hi(name: Optional[str]):
print(f"Hey {name}!")
```
Параметр `name` объявлен как `Optional[str]`, но он не является необязательным: вы не можете вызвать функцию без этого параметра:
```Python
say_hi() # О нет, это вызывает ошибку! 😱
```
Параметр `name` по-прежнему обязателен (не «optional»), так как у него нет значения по умолчанию. При этом `name` принимает `None` в качестве значения:
```Python
say_hi(name=None) # Это работает, None допустим 🎉
```
Хорошая новость: в большинстве случаев вы сможете просто использовать `|` для объявления объединений типов:
```python
def say_hi(name: str | None):
print(f"Hey {name}!")
```
Так что обычно вам не о чем переживать из‑за названий вроде `Optional` и `Union`. 😎

View File

@@ -32,11 +32,11 @@
Файл `main.py`:
{* ../../docs_src/async_tests/app_a_py39/main.py *}
{* ../../docs_src/async_tests/app_a_py310/main.py *}
Файл `test_main.py` содержит тесты для `main.py`, теперь он может выглядеть так:
{* ../../docs_src/async_tests/app_a_py39/test_main.py *}
{* ../../docs_src/async_tests/app_a_py310/test_main.py *}
## Запуск тестов { #run-it }
@@ -56,7 +56,7 @@ $ pytest
Маркер `@pytest.mark.anyio` говорит pytest, что тестовая функция должна быть вызвана асинхронно:
{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[7] *}
{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}
/// tip | Подсказка
@@ -66,7 +66,7 @@ $ pytest
Затем мы можем создать `AsyncClient` со ссылкой на приложение и посылать асинхронные запросы, используя `await`.
{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[9:12] *}
{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}
Это эквивалентно следующему:
@@ -94,6 +94,6 @@ response = client.get('/')
/// tip | Подсказка
Если вы столкнулись с `RuntimeError: Task attached to a different loop` при вызове асинхронных функций в ваших тестах (например, при использовании <a href="https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop" class="external-link" target="_blank">MongoDB's MotorClient</a>), то не забывайте инициализировать объекты, которым нужен цикл событий (event loop), только внутри асинхронных функций, например, в `'@app.on_event("startup")` callback.
Если вы столкнулись с `RuntimeError: Task attached to a different loop` при вызове асинхронных функций в ваших тестах (например, при использовании <a href="https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop" class="external-link" target="_blank">MongoDB's MotorClient</a>), то не забывайте инициализировать объекты, которым нужен цикл событий (event loop), только внутри асинхронных функций, например, в `@app.on_event("startup")` callback.
///

View File

@@ -44,7 +44,7 @@ $ fastapi run --forwarded-allow-ips="*"
Например, вы объявили операцию пути `/items/`:
{* ../../docs_src/behind_a_proxy/tutorial001_01_py39.py hl[6] *}
{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}
Если клиент обратится к `/items`, по умолчанию произойдёт редирект на `/items/`.
@@ -115,7 +115,7 @@ sequenceDiagram
Хотя весь ваш код написан с расчётом, что путь один — `/app`.
{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[6] *}
{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}
Прокси будет «обрезать» префикс пути на лету перед передачей запроса на сервер приложения (скорее всего Uvicorn, запущенный через FastAPI CLI), поддерживая у вашего приложения иллюзию, что его обслуживают по `/app`, чтобы вам не пришлось менять весь код и добавлять префикс `/api/v1`.
@@ -193,7 +193,7 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
Здесь мы добавляем его в сообщение лишь для демонстрации.
{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[8] *}
{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}
Затем, если вы запустите Uvicorn так:
@@ -220,7 +220,7 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
Если нет возможности передать опцию командной строки `--root-path` (или аналог), вы можете указать параметр `root_path` при создании приложения FastAPI:
{* ../../docs_src/behind_a_proxy/tutorial002_py39.py hl[3] *}
{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}
Передача `root_path` в `FastAPI` эквивалентна опции командной строки `--root-path` для Uvicorn или Hypercorn.
@@ -241,17 +241,17 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
Uvicorn ожидает, что прокси обратится к нему по `http://127.0.0.1:8000/app`, а уже задача прокси — добавить сверху префикс `/api/v1`.
## О прокси с урезанным префиксом пути { #about-proxies-with-a-stripped-path-prefix }
## О прокси с функцией удаления префикса пути { #about-proxies-with-a-stripped-path-prefix }
Помните, что прокси с урезанным префиксом пути — лишь один из вариантов настройки.
Помните, что прокси с функцией удаления префикса пути — лишь один из вариантов настройки.
Во многих случаях по умолчанию прокси будет без урезанного префикса пути.
Во многих случаях по умолчанию прокси будет без функции удаления префикса пути.
В таком случае (без урезанного префикса) прокси слушает, например, по адресу `https://myawesomeapp.com`, и если браузер идёт на `https://myawesomeapp.com/api/v1/app`, а ваш сервер (например, Uvicorn) слушает на `http://127.0.0.1:8000`, то прокси (без урезанного префикса) обратится к Uvicorn по тому же пути: `http://127.0.0.1:8000/api/v1/app`.
В таком случае (без функции удаления префикса пути) прокси слушает, например, по адресу `https://myawesomeapp.com`, и если браузер идёт на `https://myawesomeapp.com/api/v1/app`, а ваш сервер (например, Uvicorn) слушает на `http://127.0.0.1:8000`, то прокси (без урезанного префикса) обратится к Uvicorn по тому же пути: `http://127.0.0.1:8000/api/v1/app`.
## Локальное тестирование с Traefik { #testing-locally-with-traefik }
Вы можете легко поэкспериментировать локально с урезанным префиксом пути, используя <a href="https://docs.traefik.io/" class="external-link" target="_blank">Traefik</a>.
Вы можете легко поэкспериментировать локально с функцией удаления префикса пути, используя <a href="https://docs.traefik.io/" class="external-link" target="_blank">Traefik</a>.
<a href="https://github.com/containous/traefik/releases" class="external-link" target="_blank">Скачайте Traefik</a> — это один бинарный файл; распакуйте архив и запустите его прямо из терминала.
@@ -400,7 +400,7 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
Например:
{* ../../docs_src/behind_a_proxy/tutorial003_py39.py hl[4:7] *}
{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}
Будет сгенерирована схема OpenAPI примерно такая:
@@ -455,7 +455,7 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
Если вы не хотите, чтобы FastAPI добавлял автоматический сервер, используя `root_path`, укажите параметр `root_path_in_servers=False`:
{* ../../docs_src/behind_a_proxy/tutorial004_py39.py hl[9] *}
{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}
и тогда этот сервер не будет добавлен в схему OpenAPI.

View File

@@ -30,7 +30,7 @@
Но если вы уверены, что содержимое, которое вы возвращаете, **сериализуемо в JSON**, вы можете передать его напрямую в класс ответа и избежать дополнительных накладных расходов, которые FastAPI понёс бы, пропуская возвращаемое содержимое через `jsonable_encoder` перед передачей в класс ответа.
{* ../../docs_src/custom_response/tutorial001b_py39.py hl[2,7] *}
{* ../../docs_src/custom_response/tutorial001b_py310.py hl[2,7] *}
/// info | Информация
@@ -55,7 +55,7 @@
- Импортируйте `HTMLResponse`.
- Передайте `HTMLResponse` в параметр `response_class` вашего декоратора операции пути.
{* ../../docs_src/custom_response/tutorial002_py39.py hl[2,7] *}
{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}
/// info | Информация
@@ -73,17 +73,17 @@
Тот же пример сверху, возвращающий `HTMLResponse`, может выглядеть так:
{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *}
{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}
/// warning | Предупреждение
`Response`, возвращённый напрямую вашей функцией-обработчиком пути, не будет задокументирован в OpenAPI (например, `Content-Type` нне будет задокументирова) и не будет виден в автоматически сгенерированной интерактивной документации.
`Response`, возвращённый напрямую вашей функцией-обработчиком пути, не будет задокументирован в OpenAPI (например, `Content-Type` не будет задокументирован) и не будет виден в автоматически сгенерированной интерактивной документации.
///
/// info | Информация
Разумеется, фактические заголовок `Content-Type`, статус-код и т.д. возьмутся из объекта `Response`, который вы вернули.
Разумеется, фактический заголовок `Content-Type`, статус-код и т.д. возьмутся из объекта `Response`, который вы вернули.
///
@@ -97,7 +97,7 @@
Например, это может быть что-то вроде:
{* ../../docs_src/custom_response/tutorial004_py39.py hl[7,21,23] *}
{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}
В этом примере функция `generate_html_response()` уже генерирует и возвращает `Response` вместо возврата HTML в `str`.
@@ -136,7 +136,7 @@
FastAPI (фактически Starlette) автоматически добавит заголовок Content-Length. Также будет добавлен заголовок Content-Type, основанный на `media_type` и с добавлением charset для текстовых типов.
{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
### `HTMLResponse` { #htmlresponse }
@@ -146,7 +146,7 @@ FastAPI (фактически Starlette) автоматически добави
Принимает текст или байты и возвращает ответ в виде простого текста.
{* ../../docs_src/custom_response/tutorial005_py39.py hl[2,7,9] *}
{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}
### `JSONResponse` { #jsonresponse }
@@ -180,7 +180,7 @@ FastAPI (фактически Starlette) автоматически добави
///
{* ../../docs_src/custom_response/tutorial001_py39.py hl[2,7] *}
{* ../../docs_src/custom_response/tutorial001_py310.py hl[2,7] *}
/// tip | Совет
@@ -194,13 +194,13 @@ FastAPI (фактически Starlette) автоматически добави
Вы можете вернуть `RedirectResponse` напрямую:
{* ../../docs_src/custom_response/tutorial006_py39.py hl[2,9] *}
{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}
---
Или можно использовать его в параметре `response_class`:
{* ../../docs_src/custom_response/tutorial006b_py39.py hl[2,7,9] *}
{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}
Если вы сделаете так, то сможете возвращать URL напрямую из своей функции-обработчика пути.
@@ -210,13 +210,13 @@ FastAPI (фактически Starlette) автоматически добави
Также вы можете использовать параметр `status_code` в сочетании с параметром `response_class`:
{* ../../docs_src/custom_response/tutorial006c_py39.py hl[2,7,9] *}
{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}
### `StreamingResponse` { #streamingresponse }
Принимает асинхронный генератор или обычный генератор/итератор и отправляет тело ответа потоково.
{* ../../docs_src/custom_response/tutorial007_py39.py hl[2,14] *}
{* ../../docs_src/custom_response/tutorial007_py310.py hl[2,14] *}
#### Использование `StreamingResponse` с файлоподобными объектами { #using-streamingresponse-with-file-like-objects }
@@ -226,7 +226,7 @@ FastAPI (фактически Starlette) автоматически добави
Это включает многие библиотеки для работы с облачным хранилищем, обработки видео и т.д.
{* ../../docs_src/custom_response/tutorial008_py39.py hl[2,10:12,14] *}
{* ../../docs_src/custom_response/tutorial008_py310.py hl[2,10:12,14] *}
1. Это функция-генератор. Она является «функцией-генератором», потому что содержит оператор(ы) `yield` внутри.
2. Используя блок `with`, мы гарантируем, что файлоподобный объект будет закрыт после завершения работы функции-генератора. То есть после того, как она закончит отправку ответа.
@@ -255,11 +255,11 @@ FastAPI (фактически Starlette) автоматически добави
Файловые ответы будут содержать соответствующие заголовки `Content-Length`, `Last-Modified` и `ETag`.
{* ../../docs_src/custom_response/tutorial009_py39.py hl[2,10] *}
{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}
Вы также можете использовать параметр `response_class`:
{* ../../docs_src/custom_response/tutorial009b_py39.py hl[2,8,10] *}
{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}
В этом случае вы можете возвращать путь к файлу напрямую из своей функции-обработчика пути.
@@ -273,7 +273,7 @@ FastAPI (фактически Starlette) автоматически добави
Вы могли бы создать `CustomORJSONResponse`. Главное, что вам нужно сделать — реализовать метод `Response.render(content)`, который возвращает содержимое как `bytes`:
{* ../../docs_src/custom_response/tutorial009c_py39.py hl[9:14,17] *}
{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}
Теперь вместо того, чтобы возвращать:
@@ -299,7 +299,7 @@ FastAPI (фактически Starlette) автоматически добави
В примере ниже **FastAPI** будет использовать `ORJSONResponse` по умолчанию во всех операциях пути вместо `JSONResponse`.
{* ../../docs_src/custom_response/tutorial010_py39.py hl[2,4] *}
{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}
/// tip | Совет

View File

@@ -64,7 +64,7 @@ FastAPI построен поверх **Pydantic**, и я показывал в
6. Здесь мы возвращаем словарь, содержащий `items`, который является списком dataclass.
FastAPI по-прежнему способен <abbr title="преобразование данных в формат, который можно передавать">сериализовать</abbr> данные в JSON.
FastAPI по-прежнему способен <dfn title="преобразование данных в формат, который можно передавать">сериализовать</dfn> данные в JSON.
7. Здесь `response_model` использует аннотацию типа — список dataclass `Author`.

View File

@@ -30,7 +30,7 @@
Мы создаём асинхронную функцию `lifespan()` с `yield` примерно так:
{* ../../docs_src/events/tutorial003_py39.py hl[16,19] *}
{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}
Здесь мы симулируем дорогую операцию startup по загрузке модели, помещая (фиктивную) функцию модели в словарь с моделями Машинного обучения до `yield`. Этот код будет выполнен до того, как приложение начнет принимать запросы, во время startup.
@@ -48,7 +48,7 @@
Первое, на что стоит обратить внимание, — мы определяем асинхронную функцию с `yield`. Это очень похоже на Зависимости с `yield`.
{* ../../docs_src/events/tutorial003_py39.py hl[14:19] *}
{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}
Первая часть функции, до `yield`, будет выполнена до запуска приложения.
@@ -60,7 +60,7 @@
Это превращает функцию в «асинхронный менеджер контекста».
{* ../../docs_src/events/tutorial003_py39.py hl[1,13] *}
{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}
Менеджер контекста в Python — это то, что можно использовать в операторе `with`. Например, `open()` можно использовать как менеджер контекста:
@@ -82,7 +82,7 @@ async with lifespan(app):
Параметр `lifespan` приложения `FastAPI` принимает асинхронный менеджер контекста, поэтому мы можем передать ему наш новый асинхронный менеджер контекста `lifespan`.
{* ../../docs_src/events/tutorial003_py39.py hl[22] *}
{* ../../docs_src/events/tutorial003_py310.py hl[22] *}
## Альтернативные события (устаревшие) { #alternative-events-deprecated }
@@ -104,7 +104,7 @@ async with lifespan(app):
Чтобы добавить функцию, которую нужно запустить до старта приложения, объявите её как обработчик события `"startup"`:
{* ../../docs_src/events/tutorial001_py39.py hl[8] *}
{* ../../docs_src/events/tutorial001_py310.py hl[8] *}
В этом случае функция-обработчик события `startup` инициализирует «базу данных» items (это просто `dict`) некоторыми значениями.
@@ -116,7 +116,7 @@ async with lifespan(app):
Чтобы добавить функцию, которую нужно запустить при завершении работы приложения, объявите её как обработчик события `"shutdown"`:
{* ../../docs_src/events/tutorial002_py39.py hl[6] *}
{* ../../docs_src/events/tutorial002_py310.py hl[6] *}
Здесь функция-обработчик события `shutdown` запишет строку текста `"Application shutdown"` в файл `log.txt`.

View File

@@ -2,7 +2,7 @@
Поскольку **FastAPI** основан на спецификации **OpenAPI**, его API можно описать в стандартном формате, понятном множеству инструментов.
Это упрощает генерацию актуальной **документации**, клиентских библиотек (<abbr title="Software Development Kits Наборы средств разработки">**SDKs**</abbr>) на разных языках, а также **тестирования** или **воркфлоу автоматизации**, которые остаются синхронизированными с вашим кодом.
Это упрощает генерацию актуальной **документации**, клиентских библиотек (<abbr title="Software Development Kits - Наборы средств разработки">**SDKs**</abbr>) на разных языках, а также **тестирования** или **воркфлоу автоматизации**, которые остаются синхронизированными с вашим кодом.
В этом руководстве вы узнаете, как сгенерировать **TypeScript SDK** для вашего бэкенда на FastAPI.
@@ -40,7 +40,7 @@ FastAPI автоматически генерирует спецификации
Начнём с простого приложения FastAPI:
{* ../../docs_src/generate_clients/tutorial001_py39.py hl[7:9,12:13,16:17,21] *}
{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}
Обратите внимание, что *операции пути (обработчики пути)* определяют модели, которые они используют для полезной нагрузки запроса и полезной нагрузки ответа, с помощью моделей `Item` и `ResponseMessage`.
@@ -98,7 +98,7 @@ npx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client
Например, у вас может быть раздел для **items** и другой раздел для **users**, и они могут быть разделены тегами:
{* ../../docs_src/generate_clients/tutorial002_py39.py hl[21,26,34] *}
{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}
### Генерация TypeScriptклиента с тегами { #generate-a-typescript-client-with-tags }
@@ -145,7 +145,7 @@ FastAPI использует **уникальный ID** для каждой *о
Затем вы можете передать эту пользовательскую функцию в **FastAPI** через параметр `generate_unique_id_function`:
{* ../../docs_src/generate_clients/tutorial003_py39.py hl[6:7,10] *}
{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}
### Генерация TypeScriptклиента с пользовательскими ID операций { #generate-a-typescript-client-with-custom-operation-ids }
@@ -157,7 +157,7 @@ FastAPI использует **уникальный ID** для каждой *о
### Предобработка спецификации OpenAPI для генератора клиента { #preprocess-the-openapi-specification-for-the-client-generator }
Сгенерированном коде всё ещё есть **дублирующаяся информация**.
В сгенерированном коде всё ещё есть **дублирующаяся информация**.
Мы уже знаем, что этот метод относится к **items**, потому что это слово есть в `ItemsService` (взято из тега), но при этом имя тега всё ещё добавлено префиксом к имени метода. 😕
@@ -167,7 +167,7 @@ FastAPI использует **уникальный ID** для каждой *о
Мы можем скачать OpenAPI JSON в файл `openapi.json`, а затем **убрать этот префикс‑тег** таким скриптом:
{* ../../docs_src/generate_clients/tutorial004_py39.py *}
{* ../../docs_src/generate_clients/tutorial004_py310.py *}
//// tab | Node.js

View File

@@ -57,13 +57,13 @@ app.add_middleware(UnicornMiddleware, some_config="rainbow")
Любой входящий запрос по `http` или `ws` будет перенаправлен на безопасную схему.
{* ../../docs_src/advanced_middleware/tutorial001_py39.py hl[2,6] *}
{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}
## `TrustedHostMiddleware` { #trustedhostmiddleware }
Гарантирует, что во всех входящих запросах корректно установлен `Host`‑заголовок, чтобы защититься от атак на HTTPзаголовок Host.
{* ../../docs_src/advanced_middleware/tutorial002_py39.py hl[2,6:8] *}
{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}
Поддерживаются следующие аргументы:
@@ -78,7 +78,7 @@ app.add_middleware(UnicornMiddleware, some_config="rainbow")
Это middleware обрабатывает как обычные, так и потоковые ответы.
{* ../../docs_src/advanced_middleware/tutorial003_py39.py hl[2,6] *}
{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}
Поддерживаются следующие аргументы:

View File

@@ -16,9 +16,9 @@
Вся логика регистрации URL-адресов для вебхуков и код, который реально отправляет эти запросы, целиком на вашей стороне. Вы пишете это так, как вам нужно, в своем собственном коде.
## Документирование вебхуков с помощью FastAPI и OpenAPI { #documenting-webhooks-with-fastapi-and-openapi }
## Документирование вебхуков с помощью **FastAPI** и OpenAPI { #documenting-webhooks-with-fastapi-and-openapi }
С FastAPI, используя OpenAPI, вы можете определить имена этих вебхуков, типы HTTP-операций, которые ваше приложение может отправлять (например, `POST`, `PUT` и т.д.), а также тела запросов, которые ваше приложение будет отправлять.
С **FastAPI**, используя OpenAPI, вы можете определить имена этих вебхуков, типы HTTP-операций, которые ваше приложение может отправлять (например, `POST`, `PUT` и т.д.), а также тела запросов, которые ваше приложение будет отправлять.
Это значительно упростит вашим пользователям реализацию их API для приема ваших вебхук-запросов; возможно, они даже смогут автоматически сгенерировать часть кода своего API.
@@ -32,7 +32,7 @@
При создании приложения на **FastAPI** есть атрибут `webhooks`, с помощью которого можно объявлять вебхуки так же, как вы объявляете операции пути (обработчики пути), например с `@app.webhooks.post()`.
{* ../../docs_src/openapi_webhooks/tutorial001_py39.py hl[9:13,36:53] *}
{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}
Определенные вами вебхуки попадут в схему **OpenAPI** и в автоматический **интерфейс документации**.

View File

@@ -12,7 +12,7 @@
Нужно убедиться, что он уникален для каждой операции.
{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}
### Использование имени *функции-обработчика пути* как operationId { #using-the-path-operation-function-name-as-the-operationid }
@@ -20,7 +20,7 @@
Делать это следует после добавления всех *операций пути*.
{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *}
{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}
/// tip | Совет
@@ -40,7 +40,7 @@
Чтобы исключить *операцию пути* из генерируемой схемы OpenAPI (а значит, и из автоматических систем документации), используйте параметр `include_in_schema` и установите его в `False`:
{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *}
{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}
## Расширенное описание из docstring { #advanced-description-from-docstring }
@@ -92,7 +92,7 @@
`openapi_extra` может пригодиться, например, чтобы объявить [Расширения OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions):
{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py39.py hl[6] *}
{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}
Если вы откроете автоматическую документацию API, ваше расширение появится внизу страницы конкретной *операции пути*.
@@ -139,9 +139,9 @@
Это можно сделать с помощью `openapi_extra`:
{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *}
{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}
В этом примере мы не объявляли никакую Pydantic-модель. Фактически тело запроса даже не <abbr title="преобразовано из простого формата, например байтов, в объекты Python">распарсено</abbr> как JSON, оно читается напрямую как `bytes`, а функция `magic_data_reader()` будет отвечать за его парсинг каким-то способом.
В этом примере мы не объявляли никакую Pydantic-модель. Фактически тело запроса даже не <dfn title="преобразован из простого формата, например байтов, в объекты Python">распарсено</dfn> как JSON, оно читается напрямую как `bytes`, а функция `magic_data_reader()` будет отвечать за его парсинг каким-то способом.
Тем не менее, мы можем объявить ожидаемую схему для тела запроса.
@@ -153,7 +153,7 @@
Например, в этом приложении мы не используем встроенную функциональность FastAPI для извлечения JSON Schema из моделей Pydantic, равно как и автоматическую валидацию JSON. Мы объявляем тип содержимого HTTP-запроса как YAML, а не JSON:
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}
Тем не менее, хотя мы не используем встроенную функциональность по умолчанию, мы всё равно используем Pydantic-модель, чтобы вручную сгенерировать JSON Schema для данных, которые мы хотим получить в YAML.
@@ -161,7 +161,7 @@
А затем в нашем коде мы напрямую парсим это содержимое YAML и снова используем ту же Pydantic-модель, чтобы валидировать YAML-содержимое:
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}
/// tip | Совет

View File

@@ -20,7 +20,7 @@
И затем вы можете установить `status_code` в этом *временном* объекте ответа.
{* ../../docs_src/response_change_status_code/tutorial001_py39.py hl[1,9,12] *}
{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}
После этого вы можете вернуть любой объект, который вам нужен, как обычно (`dict`, модель базы данных и т.д.).

View File

@@ -6,7 +6,7 @@
Затем установить cookies в этом временном объекте ответа.
{* ../../docs_src/response_cookies/tutorial002_py39.py hl[1, 8:9] *}
{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}
После этого можно вернуть любой объект, как и раньше (например, `dict`, объект модели базы данных и так далее).
@@ -24,7 +24,7 @@
Затем установите cookies и верните этот объект:
{* ../../docs_src/response_cookies/tutorial001_py39.py hl[10:12] *}
{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}
/// tip | Совет

View File

@@ -54,7 +54,7 @@
Вы можете поместить ваш XML-контент в строку, поместить её в `Response` и вернуть:
{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
## Примечания { #notes }

View File

@@ -6,7 +6,7 @@
А затем вы можете устанавливать HTTP-заголовки в этом *временном* объекте ответа.
{* ../../docs_src/response_headers/tutorial002_py39.py hl[1, 7:8] *}
{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}
После этого вы можете вернуть любой нужный объект, как обычно (например, `dict`, модель из базы данных и т.д.).
@@ -22,7 +22,7 @@
Создайте ответ, как описано в [Вернуть Response напрямую](response-directly.md){.internal-link target=_blank}, и передайте заголовки как дополнительный параметр:
{* ../../docs_src/response_headers/tutorial001_py39.py hl[10:12] *}
{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}
/// note | Технические детали

View File

@@ -20,7 +20,7 @@
* Она возвращает объект типа `HTTPBasicCredentials`:
* Он содержит отправленные `username` и `password`.
{* ../../docs_src/security/tutorial006_an_py39.py hl[4,8,12] *}
{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}
Когда вы впервые откроете URL (или нажмёте кнопку «Execute» в документации), браузер попросит ввести имя пользователя и пароль:
@@ -40,7 +40,7 @@
Затем можно использовать `secrets.compare_digest()`, чтобы убедиться, что `credentials.username` равен `"stanleyjobson"`, а `credentials.password``"swordfish"`.
{* ../../docs_src/security/tutorial007_an_py39.py hl[1,12:24] *}
{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}
Это было бы похоже на:
@@ -104,4 +104,4 @@ Pythonу придётся сравнить весь общий префикс `s
После того как обнаружено, что учётные данные некорректны, верните `HTTPException` со статус-кодом ответа 401 (тем же, что и при отсутствии учётных данных) и добавьте HTTP-заголовок `WWW-Authenticate`, чтобы браузер снова показал окно входа:
{* ../../docs_src/security/tutorial007_an_py39.py hl[26:30] *}
{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}

View File

@@ -54,7 +54,7 @@ $ pip install "fastapi[all]"
Вы можете использовать все те же возможности валидации и инструменты, что и для Pydanticмоделей, например разные типы данных и дополнительную валидацию через `Field()`.
{* ../../docs_src/settings/tutorial001_py39.py hl[2,5:8,11] *}
{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}
/// tip | Совет
@@ -70,7 +70,7 @@ $ pip install "fastapi[all]"
Затем вы можете использовать новый объект `settings` в вашем приложении:
{* ../../docs_src/settings/tutorial001_py39.py hl[18:20] *}
{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}
### Запуск сервера { #run-the-server }
@@ -104,11 +104,11 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.p
Например, у вас может быть файл `config.py` со следующим содержимым:
{* ../../docs_src/settings/app01_py39/config.py *}
{* ../../docs_src/settings/app01_py310/config.py *}
А затем использовать его в файле `main.py`:
{* ../../docs_src/settings/app01_py39/main.py hl[3,11:13] *}
{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}
/// tip | Совет
@@ -126,7 +126,7 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.p
Продолжая предыдущий пример, ваш файл `config.py` может выглядеть так:
{* ../../docs_src/settings/app02_an_py39/config.py hl[10] *}
{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}
Обратите внимание, что теперь мы не создаем экземпляр по умолчанию `settings = Settings()`.
@@ -134,7 +134,7 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.p
Теперь мы создаем зависимость, которая возвращает новый `config.Settings()`.
{* ../../docs_src/settings/app02_an_py39/main.py hl[6,12:13] *}
{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}
/// tip | Совет
@@ -146,13 +146,13 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.p
Затем мы можем запросить ее в *функции-обработчике пути* как зависимость и использовать там, где нужно.
{* ../../docs_src/settings/app02_an_py39/main.py hl[17,19:21] *}
{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}
### Настройки и тестирование { #settings-and-testing }
Далее будет очень просто предоставить другой объект настроек во время тестирования, создав переопределение зависимости для `get_settings`:
{* ../../docs_src/settings/app02_an_py39/test_main.py hl[9:10,13,21] *}
{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}
В переопределении зависимости мы задаем новое значение `admin_email` при создании нового объекта `Settings`, а затем возвращаем этот новый объект.
@@ -193,7 +193,7 @@ APP_NAME="ChimichangApp"
Затем обновите ваш `config.py` так:
{* ../../docs_src/settings/app03_an_py39/config.py hl[9] *}
{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}
/// tip | Совет
@@ -226,7 +226,7 @@ def get_settings():
Но так как мы используем декоратор `@lru_cache` сверху, объект `Settings` будет создан только один раз — при первом вызове. ✔️
{* ../../docs_src/settings/app03_an_py39/main.py hl[1,11] *}
{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}
Затем при любых последующих вызовах `get_settings()` в зависимостях для следующих запросов, вместо выполнения внутреннего кода `get_settings()` и создания нового объекта `Settings`, будет возвращаться тот же объект, что был возвращен при первом вызове, снова и снова.

View File

@@ -10,7 +10,7 @@
Сначала создайте основное, верхнего уровня, приложение **FastAPI** и его *операции пути*:
{* ../../docs_src/sub_applications/tutorial001_py39.py hl[3, 6:8] *}
{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}
### Подприложение { #sub-application }
@@ -18,7 +18,7 @@
Это подприложение — обычное стандартное приложение FastAPI, но именно оно будет «смонтировано»:
{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 14:16] *}
{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}
### Смонтируйте подприложение { #mount-the-sub-application }
@@ -26,7 +26,7 @@
В этом случае оно будет смонтировано по пути `/subapi`:
{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 19] *}
{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}
### Проверьте автоматическую документацию API { #check-the-automatic-api-docs }

View File

@@ -27,7 +27,7 @@ $ pip install jinja2
- Объявите параметр `Request` в *операции пути*, которая будет возвращать шаблон.
- Используйте созданный `templates`, чтобы отрендерить и вернуть `TemplateResponse`; передайте имя шаблона, объект `request` и словарь «context» с парами ключ-значение для использования внутри шаблона Jinja2.
{* ../../docs_src/templates/tutorial001_py39.py hl[4,11,15:18] *}
{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}
/// note | Примечание

View File

@@ -2,11 +2,11 @@
Если вам нужно, чтобы `lifespan` выполнялся в ваших тестах, вы можете использовать `TestClient` вместе с оператором `with`:
{* ../../docs_src/app_testing/tutorial004_py39.py hl[9:15,18,27:28,30:32,41:43] *}
{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}
Вы можете узнать больше подробностей в статье [Запуск lifespan в тестах на официальном сайте документации Starlette.](https://www.starlette.dev/lifespan/#running-lifespan-in-tests)
Для устаревших событий `startup` и `shutdown` вы можете использовать `TestClient` следующим образом:
{* ../../docs_src/app_testing/tutorial003_py39.py hl[9:12,20:24] *}
{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}

View File

@@ -4,7 +4,7 @@
Для этого используйте `TestClient` с менеджером контекста `with`, подключаясь к WebSocket:
{* ../../docs_src/app_testing/tutorial002_py39.py hl[27:31] *}
{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}
/// note | Примечание

View File

@@ -29,7 +29,7 @@
Для этого нужно обратиться к запросу напрямую.
{* ../../docs_src/using_request_directly/tutorial001_py39.py hl[1,7:8] *}
{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}
Если объявить параметр *функции-обработчика пути* с типом `Request`, **FastAPI** поймёт, что нужно передать объект `Request` в этот параметр.

View File

@@ -38,13 +38,13 @@ $ pip install websockets
Для примера нам нужен наиболее простой способ, который позволит сосредоточиться на серверной части веб‑сокетов и получить рабочий код:
{* ../../docs_src/websockets/tutorial001_py39.py hl[2,6:38,41:43] *}
{* ../../docs_src/websockets/tutorial001_py310.py hl[2,6:38,41:43] *}
## Создание `websocket` { #create-a-websocket }
Создайте `websocket` в своем **FastAPI** приложении:
{* ../../docs_src/websockets/tutorial001_py39.py hl[1,46:47] *}
{* ../../docs_src/websockets/tutorial001_py310.py hl[1,46:47] *}
/// note | Технические детали
@@ -58,7 +58,7 @@ $ pip install websockets
Через эндпоинт веб-сокета вы можете получать и отправлять сообщения.
{* ../../docs_src/websockets/tutorial001_py39.py hl[48:52] *}
{* ../../docs_src/websockets/tutorial001_py310.py hl[48:52] *}
Вы можете получать и отправлять двоичные, текстовые и JSON данные.
@@ -154,7 +154,7 @@ $ fastapi dev main.py
Если веб-сокет соединение закрыто, то `await websocket.receive_text()` вызовет исключение `WebSocketDisconnect`, которое можно поймать и обработать как в этом примере:
{* ../../docs_src/websockets/tutorial003_py39.py hl[79:81] *}
{* ../../docs_src/websockets/tutorial003_py310.py hl[79:81] *}
Чтобы воспроизвести пример:

View File

@@ -18,7 +18,7 @@
После этого смонтируйте его на путь.
{* ../../docs_src/wsgi/tutorial001_py39.py hl[1,3,23] *}
{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}
/// note | Примечание

View File

@@ -137,7 +137,7 @@ def read_url():
### <a href="https://marshmallow.readthedocs.io/en/stable/" class="external-link" target="_blank">Marshmallow</a> { #marshmallow }
Одна из основных возможностей, нужных системам API, — «<abbr title="также называемая маршаллингом или преобразованием">сериализация</abbr>» данных, то есть преобразование данных из кода (Python) во что-то, что можно отправить по сети. Например, преобразование объекта с данными из базы в JSON-объект. Преобразование объектов `datetime` в строки и т. п.
Одна из основных возможностей, нужных системам API, — «<dfn title="также называемая маршаллингом, преобразованием">сериализация</dfn>» данных, то есть преобразование данных из кода (Python) во что-то, что можно отправить по сети. Например, преобразование объекта с данными из базы в JSON-объект. Преобразование объектов `datetime` в строки и т. п.
Ещё одна важная возможность, востребованная API, — валидация данных: убеждаться, что данные валидны с учётом заданных параметров. Например, что какое-то поле — `int`, а не произвольная строка. Это особенно полезно для входящих данных.
@@ -145,7 +145,7 @@ def read_url():
Именно для этих возможностей и был создан Marshmallow. Это отличная библиотека, я много ей пользовался раньше.
Но она появилась до того, как в Python появились аннотации типов. Поэтому для определения каждой <abbr title="описание того, как данные должны быть сформированы">схемы</abbr> нужно использовать специальные утилиты и классы, предоставляемые Marshmallow.
Но она появилась до того, как в Python появились аннотации типов. Поэтому для определения каждой <dfn title="определение того, как должны быть сформированы данные">схемы</dfn> нужно использовать специальные утилиты и классы, предоставляемые Marshmallow.
/// check | Вдохновило **FastAPI** на
@@ -155,7 +155,7 @@ def read_url():
### <a href="https://webargs.readthedocs.io/en/latest/" class="external-link" target="_blank">Webargs</a> { #webargs }
Ещё одна важная возможность для API — <abbr title="чтение и преобразование данных в объекты Python">парсинг</abbr> данных из входящих HTTP-запросов.
Ещё одна важная возможность для API — <dfn title="чтение и преобразование в данные Python">парсинг</dfn> данных из входящих HTTP-запросов.
Webargs — это инструмент, созданный для этого поверх нескольких фреймворков, включая Flask.
@@ -245,7 +245,7 @@ Flask-apispec был создан теми же разработчиками, ч
В нём встроена система внедрения зависимостей, вдохновлённая Angular 2. Требуется предварительная регистрация «инжектируемых» компонентов (как и во всех известных мне системах внедрения зависимостей), что добавляет многословности и повторяемости кода.
Поскольку параметры описываются с помощью типов TypeScript (аналог аннотаций типов в Python), поддержка редактора весьма хороша.
Поскольку параметры описываются с помощью типов TypeScript (аналог аннотаций типов в Python), поддержка редактора кода весьма хороша.
Но так как данные о типах TypeScript не сохраняются после компиляции в JavaScript, он не может полагаться на типы для одновременного определения валидации, сериализации и документации. Из‑за этого и некоторых проектных решений для получения валидации, сериализации и автоматической генерации схем приходится добавлять декораторы во многих местах. В итоге это становится довольно многословным.
@@ -359,7 +359,7 @@ Hug вдохновил **FastAPI** объявлять параметр `response
В нём были автоматические валидация данных, сериализация данных и генерация схемы OpenAPI на основе тех же аннотаций типов в нескольких местах.
Определение схемы тела запроса не использовало те же аннотации типов Python, как в Pydantic, — это было ближе к Marshmallow, поэтому поддержка редактора была бы хуже, но всё равно APIStar оставался лучшим доступным вариантом.
Определение схемы тела запроса не использовало те же аннотации типов Python, как в Pydantic, — это было ближе к Marshmallow, поэтому поддержка редактора кода была бы хуже, но всё равно APIStar оставался лучшим доступным вариантом.
На тот момент у него были лучшие показатели в бенчмарках (его превосходил только Starlette).
@@ -419,7 +419,7 @@ Pydantic — это библиотека для определения вали
### <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a> { #starlette }
Starlette — это лёгкий <abbr title="Новый стандарт построения асинхронных веб-сервисов Python">ASGI</abbr> фреймворк/набор инструментов, идеально подходящий для создания высокопроизводительных asyncioсервисов.
Starlette — это лёгкий <dfn title="Новый стандарт построения асинхронных веб-приложений на Python">ASGI</dfn> фреймворк/набор инструментов, идеально подходящий для создания высокопроизводительных asyncioсервисов.
Он очень простой и интуитивный. Спроектирован так, чтобы его было легко расширять, и чтобы компоненты были модульными.

View File

@@ -4,7 +4,7 @@
## Нет времени? { #in-a-hurry }
<abbr title="too long; didn't read слишком длинно; не читал"><strong>TL;DR:</strong></abbr>
<abbr title="too long; didn't read - слишком длинно; не читал"><strong>TL;DR:</strong></abbr>
Если вы используете сторонние библиотеки, которые нужно вызывать с `await`, например:
@@ -68,13 +68,13 @@ def results():
Асинхронный код значит, что в языке 💬 есть способ сказать компьютеру/программе 🤖, что в некоторый момент кода ему 🤖 придётся подождать, пока *что-то ещё* где-то в другом месте завершится. Назовём это *что-то ещё* «медленный файл» 📝.
И пока мы ждём завершения работы с «медленныи файлом» 📝, компьютер может заняться другой работой.
И пока мы ждём завершения работы с «медленным файлом» 📝, компьютер может заняться другой работой.
Затем компьютер/программа 🤖 будет возвращаться каждый раз, когда появится возможность (пока снова где-то идёт ожидание), или когда 🤖 завершит всю текущую работу. И он 🤖 проверит, не завершилась ли какая-либо из задач, которых он ждал, и сделает то, что нужно.
Далее он 🤖 возьмёт первую завершившуюся задачу (скажем, наш «медленный файл» 📝) и продолжит делать с ней то, что требуется.
Это «ожидание чего-то ещё» обычно относится к операциям <abbr title="Input and Output Ввод/вывод">I/O</abbr>, которые относительно «медленные» (по сравнению со скоростью процессора и оперативной памяти), например ожидание:
Это «ожидание чего-то ещё» обычно относится к операциям <abbr title="Input and Output - Ввод/вывод">I/O</abbr>, которые относительно «медленные» (по сравнению со скоростью процессора и оперативной памяти), например ожидание:
* отправки данных клиентом по сети
* получения клиентом данных, отправленных вашей программой по сети
@@ -85,7 +85,7 @@ def results():
* возврата результатов запроса к базе данных
* и т.д.
Поскольку основное время выполнения уходит на ожидание операций <abbr title="Input and Output Ввод/вывод">I/O</abbr>, их называют операциями, «ограниченными вводом-выводом» (I/O bound).
Поскольку основное время выполнения уходит на ожидание операций <abbr title="Input and Output - Ввод/вывод">I/O</abbr>, их называют операциями, «ограниченными вводом-выводом» (I/O bound).
Это называется «асинхронным», потому что компьютеру/программе не нужно «синхронизироваться» с медленной задачей, простаивая и выжидая точный момент её завершения, чтобы забрать результат и продолжить работу.
@@ -277,7 +277,7 @@ def results():
В этом сценарии каждый уборщик (включая вас) был бы процессором, выполняющим свою часть работы.
И так как основное время выполнения уходит на реальную работу (а не ожидание), а работу в компьютере выполняет <abbr title="Central Processing Unit Центральный процессор">CPU</abbr>, такие задачи называют «ограниченными процессором» (CPU bound).
И так как основное время выполнения уходит на реальную работу (а не ожидание), а работу в компьютере выполняет <abbr title="Central Processing Unit - Центральный процессор">CPU</abbr>, такие задачи называют «ограниченными процессором» (CPU bound).
---
@@ -417,7 +417,7 @@ Starlette (и **FastAPI**) основаны на <a href="https://anyio.readthed
Когда вы объявляете *функцию-обработчик пути* обычным `def` вместо `async def`, она запускается во внешнем пуле потоков, который затем «ожидается», вместо прямого вызова (прямой вызов заблокировал бы сервер).
Если вы пришли из другого async-фреймворка, который работает иначе, и привыкли объявлять тривиальные *функции-обработчики пути*, выполняющие только вычисления, через простой `def` ради крошечной выгоды в производительности (около 100 наносекунд), обратите внимание: в **FastAPI** эффект будет противоположным. В таких случаях лучше использовать `async def`, если только ваши *функции-обработчики пути* не используют код, выполняющий блокирующий <abbr title="Input/Output Ввод/вывод: чтение или запись на диск, сетевые соединения.">I/O</abbr>.
Если вы пришли из другого async-фреймворка, который работает иначе, и привыкли объявлять тривиальные *функции-обработчики пути*, выполняющие только вычисления, через простой `def` ради крошечной выгоды в производительности (около 100 наносекунд), обратите внимание: в **FastAPI** эффект будет противоположным. В таких случаях лучше использовать `async def`, если только ваши *функции-обработчики пути* не используют код, выполняющий блокирующий <abbr title="Input/Output - Ввод/вывод: чтение или запись на диск, сетевые соединения.">I/O</abbr>.
Тем не менее, в обоих случаях велика вероятность, что **FastAPI** [всё равно будет быстрее](index.md#performance){.internal-link target=_blank} (или как минимум сопоставим) с вашим предыдущим фреймворком.

View File

@@ -16,19 +16,19 @@
* **Uvicorn**: ASGI-сервер
* **Starlette**: (использует Uvicorn) веб-микрофреймворк
* **FastAPI**: (использует Starlette) API-микрофреймворк с рядом дополнительных возможностей для создания API, включая валидацию данных и т. п.
* **FastAPI**: (использует Starlette) API-микрофреймворк с рядом дополнительных возможностей для создания API, включая валидацию данных и т.п.
* **Uvicorn**:
* Будет иметь наилучшую производительность, так как помимо самого сервера у него немного дополнительного кода.
* Вы не будете писать приложение непосредственно на Uvicorn. Это означало бы, что Ваш код должен включать как минимум весь код, предоставляемый Starlette (или **FastAPI**). И если Вы так сделаете, то в конечном итоге Ваше приложение будет иметь те же накладные расходы, что и при использовании фреймворка, минимизирующего код Вашего приложения и Ваши ошибки.
* Если Вы сравниваете Uvicorn, сравнивайте его с Daphne, Hypercorn, uWSGI и т. д. — серверами приложений.
* Если Вы сравниваете Uvicorn, сравнивайте его с Daphne, Hypercorn, uWSGI и т.д. — серверами приложений.
* **Starlette**:
* Будет на следующем месте по производительности после Uvicorn. Фактически Starlette запускается под управлением Uvicorn, поэтому он может быть только «медленнее» Uvicorn из‑за выполнения большего объёма кода.
* Зато он предоставляет Вам инструменты для создания простых веб‑приложений с маршрутизацией по путям и т. п.
* Если Вы сравниваете Starlette, сравнивайте его с Sanic, Flask, Django и т. д. — веб‑фреймворками (или микрофреймворками).
* Зато он предоставляет Вам инструменты для создания простых веб‑приложений с маршрутизацией по путям и т.п.
* Если Вы сравниваете Starlette, сравнивайте его с Sanic, Flask, Django и т.д. — веб‑фреймворками (или микрофреймворками).
* **FastAPI**:
* Точно так же, как Starlette использует Uvicorn и не может быть быстрее него, **FastAPI** использует Starlette, поэтому не может быть быстрее его.
* FastAPI предоставляет больше возможностей поверх Starlette — те, которые почти всегда нужны при создании API, такие как валидация и сериализация данных. В довесок Вы ещё и получаете автоматическую документацию (автоматическая документация даже не увеличивает накладные расходы при работе приложения, так как она создаётся при запуске).
* Если бы Вы не использовали FastAPI, а использовали Starlette напрямую (или другой инструмент вроде Sanic, Flask, Responder и т. д.), Вам пришлось бы самостоятельно реализовать валидацию и сериализацию данных. То есть, в итоге, Ваше приложение имело бы такие же накладные расходы, как если бы оно было создано с использованием FastAPI. И во многих случаях валидация и сериализация данных представляют собой самый большой объём кода, написанного в приложениях.
* Если бы Вы не использовали FastAPI, а использовали Starlette напрямую (или другой инструмент вроде Sanic, Flask, Responder и т.д.), Вам пришлось бы самостоятельно реализовать валидацию и сериализацию данных. То есть, в итоге, Ваше приложение имело бы такие же накладные расходы, как если бы оно было создано с использованием FastAPI. И во многих случаях валидация и сериализация данных представляют собой самый большой объём кода, написанного в приложениях.
* Таким образом, используя FastAPI, Вы экономите время разработки, уменьшаете количество ошибок, строк кода и, вероятно, получите ту же производительность (или лучше), как и если бы не использовали его (поскольку Вам пришлось бы реализовать все его возможности в своём коде).
* Если Вы сравниваете FastAPI, сравнивайте его с фреймворком веб‑приложений (или набором инструментов), который обеспечивает валидацию данных, сериализацию и документацию, такими как Flask-apispec, NestJS, Molten и им подобные. Фреймворки с интегрированной автоматической валидацией данных, сериализацией и документацией.

View File

@@ -27,13 +27,13 @@
В [предыдущей главе про HTTPS](https.md){.internal-link target=_blank} мы разобрались, как HTTPS обеспечивает шифрование для вашего API.
Также мы увидели, что HTTPS обычно обеспечивает компонент, **внешний** по отношению к серверу вашего приложения — **TLS Termination Proxy**.
Также мы увидели, что HTTPS обычно обеспечивает компонент, **внешний** по отношению к серверу вашего приложения — **прокси-сервер TSL-терминации**.
И должен быть компонент, отвечающий за **обновление HTTPSсертификатов** — это может быть тот же самый компонент или отдельный.
### Примеры инструментов для HTTPS { #example-tools-for-https }
Некоторые инструменты, которые можно использовать как TLS Termination Proxy:
Некоторые инструменты, которые можно использовать как прокси-сервер TSL-терминации:
* Traefik
* Автоматически обновляет сертификаты ✨
@@ -47,7 +47,7 @@
* С внешним компонентом (например, cert-manager) для обновления сертификатов
* Обрабатывается внутри облачного провайдера как часть его услуг (см. ниже 👇)
Другой вариант — использовать **облачный сервис**, который возьмёт на себя больше задач, включая настройку HTTPS. Там могут быть ограничения или дополнительная стоимость и т.п., но в таком случае вам не придётся самим настраивать TLS Termination Proxy.
Другой вариант — использовать **облачный сервис**, который возьмёт на себя больше задач, включая настройку HTTPS. Там могут быть ограничения или дополнительная стоимость и т.п., но в таком случае вам не придётся самим настраивать прокси-сервер TSL-терминации.
В следующих главах я покажу конкретные примеры.
@@ -214,7 +214,7 @@
Процесс‑менеджер, вероятно, будет тем, кто слушает **порт** на IP. И он будет передавать всю коммуникацию воркер‑процессам.
Эти воркеры будут запускать ваше приложение, выполнять основные вычисления для получения **запроса** и возврата **ответа**, и загружать всё, что вы кладёте в переменные, в RAM.
Эти воркеры будут запускать ваше приложение, выполнять основные вычисления для получения **HTTPзапроса** и возврата **HTTPответа**, и загружать всё, что вы кладёте в переменные, в RAM.
<img src="/img/deployment/concepts/process-ram.drawio.svg">
@@ -289,7 +289,7 @@
Ваш сервер(а) — это **ресурс**, который ваши программы могут потреблять или **использовать**: время вычислений на CPU и доступную оперативную память (RAM).
Какую долю системных ресурсов вы хотите потреблять/использовать? Можно подумать «немного», но на практике вы, скорее всего, захотите потреблять **максимум без падений**.
Какую долю системных ресурсов вы хотите потреблять/использовать? Можно подумать «немного», но на практике вы, вероятно, захотите потреблять **максимум без падений**.
Если вы платите за 3 сервера, но используете лишь малую часть их RAM и CPU, вы, вероятно, **тратите деньги впустую** 💸 и **электроэнергию серверов** 🌎 и т.п.

View File

@@ -14,7 +14,7 @@
<summary>Предпросмотр Dockerfile 👀</summary>
```Dockerfile
FROM python:3.9
FROM python:3.14
WORKDIR /code
@@ -166,7 +166,7 @@ def read_item(item_id: int, q: str | None = None):
```{ .dockerfile .annotate }
# (1)!
FROM python:3.9
FROM python:3.14
# (2)!
WORKDIR /code
@@ -273,9 +273,9 @@ CMD fastapi run app/main.py --port 80
└── requirements.txt
```
#### За прокси-сервером TLS терминации { #behind-a-tls-termination-proxy }
#### За прокси-сервером TSL-терминации { #behind-a-tls-termination-proxy }
Если вы запускаете контейнер за прокси-сервером завершения TLS (балансировщиком нагрузки), таким как Nginx или Traefik, добавьте опцию `--proxy-headers`. Это сообщит Uvicorn (через FastAPI CLI), что приложение работает за HTTPS и можно доверять соответствующим заголовкам.
Если вы запускаете контейнер за прокси-сервером TSL-терминации (балансировщиком нагрузки), таким как Nginx или Traefik, добавьте опцию `--proxy-headers`. Это сообщит Uvicorn (через FastAPI CLI), что приложение работает за HTTPS и можно доверять соответствующим заголовкам.
```Dockerfile
CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"]
@@ -390,7 +390,7 @@ $ docker run -d --name mycontainer -p 80:80 myimage
Тогда в `Dockerfile` нужно изменить пути копирования:
```{ .dockerfile .annotate hl_lines="10 13" }
FROM python:3.9
FROM python:3.14
WORKDIR /code
@@ -454,7 +454,7 @@ CMD ["fastapi", "run", "main.py", "--port", "80"]
## Репликация — количество процессов { #replication-number-of-processes }
Если у вас есть <abbr title="Группа машин, настроенных так, чтобы быть соединенными и работать вместе определенным образом.">кластер</abbr> машин с **Kubernetes**, Docker Swarm Mode, Nomad или другой похожей системой для управления распределёнными контейнерами на нескольких машинах, скорее всего вы будете **управлять репликацией** на **уровне кластера**, а не использовать **менеджер процессов** (например, Uvicorn с воркерами) в каждом контейнере.
Если у вас есть <dfn title="Группа машин, настроенных так, чтобы быть соединенными и работать вместе определенным образом.">кластер</dfn> машин с **Kubernetes**, Docker Swarm Mode, Nomad или другой похожей системой для управления распределёнными контейнерами на нескольких машинах, скорее всего вы будете **управлять репликацией** на **уровне кластера**, а не использовать **менеджер процессов** (например, Uvicorn с воркерами) в каждом контейнере.
Одна из таких систем управления распределёнными контейнерами, как Kubernetes, обычно имеет встроенный способ управлять **репликацией контейнеров**, поддерживая **балансировку нагрузки** для входящих запросов — всё это на **уровне кластера**.
@@ -462,17 +462,17 @@ CMD ["fastapi", "run", "main.py", "--port", "80"]
### Балансировщик нагрузки { #load-balancer }
При использовании контейнеров обычно есть компонент, **слушающий главный порт**. Это может быть другой контейнер — **прокси завершения TLS** для обработки **HTTPS** или похожий инструмент.
При использовании контейнеров обычно есть компонент, **слушающий главный порт**. Это может быть другой контейнер — **прокси-сервер TSL-терминации** для обработки **HTTPS** или похожий инструмент.
Поскольку этот компонент принимает **нагрузку** запросов и распределяет её между воркерами **сбалансированно**, его часто называют **балансировщиком нагрузки**.
/// tip | Подсказка
Тот же компонент **прокси завершения TLS**, который обрабатывает HTTPS, скорее всего также будет **балансировщиком нагрузки**.
Тот же компонент **прокси-сервер TSL-терминации**, который обрабатывает HTTPS, скорее всего также будет **балансировщиком нагрузки**.
///
При работе с контейнерами система, которую вы используете для запуска и управления ими, уже имеет внутренние средства для передачи **сетевого взаимодействия** (например, HTTP-запросов) от **балансировщика нагрузки** (который также может быть **прокси завершения TLS**) к контейнеру(-ам) с вашим приложением.
При работе с контейнерами система, которую вы используете для запуска и управления ими, уже имеет внутренние средства для передачи **сетевого взаимодействия** (например, HTTP-запросов) от **балансировщика нагрузки** (который также может быть **прокси-сервером TSL-терминации**) к контейнеру(-ам) с вашим приложением.
### Один балансировщик — несколько контейнеров-воркеров { #one-load-balancer-multiple-worker-containers }
@@ -499,7 +499,7 @@ CMD ["fastapi", "run", "main.py", "--port", "80"]
В таких случаях вы можете использовать опцию командной строки `--workers`, чтобы указать нужное количество воркеров:
```{ .dockerfile .annotate }
FROM python:3.9
FROM python:3.14
WORKDIR /code

View File

@@ -65,7 +65,7 @@
Чаще всего всё начинается с **приобретения** **имени домена**. Затем вы настраиваете его на DNSсервере (возможно, у того же облачного провайдера).
Скорее всего, вы получите облачный сервер (виртуальную машину) или что-то подобное, и у него будет <abbr title="Не изменяется">постоянный</abbr> **публичный IP-адрес**.
Скорее всего, вы получите облачный сервер (виртуальную машину) или что-то подобное, и у него будет <dfn title="Со временем не меняется. Не динамический.">постоянный</dfn> **публичный IP-адрес**.
На DNSсервере(ах) вы настроите запись («`A record`» - запись типа A), указывающую, что **ваш домен** должен указывать на публичный **IPадрес вашего сервера**.

View File

@@ -18,6 +18,6 @@
Например, мы, команда, стоящая за FastAPI, создали <a href="https://fastapicloud.com" class="external-link" target="_blank">**FastAPI Cloud**</a>, чтобы сделать развёртывание приложений FastAPI в облаке как можно более простым и прямолинейным, с тем же удобством для разработчика, что и при работе с FastAPI.
В этом блоке я покажу вам некоторые из основных концепций, которые вы, вероятно, должны иметь в виду при развертывании приложения **FastAPI** (хотя большинство из них применимо к любому другому типу веб-приложений).
Я покажу вам некоторые из основных концепций, которые вы, вероятно, должны иметь в виду при развертывании приложения **FastAPI** (хотя большинство из них применимо к любому другому типу веб-приложений).
В последующих разделах вы узнаете больше деталей и методов, необходимых для этого. ✨

View File

@@ -1,12 +1,12 @@
# О версиях FastAPI { #about-fastapi-versions }
**FastAPI** уже используется в продакшене во многих приложениях и системах. Покрытие тестами поддерживается на уровне 100%. Но его разработка всё ещё движется быстрыми темпами.
**FastAPI** уже используется в продакшн во многих приложениях и системах. Покрытие тестами поддерживается на уровне 100%. Но его разработка всё ещё движется быстрыми темпами.
Часто добавляются новые функции, регулярно исправляются баги, код продолжает постоянно совершенствоваться.
По указанным причинам текущие версии до сих пор `0.x.x`. Это говорит о том, что каждая версия может содержать обратно несовместимые изменения, следуя <a href="https://semver.org/" class="external-link" target="_blank">Семантическому версионированию</a>.
Уже сейчас вы можете создавать приложения в продакшене, используя **FastAPI** (и скорее всего так и делаете), главное убедиться в том, что вы используете версию, которая корректно работает с вашим кодом.
Уже сейчас вы можете создавать приложения в продакшн, используя **FastAPI** (и скорее всего так и делаете), главное убедиться в том, что вы используете версию, которая корректно работает с вашим кодом.
## Закрепите вашу версию `fastapi` { #pin-your-fastapi-version }

View File

@@ -161,7 +161,7 @@ Hello World from Python
Эти переменные окружения могут работать только с **текстовыми строками**, поскольку они являются внешними по отношению к Python и должны быть совместимы с другими программами и остальной системой (и даже с различными операционными системами, такими как Linux, Windows, macOS).
Это означает, что **любое значение**, считанное в Python из переменной окружения, **будет `str`**, и любое преобразование к другому типу или любая проверка должны быть выполнены в коде.
Это означает, что **любое значение**, считанное в Python из переменной окружения, **будет `str`**, и любое преобразование к другому типу или любая валидация должны быть выполнены в коде.
Подробнее об использовании переменных окружения для работы с **настройками приложения** вы узнаете в [Расширенное руководство пользователя - Настройки и переменные среды](./advanced/settings.md){.internal-link target=_blank}.

View File

@@ -52,7 +52,7 @@ FastAPI CLI берет путь к вашей Python-программе (нап
Для работы в режиме продакшн вместо `fastapi dev` нужно использовать `fastapi run`. 🚀
Внутри **FastAPI CLI** используется <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a>, высокопроизводительный, готовый к работе в продакшне ASGI-сервер. 😎
Внутри **FastAPI CLI** используется <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a>, высокопроизводительный, готовый к работе в продакшн ASGI-сервер. 😎
## `fastapi dev` { #fastapi-dev }

View File

@@ -6,7 +6,7 @@
### Основано на открытых стандартах { #based-on-open-standards }
* <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a> для создания API, включая объявления <abbr title="также известные как HTTP-методы, например: POST, GET, PUT, DELETE">операций</abbr> <abbr title="также известен как: эндпоинты, маршруты)">пути</abbr>, параметров, тел запросов, безопасности и т. д.
* <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a> для создания API, включая объявления <dfn title="также известны как HTTP-методы, например: POST, GET, PUT, DELETE">операций</dfn> <dfn title="также известен как: эндпоинты, маршруты">пути</dfn>, параметров, тел запросов, безопасности и т.д.
* Автоматическая документация моделей данных с помощью <a href="https://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a> (так как сама спецификация OpenAPI основана на JSON Schema).
* Разработан вокруг этих стандартов, после тщательного их изучения. Это не дополнительная надстройка поверх.
* Это также позволяет использовать автоматическую **генерацию клиентского кода** на многих языках.
@@ -107,7 +107,7 @@ FastAPI имеет продуманные значения **по умолчан
* Объекты JSON (`dict`).
* Массив JSON (`list`) с определёнными типами элементов.
* Строковые (`str`) поля с ограничением минимальной и максимальной длины.
* Числа (`int`, `float`) с минимальными и максимальными значениями и т. п.
* Числа (`int`, `float`) с минимальными и максимальными значениями и т.п.
* Проверка для более экзотических типов, таких как:
* URL.
@@ -126,24 +126,24 @@ FastAPI имеет продуманные значения **по умолчан
* HTTP Basic.
* **OAuth2** (также с **токенами JWT**). Ознакомьтесь с руководством [OAuth2 с JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}.
* Ключи API в:
* Заголовках.
* HTTP-заголовках.
* Параметрах запросов.
* Cookies и т.п.
Вдобавок все функции безопасности от Starlette (включая **сессионные cookies**).
Все инструменты и компоненты спроектированы для многократного использования и легко интегрируются с вашими системами, хранилищами данных, реляционными и NoSQL базами данных и т. д.
Все инструменты и компоненты спроектированы для многократного использования и легко интегрируются с вашими системами, хранилищами данных, реляционными и NoSQL базами данных и т.д.
### Внедрение зависимостей { #dependency-injection }
FastAPI включает в себя чрезвычайно простую в использовании, но чрезвычайно мощную систему <abbr title='известную как: "components", "resources", "services", "providers"'><strong>Внедрения зависимостей</strong></abbr>.
FastAPI включает в себя чрезвычайно простую в использовании, но чрезвычайно мощную систему <dfn title='также известна как: "компоненты", "ресурсы", "сервисы", "провайдеры"'><strong>Внедрения зависимостей</strong></dfn>.
* Даже зависимости могут иметь зависимости, создавая иерархию или **«граф» зависимостей**.
* Всё **автоматически обрабатывается** фреймворком.
* Все зависимости могут запрашивать данные из запросов и **дополнять операции пути** ограничениями и автоматической документацией.
* **Автоматическая проверка** даже для параметров *операций пути*, определённых в зависимостях.
* Поддержка сложных систем аутентификации пользователей, **соединений с базами данных** и т. д.
* **Никаких компромиссов** с базами данных, интерфейсами и т. д. Но при этом — лёгкая интеграция со всеми ними.
* Поддержка сложных систем аутентификации пользователей, **соединений с базами данных** и т.д.
* **Никаких компромиссов** с базами данных, интерфейсами и т.д. Но при этом — лёгкая интеграция со всеми ними.
### Нет ограничений на "Плагины" { #unlimited-plug-ins }
@@ -153,8 +153,8 @@ FastAPI включает в себя чрезвычайно простую в и
### Проверен { #tested }
* 100% <abbr title="Количество автоматически проверяемого кода">покрытие тестами</abbr>.
* 100% <abbr title="Аннотации типов Python, благодаря которым ваш редактор и внешние инструменты могут обеспечить вам лучшую поддержку">аннотирование типов</abbr> в кодовой базе.
* 100% <dfn title="Количество автоматически проверяемого кода">покрытие тестами</dfn>.
* 100% <dfn title="Аннотации типов Python, благодаря которым ваш редактор кода и внешние инструменты могут обеспечить вам лучшую поддержку">аннотирование типов</dfn> в кодовой базе.
* Используется в продакшн‑приложениях.
## Возможности Starlette { #starlette-features }
@@ -179,7 +179,7 @@ FastAPI включает в себя чрезвычайно простую в и
**FastAPI** полностью совместим с (и основан на) <a href="https://docs.pydantic.dev/" class="external-link" target="_blank"><strong>Pydantic</strong></a>. Поэтому любой дополнительный код Pydantic, который у вас есть, также будет работать.
Включая внешние библиотеки, также основанные на Pydantic, такие как <abbr title="Object-Relational Mapper">ORM</abbr>’ы, <abbr title="Object-Document Mapper">ODM</abbr>’ы для баз данных.
Включая внешние библиотеки, также основанные на Pydantic, такие как <abbr title="Object-Relational Mapper - объектно-реляционный маппер">ORM</abbr>’ы, <abbr title="Object-Document Mapper - объектно-документный маппер">ODM</abbr>’ы для баз данных.
Это также означает, что во многих случаях вы можете передавать тот же объект, который получили из запроса, **непосредственно в базу данных**, так как всё проверяется автоматически.
@@ -190,10 +190,10 @@ FastAPI включает в себя чрезвычайно простую в и
* **Никакой нервотрёпки**:
* Не нужно изучать новые схемы в микроязыках.
* Если вы знаете типы в Python, вы знаете, как использовать Pydantic.
* Прекрасно сочетается с вашим **<abbr title="Integrated Development Environment - Интегрированная среда разработки: попросту «редактора кода»">IDE</abbr>/<abbr title="Программа, проверяющая ошибки в коде">linter</abbr>/мозгом**:
* Прекрасно сочетается с вашим **<abbr title="Integrated Development Environment - Интегрированная среда разработки: похоже на редактор кода">IDE</abbr>/<dfn title="Программа, которая проверяет код на ошибки">линтер</dfn>/мозгом**:
* Потому что структуры данных pydantic — это всего лишь экземпляры классов, определённых вами; автозавершение, проверка кода, mypy и ваша интуиция — всё будет работать с вашими валидированными данными.
* Валидация **сложных структур**:
* Использование иерархических моделей Pydantic; `List`, `Dict` и т. п. из модуля `typing` (входит в стандартную библиотеку Python).
* Использование иерархических моделей Pydantic; `List`, `Dict` и т.п. из модуля `typing` (входит в стандартную библиотеку Python).
* Валидаторы позволяют чётко и легко определять, проверять и документировать сложные схемы данных в виде JSON Schema.
* У вас могут быть глубоко **вложенные объекты JSON**, и все они будут проверены и аннотированы.
* **Расширяемость**:

View File

@@ -30,7 +30,7 @@
## Исследования { #investigation }
Благодаря опыту использования существующих альтернатив, мы с коллегами изучили их основные идеи и скомбинировали собранные знания наилучшим образом.
Используя все существовавшие ранее альтернативы, я получил возможность у каждой из них чему-то научиться, позаимствовать идеи и объединить их наилучшим образом для себя и для команд разработчиков, с которыми я работал.
Например, стало ясно, что необходимо брать за основу стандартные аннотации типов Python.
@@ -44,13 +44,13 @@
Я проверил несколько идей на самых популярных редакторах кода: PyCharm, VS Code, редакторы на базе Jedi.
Данные по редакторам я взял из <a href="https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools" class="external-link" target="_blank">опроса Python-разработчиков</a>, который охватывает около 80% пользователей.
Согласно последнему <a href="https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools" class="external-link" target="_blank">опросу Python-разработчиков</a>, который охватывает около 80% пользователей.
Это означает, что **FastAPI** был специально проверен на редакторах, используемых 80% Python-разработчиками. И поскольку большинство других редакторов, как правило, работают аналогичным образом, все его преимущества должны работать практически для всех редакторов.
Таким образом, я смог найти наилучшие способы сократить дублирование кода, обеспечить повсеместное автозавершение, проверку типов и ошибок и т.д.
И все это, чтобы все пользователи могли получать наилучший опыт разработки.
И все это, чтобы все разработчики могли получать наилучший опыт разработки.
## Зависимости { #requirements }
@@ -58,7 +58,7 @@
По моим предложениям был изменён код этого фреймворка, чтобы сделать его полностью совместимым с JSON Schema, поддержать различные способы определения ограничений и улучшить поддержку в редакторах кода (проверки типов, автозавершение) на основе тестов в нескольких редакторах.
В то же время, я принимал участие в разработке <a href="https://www.starlette.dev/" class="external-link" target="_blank">**Starlette**</a>, ещё один из основных компонентов FastAPI.
Во время разработки я также внес вклад в <a href="https://www.starlette.dev/" class="external-link" target="_blank">**Starlette**</a>, другую ключевую зависимость.
## Разработка { #development }

View File

@@ -8,7 +8,7 @@
Например, вы можете создать подкласс `HTTPBearer`, который будет возвращать ошибку `403 Forbidden` вместо стандартной `401 Unauthorized`:
{* ../../docs_src/authentication_error_status_code/tutorial001_an_py39.py hl[9:13] *}
{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}
/// tip | Совет

View File

@@ -4,9 +4,9 @@
## О безопасности, API и документации { #about-security-apis-and-docs }
Скрытие пользовательских интерфейсов документации в продакшн *не должно* быть способом защиты вашего API.
Скрытие пользовательских интерфейсов документации в продакшн не должно быть способом защиты вашего API.
Это не добавляет дополнительной безопасности вашему API, *операции пути* (обработчики пути) всё равно будут доступны по своим путям.
Это не добавляет дополнительной безопасности вашему API, операции пути (обработчики пути) всё равно будут доступны по своим путям.
Если в вашем коде есть уязвимость, она всё равно останется.
@@ -29,7 +29,7 @@
Например:
{* ../../docs_src/conditional_openapi/tutorial001_py39.py hl[6,11] *}
{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}
Здесь мы объявляем настройку `openapi_url` с тем же значением по умолчанию — `"/openapi.json"`.

View File

@@ -18,7 +18,7 @@ FastAPI преобразует эти настройки в **JSON**, чтобы
Но вы можете отключить её, установив `syntaxHighlight` в `False`:
{* ../../docs_src/configure_swagger_ui/tutorial001_py39.py hl[3] *}
{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}
…и после этого Swagger UI больше не будет показывать подсветку синтаксиса:
@@ -28,7 +28,7 @@ FastAPI преобразует эти настройки в **JSON**, чтобы
Аналогично вы можете задать тему подсветки синтаксиса с ключом "syntaxHighlight.theme" (обратите внимание, что посередине стоит точка):
{* ../../docs_src/configure_swagger_ui/tutorial002_py39.py hl[3] *}
{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}
Эта настройка изменит цветовую тему подсветки синтаксиса:
@@ -46,7 +46,7 @@ FastAPI включает некоторые параметры конфигур
Например, чтобы отключить `deepLinking`, можно передать такие настройки в `swagger_ui_parameters`:
{* ../../docs_src/configure_swagger_ui/tutorial003_py39.py hl[3] *}
{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}
## Другие параметры Swagger UI { #other-swagger-ui-parameters }

View File

@@ -18,7 +18,7 @@
Чтобы отключить её, установите их URL в значение `None` при создании вашего приложения `FastAPI`:
{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[8] *}
{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}
### Подключить пользовательскую документацию { #include-the-custom-docs }
@@ -34,7 +34,7 @@
Аналогично и для ReDoc...
{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[2:6,11:19,22:24,27:33] *}
{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}
/// tip | Совет
@@ -50,7 +50,7 @@ Swagger UI сделает это за вас «за кулисами», но д
Чтобы убедиться, что всё работает, создайте *операцию пути*:
{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[36:38] *}
{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}
### Тестирование { #test-it }
@@ -118,7 +118,7 @@ Swagger UI сделает это за вас «за кулисами», но д
* Импортируйте `StaticFiles`.
* Смонтируйте экземпляр `StaticFiles()` в определённый путь.
{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[7,11] *}
{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}
### Протестируйте статические файлы { #test-the-static-files }
@@ -144,7 +144,7 @@ Swagger UI сделает это за вас «за кулисами», но д
Чтобы отключить её, установите их URL в значение `None` при создании вашего приложения `FastAPI`:
{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[9] *}
{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}
### Подключить пользовательскую документацию со статическими файлами { #include-the-custom-docs-for-static-files }
@@ -160,7 +160,7 @@ Swagger UI сделает это за вас «за кулисами», но д
Аналогично и для ReDoc...
{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[2:6,14:22,25:27,30:36] *}
{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}
/// tip | Совет
@@ -176,7 +176,7 @@ Swagger UI сделает это за вас «за кулисами», но д
Чтобы убедиться, что всё работает, создайте *операцию пути*:
{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[39:41] *}
{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}
### Тестирование UI со статическими файлами { #test-static-files-ui }

View File

@@ -24,7 +24,7 @@
* `version`: Версия вашего API, например `2.5.0`.
* `openapi_version`: Версия используемой спецификации OpenAPI. По умолчанию — последняя: `3.1.0`.
* `summary`: Краткое описание API.
* `description`: Описание вашего API; может включать Markdown и будет отображается в документации.
* `description`: Описание вашего API; может включать Markdown и будет отображаться в документации.
* `routes`: Список маршрутов — это каждая зарегистрированная *операция пути*. Берутся из `app.routes`.
/// info | Информация
@@ -43,19 +43,19 @@
Сначала напишите приложение **FastAPI** как обычно:
{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[1,4,7:9] *}
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}
### Сгенерируйте схему OpenAPI { #generate-the-openapi-schema }
Затем используйте ту же вспомогательную функцию для генерации схемы OpenAPI внутри функции `custom_openapi()`:
{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[2,15:21] *}
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}
### Измените схему OpenAPI { #modify-the-openapi-schema }
Теперь можно добавить расширение ReDoc, добавив кастомный `x-logo` в «объект» `info` в схеме OpenAPI:
{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[22:24] *}
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}
### Кэшируйте схему OpenAPI { #cache-the-openapi-schema }
@@ -65,13 +65,13 @@
Она будет создана один раз, а затем тот же кэшированный вариант будет использоваться для последующих запросов.
{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[13:14,25:26] *}
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}
### Переопределите метод { #override-the-method }
Теперь вы можете заменить метод `.openapi()` на вашу новую функцию.
{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[29] *}
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}
### Проверьте { #check-it }

View File

@@ -35,7 +35,7 @@
Вот небольшой пример того, как можно интегрировать Strawberry с FastAPI:
{* ../../docs_src/graphql_/tutorial001_py39.py hl[3,22,25] *}
{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}
Подробнее о Strawberry можно узнать в <a href="https://strawberry.rocks/" class="external-link" target="_blank">документации Strawberry</a>.

View File

@@ -1,13 +1,13 @@
# Как сделать — Рецепты { #how-to-recipes }
Здесь вы найдете разные рецепты и руководства «как сделать» по различным темам.
Здесь вы найдете разные рецепты и руководства «как сделать» по **различным темам**.
Большинство из этих идей более-менее независимы, и в большинстве случаев вам стоит изучать их только если они напрямую относятся к вашему проекту.
Большинство из этих идей более-менее **независимы**, и в большинстве случаев вам стоит изучать их только если они напрямую относятся к **вашему проекту**.
Если что-то кажется интересным и полезным для вашего проекта, смело изучайте; в противном случае, вероятно, можно просто пропустить.
/// tip | Совет
Если вы хотите изучить FastAPI структурированно (рекомендуется), вместо этого читайте [Учебник — Руководство пользователя](../tutorial/index.md){.internal-link target=_blank} по главам.
Если вы хотите **изучить FastAPI** структурированно (рекомендуется), вместо этого читайте [Учебник — Руководство пользователя](../tutorial/index.md){.internal-link target=_blank} по главам.
///

View File

@@ -40,7 +40,7 @@ FastAPI — это современный, быстрый (высокопрои
* **Скорость**: Очень высокая производительность, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic). [Один из самых быстрых доступных фреймворков Python](#performance).
* **Быстрота разработки**: Увеличьте скорость разработки фич примерно на 200300%. *
* **Меньше ошибок**: Сократите примерно на 40% количество ошибок, вызванных человеком (разработчиком). *
* **Интуитивность**: Отличная поддержка редактора кода. <abbr title="также известное как: автодополнение, автозавершение, IntelliSense">Автозавершение</abbr> везде. Меньше времени на отладку.
* **Интуитивность**: Отличная поддержка редактора кода. <dfn title="также известное как: автодополнение, автозавершение, IntelliSense">Автозавершение</dfn> везде. Меньше времени на отладку.
* **Простота**: Разработан так, чтобы его было легко использовать и осваивать. Меньше времени на чтение документации.
* **Краткость**: Минимизируйте дублирование кода. Несколько возможностей из каждого объявления параметров. Меньше ошибок.
* **Надежность**: Получите код, готовый к продакшн. С автоматической интерактивной документацией.
@@ -127,7 +127,7 @@ FastAPI — это современный, быстрый (высокопрои
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
Если вы создаёте приложение <abbr title="Command Line Interface Интерфейс командной строки">CLI</abbr> для использования в терминале вместо веб-API, посмотрите <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
Если вы создаёте приложение <abbr title="Command Line Interface - Интерфейс командной строки">CLI</abbr> для использования в терминале вместо веб-API, посмотрите <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
**Typer** — младший брат FastAPI. И он задуман как **FastAPI для CLI**. ⌨️ 🚀
@@ -368,7 +368,7 @@ item: Item
* Валидацию данных:
* Автоматические и понятные ошибки, когда данные некорректны.
* Валидацию даже для глубоко вложенных объектов JSON.
* <abbr title="также известное как: сериализация, парсинг, маршалинг">Преобразование</abbr> входных данных: из сети в данные и типы Python. Чтение из:
* <dfn title="также известное как: сериализация, парсинг, маршалинг">Преобразование</dfn> входных данных: из сети в данные и типы Python. Чтение из:
* JSON.
* Параметров пути.
* Параметров запроса.
@@ -376,7 +376,7 @@ item: Item
* HTTP-заголовков.
* Форм.
* Файлов.
* <abbr title="также известное как: сериализация, парсинг, маршалинг">Преобразование</abbr> выходных данных: из данных и типов Python в данные сети (например, JSON):
* <dfn title="также известное как: сериализация, парсинг, маршалинг">Преобразование</dfn> выходных данных: из данных и типов Python в данные сети (например, JSON):
* Преобразование типов Python (`str`, `int`, `float`, `bool`, `list` и т.д.).
* Объекты `datetime`.
* Объекты `UUID`.
@@ -439,7 +439,7 @@ item: Item
* Объявление **параметров** из других источников: **HTTP-заголовки**, **cookies**, **поля формы** и **файлы**.
* Как задать **ограничения валидации** вроде `maximum_length` или `regex`.
* Очень мощную и простую в использовании систему **<abbr title="также известна как: компоненты, ресурсы, провайдеры, сервисы, инъекции">внедрения зависимостей</abbr>**.
* Очень мощную и простую в использовании систему **<dfn title="также известна как: компоненты, ресурсы, провайдеры, сервисы, инъекции">внедрения зависимостей</dfn>**.
* Безопасность и аутентификацию, включая поддержку **OAuth2** с **JWT токенами** и **HTTP Basic** аутентификацию.
* Более продвинутые (но столь же простые) приёмы объявления **глубоко вложенных JSON-моделей** (спасибо Pydantic).
* Интеграцию **GraphQL** с <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> и другими библиотеками.
@@ -524,7 +524,7 @@ FastAPI зависит от Pydantic и Starlette.
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> — обязателен, если вы хотите использовать `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> — обязателен, если вы хотите использовать конфигурацию шаблонов по умолчанию.
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - обязателен, если вы хотите поддерживать <abbr title="преобразование строки, полученной из HTTP-запроса, в данные Python">«парсинг»</abbr> форм через `request.form()`.
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - обязателен, если вы хотите поддерживать <dfn title="преобразование строки, полученной из HTTP-запроса, в данные Python">«парсинг»</dfn> форм через `request.form()`.
Используется FastAPI:

View File

@@ -18,7 +18,7 @@
- 🤖 Автоматически сгенерированный фронтенд‑клиент.
- 🧪 [Playwright](https://playwright.dev) для EndtoEnd тестирования.
- 🦇 Поддержка тёмной темы.
- 🐋 [Docker Compose](https://www.docker.com) для разработки и продакшна.
- 🐋 [Docker Compose](https://www.docker.com) для разработки и продакшн.
- 🔒 Безопасное хэширование паролей по умолчанию.
- 🔑 Аутентификация по JWTтокенам.
- 📫 Восстановление пароля по электронной почте.

View File

@@ -2,7 +2,7 @@
Python поддерживает необязательные «подсказки типов» (их также называют «аннотациями типов»).
Эти **«подсказки типов»** или аннотации — это специальный синтаксис, позволяющий объявлять <abbr title="например: str, int, float, bool">тип</abbr> переменной.
Эти **«подсказки типов»** или аннотации — это специальный синтаксис, позволяющий объявлять <dfn title="например: str, int, float, bool">тип</dfn> переменной.
Объявляя типы для ваших переменных, редакторы кода и инструменты смогут лучше вас поддерживать.
@@ -22,7 +22,7 @@ Python поддерживает необязательные «подсказк
Давайте начнем с простого примера:
{* ../../docs_src/python_types/tutorial001_py39.py *}
{* ../../docs_src/python_types/tutorial001_py310.py *}
Вызов этой программы выводит:
@@ -34,9 +34,9 @@ John Doe
* Принимает `first_name` и `last_name`.
* Преобразует первую букву каждого значения в верхний регистр с помощью `title()`.
* <abbr title="Объединяет в одно целое. Содержимое одного — сразу после другого.">Соединяет</abbr> их пробелом посередине.
* <dfn title="Соединяет их в одно. Содержимое одного — сразу после другого.">Соединяет</dfn> их пробелом посередине.
{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *}
{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}
### Отредактируем пример { #edit-it }
@@ -78,7 +78,7 @@ John Doe
Это и есть «подсказки типов»:
{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *}
{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}
Это не то же самое, что объявление значений по умолчанию, как, например:
@@ -106,7 +106,7 @@ John Doe
Посмотрите на эту функцию — у неё уже есть подсказки типов:
{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *}
{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}
Так как редактор кода знает типы переменных, вы получаете не только автозавершение, но и проверки ошибок:
@@ -114,7 +114,7 @@ John Doe
Теперь вы знаете, что нужно исправить — преобразовать `age` в строку с помощью `str(age)`:
{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *}
{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}
## Объявление типов { #declaring-types }
@@ -133,29 +133,32 @@ John Doe
* `bool`
* `bytes`
{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *}
{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}
### Generic-типы с параметрами типов { #generic-types-with-type-parameters }
### Модуль `typing` { #typing-module }
Есть структуры данных, которые могут содержать другие значения, например, `dict`, `list`, `set` и `tuple`. И внутренние значения тоже могут иметь свой тип.
Для некоторых дополнительных сценариев может понадобиться импортировать что-то из стандартного модуля `typing`. Например, когда вы хотите объявить, что что-то имеет «любой тип», можно использовать `Any` из `typing`:
Такие типы, которые содержат внутренние типы, называют «**generic**»-типами. И их можно объявлять, в том числе с указанием внутренних типов.
```python
from typing import Any
Чтобы объявлять эти типы и их внутренние типы, вы можете использовать стандартный модуль Python `typing`. Он существует специально для поддержки подсказок типов.
#### Новые версии Python { #newer-versions-of-python }
def some_function(data: Any):
print(data)
```
Синтаксис с использованием `typing` **совместим** со всеми версиями, от Python 3.6 до самых новых, включая Python 3.9, Python 3.10 и т.д.
### Generic-типы { #generic-types }
По мере развития Python **новые версии** получают улучшенную поддержку этих аннотаций типов, и во многих случаях вам даже не нужно импортировать и использовать модуль `typing`, чтобы объявлять аннотации типов.
Некоторые типы могут принимать «параметры типов» в квадратных скобках, чтобы определить их внутренние типы. Например, «список строк» объявляется как `list[str]`.
Если вы можете выбрать более свежую версию Python для проекта, вы получите дополнительную простоту.
Такие типы, которые принимают параметры типов, называются **Generic-типами** или **Generics**.
Во всей документации есть примеры, совместимые с каждой версией Python (когда есть различия).
Вы можете использовать те же встроенные типы как generics (с квадратными скобками и типами внутри):
Например, «**Python 3.6+**» означает совместимость с Python 3.6 и выше (включая 3.7, 3.8, 3.9, 3.10 и т.д.). А «**Python 3.9+**» — совместимость с Python 3.9 и выше (включая 3.10 и т.п.).
Если вы можете использовать **последние версии Python**, используйте примеры для самой новой версии — у них будет **самый лучший и простой синтаксис**, например, «**Python 3.10+**».
* `list`
* `tuple`
* `set`
* `dict`
#### List { #list }
@@ -167,7 +170,7 @@ John Doe
Так как список — это тип, содержащий внутренние типы, укажите их в квадратных скобках:
{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *}
{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}
/// info | Информация
@@ -193,7 +196,7 @@ John Doe
Аналогично вы бы объявили `tuple` и `set`:
{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *}
{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}
Это означает:
@@ -208,7 +211,7 @@ John Doe
Второй параметр типа — для значений `dict`:
{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *}
{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}
Это означает:
@@ -220,44 +223,20 @@ John Doe
Вы можете объявить, что переменная может быть **одним из нескольких типов**, например, `int` или `str`.
В Python 3.6 и выше (включая Python 3.10) вы можете использовать тип `Union` из `typing` и перечислить в квадратных скобках все допустимые типы.
Чтобы это определить, используйте <dfn title='также называется «побитовый оператор OR», но это значение здесь нерелевантно'>вертикальную черту (`|`)</dfn> для разделения обоих типов.
В Python 3.10 также появился **новый синтаксис**, где допустимые типы можно указать через <abbr title='также называется «побитовый оператор OR», но это значение здесь нерелевантно'>вертикальную черту (`|`)</abbr>.
//// tab | Python 3.10+
Это называется «объединение» (union), потому что переменная может быть чем угодно из объединения этих двух множеств типов.
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial008b_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial008b_py39.py!}
```
////
В обоих случаях это означает, что `item` может быть `int` или `str`.
Это означает, что `item` может быть `int` или `str`.
#### Возможно `None` { #possibly-none }
Вы можете объявить, что значение может иметь определённый тип, например `str`, но также может быть и `None`.
В Python 3.6 и выше (включая Python 3.10) это можно объявить, импортировав и используя `Optional` из модуля `typing`.
```Python hl_lines="1 4"
{!../../docs_src/python_types/tutorial009_py39.py!}
```
Использование `Optional[str]` вместо просто `str` позволит редактору кода помочь вам обнаружить ошибки, когда вы предполагаете, что значение всегда `str`, хотя на самом деле оно может быть и `None`.
`Optional[Something]` — это на самом деле сокращение для `Union[Something, None]`, они эквивалентны.
Это также означает, что в Python 3.10 вы можете использовать `Something | None`:
//// tab | Python 3.10+
```Python hl_lines="1"
@@ -266,96 +245,7 @@ John Doe
////
//// tab | Python 3.9+
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial009_py39.py!}
```
////
//// tab | Python 3.9+ альтернативный вариант
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial009b_py39.py!}
```
////
#### Использовать `Union` или `Optional` { #using-union-or-optional }
Если вы используете версию Python ниже 3.10, вот совет с моей весьма **субъективной** точки зрения:
* 🚨 Избегайте использования `Optional[SomeType]`
* Вместо этого ✨ **используйте `Union[SomeType, None]`** ✨.
Оба варианта эквивалентны и внутри одинаковы, но я бы рекомендовал `Union` вместо `Optional`, потому что слово «**optional**» («необязательный») может навести на мысль, что значение необязательное, хотя на самом деле оно означает «может быть `None`», даже если параметр не является необязательным и всё ещё обязателен.
Мне кажется, `Union[SomeType, None]` более явно выражает смысл.
Речь только о словах и названиях. Но эти слова могут влиять на то, как вы и ваши коллеги думаете о коде.
В качестве примера возьмём эту функцию:
{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *}
Параметр `name` определён как `Optional[str]`, но он **не необязательный** — вы не можете вызвать функцию без этого параметра:
```Python
say_hi() # О нет, это вызывает ошибку! 😱
```
Параметр `name` всё ещё **обязателен** (не *optional*), потому что у него нет значения по умолчанию. При этом `name` принимает `None` как значение:
```Python
say_hi(name=None) # Это работает, None допустим 🎉
```
Хорошая новость: как только вы перейдёте на Python 3.10, об этом можно не переживать — вы сможете просто использовать `|` для объединения типов:
{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *}
И тогда вам не придётся задумываться о названиях вроде `Optional` и `Union`. 😎
#### Generic-типы { #generic-types }
Типы, которые принимают параметры типов в квадратных скобках, называются **Generic-типами** или **Generics**, например:
//// tab | Python 3.10+
Вы можете использовать те же встроенные типы как generics (с квадратными скобками и типами внутри):
* `list`
* `tuple`
* `set`
* `dict`
И, как и в предыдущих версиях Python, из модуля `typing`:
* `Union`
* `Optional`
* ...и другие.
В Python 3.10, как альтернативу generics `Union` и `Optional`, можно использовать <abbr title='также называется «побитовый оператор OR», но это значение здесь нерелевантно'>вертикальную черту (`|`)</abbr> для объявления объединений типов — это гораздо лучше и проще.
////
//// tab | Python 3.9+
Вы можете использовать те же встроенные типы как generics (с квадратными скобками и типами внутри):
* `list`
* `tuple`
* `set`
* `dict`
И generics из модуля `typing`:
* `Union`
* `Optional`
* ...и другие.
////
Использование `str | None` вместо просто `str` позволит редактору кода помочь вам обнаружить ошибки, когда вы предполагаете, что значение всегда `str`, хотя на самом деле оно может быть и `None`.
### Классы как типы { #classes-as-types }
@@ -363,11 +253,11 @@ say_hi(name=None) # Это работает, None допустим 🎉
Допустим, у вас есть класс `Person` с именем:
{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *}
{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}
Тогда вы можете объявить переменную типа `Person`:
{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *}
{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}
И снова вы получите полную поддержку редактора кода:
@@ -401,21 +291,15 @@ say_hi(name=None) # Это работает, None допустим 🎉
**FastAPI** целиком основан на Pydantic.
Вы увидите намного больше всего этого на практике в [Руководстве пользователя](tutorial/index.md){.internal-link target=_blank}.
/// tip | Совет
У Pydantic есть особое поведение, когда вы используете `Optional` или `Union[Something, None]` без значения по умолчанию. Подробнее читайте в документации Pydantic: <a href="https://docs.pydantic.dev/2.3/usage/models/#required-fields" class="external-link" target="_blank">Required Optional fields</a>.
///
Вы увидите намного больше всего этого на практике в [Учебник - Руководство пользователя](tutorial/index.md){.internal-link target=_blank}.
## Подсказки типов с аннотациями метаданных { #type-hints-with-metadata-annotations }
В Python также есть возможность добавлять **дополнительные <abbr title="Данные о данных, в данном случае — информация о типе, например описание.">метаданные</abbr>** к подсказкам типов с помощью `Annotated`.
В Python также есть возможность добавлять **дополнительные <dfn title="Данные о данных, в данном случае — информация о типе, например описание.">метаданные</dfn>** к подсказкам типов с помощью `Annotated`.
Начиная с Python 3.9, `Annotated` входит в стандартную библиотеку, поэтому вы можете импортировать его из `typing`.
Вы можете импортировать `Annotated` из `typing`.
{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *}
{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}
Сам Python ничего не делает с `Annotated`. А для редакторов кода и других инструментов тип по-прежнему `str`.
@@ -453,7 +337,7 @@ say_hi(name=None) # Это работает, None допустим 🎉
* **Документирования** API с использованием OpenAPI:
* что затем используется пользовательскими интерфейсами автоматической интерактивной документации.
Всё это может звучать абстрактно. Не волнуйтесь. Вы увидите всё это в действии в [Руководстве пользователя](tutorial/index.md){.internal-link target=_blank}.
Всё это может звучать абстрактно. Не волнуйтесь. Вы увидите всё это в действии в [Учебник - Руководство пользователя](tutorial/index.md){.internal-link target=_blank}.
Важно то, что, используя стандартные типы Python в одном месте (вместо добавления дополнительных классов, декораторов и т.д.), **FastAPI** сделает за вас большую часть работы.

View File

@@ -15,7 +15,7 @@
Сначала импортируйте `BackgroundTasks` и объявите параметр в вашей функции‑обработчике пути с типом `BackgroundTasks`:
{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *}
{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}
**FastAPI** создаст объект типа `BackgroundTasks` для вас и передаст его через этот параметр.
@@ -31,13 +31,13 @@
Так как операция записи не использует `async` и `await`, мы определим функцию как обычную `def`:
{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *}
{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}
## Добавление фоновой задачи { #add-the-background-task }
Внутри вашей функции‑обработчика пути передайте функцию задачи объекту фоновых задач методом `.add_task()`:
{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *}
{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}
`.add_task()` принимает следующие аргументы:
@@ -47,7 +47,7 @@
## Встраивание зависимостей { #dependency-injection }
Использование `BackgroundTasks` также работает с системой встраивания зависимостей, вы можете объявить параметр типа `BackgroundTasks` на нескольких уровнях: в функции‑обработчике пути, в зависимости (dependable), в подзависимости и т. д.
Использование `BackgroundTasks` также работает с системой встраивания зависимостей, вы можете объявить параметр типа `BackgroundTasks` на нескольких уровнях: в функции‑обработчике пути, в зависимости (dependable), в подзависимости и т.д.
**FastAPI** знает, что делать в каждом случае и как переиспользовать один и тот же объект, так чтобы все фоновые задачи были объединены и затем выполнены в фоне:
@@ -73,7 +73,7 @@
## Предостережение { #caveat }
Если вам нужно выполнять тяжелые вычисления в фоне, и при этом они не обязательно должны запускаться тем же процессом (например, вам не нужно делиться памятью, переменными и т. п.), вам могут подойти более мощные инструменты, такие как <a href="https://docs.celeryq.dev" class="external-link" target="_blank">Celery</a>.
Если вам нужно выполнять тяжелые вычисления в фоне, и при этом они не обязательно должны запускаться тем же процессом (например, вам не нужно делиться памятью, переменными и т.п.), вам могут подойти более мощные инструменты, такие как <a href="https://docs.celeryq.dev" class="external-link" target="_blank">Celery</a>.
Они обычно требуют более сложной конфигурации, менеджера очереди сообщений/заданий (например, RabbitMQ или Redis), но позволяют запускать фоновые задачи в нескольких процессах и, что особенно важно, на нескольких серверах.

View File

@@ -85,7 +85,7 @@ from app.routers import items
Точно так же, как и в случае с классом `FastAPI`, вам нужно импортировать и создать его «экземпляр»:
{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[1,3] title["app/routers/users.py"] *}
{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title["app/routers/users.py"] *}
### *Операции пути* с `APIRouter` { #path-operations-with-apirouter }
@@ -93,7 +93,7 @@ from app.routers import items
Используйте его так же, как вы использовали бы класс `FastAPI`:
{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
Вы можете думать об `APIRouter` как об «мини-классе `FastAPI`».
@@ -117,7 +117,7 @@ from app.routers import items
Теперь мы воспользуемся простой зависимостью, чтобы прочитать кастомный HTTP-заголовок `X-Token`:
{* ../../docs_src/bigger_applications/app_an_py39/dependencies.py hl[3,6:8] title["app/dependencies.py"] *}
{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title["app/dependencies.py"] *}
/// tip | Подсказка
@@ -149,7 +149,7 @@ from app.routers import items
Таким образом, вместо того чтобы добавлять всё это в каждую *операцию пути*, мы можем добавить это в `APIRouter`.
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
Так как путь каждой *операции пути* должен начинаться с `/`, как здесь:
@@ -208,7 +208,7 @@ async def read_item(item_id: str):
Поэтому мы используем относительный импорт с `..` для зависимостей:
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[3] title["app/routers/items.py"] *}
{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title["app/routers/items.py"] *}
#### Как работает относительный импорт { #how-relative-imports-work }
@@ -279,7 +279,7 @@ from ...dependencies import get_token_header
Но мы всё равно можем добавить _ещё_ `tags`, которые будут применяться к конкретной *операции пути*, а также дополнительные `responses`, специфичные для этой *операции пути*:
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[30:31] title["app/routers/items.py"] *}
{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title["app/routers/items.py"] *}
/// tip | Подсказка
@@ -305,13 +305,13 @@ from ...dependencies import get_token_header
И мы даже можем объявить [глобальные зависимости](dependencies/global-dependencies.md){.internal-link target=_blank}, которые будут объединены с зависимостями для каждого `APIRouter`:
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[1,3,7] title["app/main.py"] *}
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title["app/main.py"] *}
### Импорт `APIRouter` { #import-the-apirouter }
Теперь мы импортируем другие подмодули, содержащие `APIRouter`:
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[4:5] title["app/main.py"] *}
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title["app/main.py"] *}
Так как файлы `app/routers/users.py` и `app/routers/items.py` являются подмодулями, входящими в один и тот же Python-пакет `app`, мы можем использовать одну точку `.` для импорта через «относительные импорты».
@@ -374,13 +374,13 @@ from .routers.users import router
Поэтому, чтобы иметь возможность использовать обе в одном файле, мы импортируем подмодули напрямую:
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[5] title["app/main.py"] *}
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title["app/main.py"] *}
### Подключение `APIRouter` для `users` и `items` { #include-the-apirouters-for-users-and-items }
Теперь давайте подключим `router` из подмодулей `users` и `items`:
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[10:11] title["app/main.py"] *}
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title["app/main.py"] *}
/// info | Примечание
@@ -420,13 +420,13 @@ from .routers.users import router
Для этого примера всё будет очень просто. Но допустим, что поскольку он используется совместно с другими проектами в организации, мы не можем модифицировать его и добавить `prefix`, `dependencies`, `tags` и т.д. непосредственно в `APIRouter`:
{* ../../docs_src/bigger_applications/app_an_py39/internal/admin.py hl[3] title["app/internal/admin.py"] *}
{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title["app/internal/admin.py"] *}
Но мы всё равно хотим задать пользовательский `prefix` при подключении `APIRouter`, чтобы все его *операции пути* начинались с `/admin`, хотим защитить его с помощью `dependencies`, которые у нас уже есть для этого проекта, и хотим включить `tags` и `responses`.
Мы можем объявить всё это, не изменяя исходный `APIRouter`, передав эти параметры в `app.include_router()`:
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[14:17] title["app/main.py"] *}
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title["app/main.py"] *}
Таким образом исходный `APIRouter` не будет модифицирован, и мы сможем использовать файл `app/internal/admin.py` сразу в нескольких проектах организации.
@@ -447,7 +447,7 @@ from .routers.users import router
Здесь мы делаем это... просто чтобы показать, что можем 🤷:
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[21:23] title["app/main.py"] *}
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title["app/main.py"] *}
и это будет работать корректно вместе со всеми другими *операциями пути*, добавленными через `app.include_router()`.

View File

@@ -52,7 +52,7 @@
}
```
/// note | Внимание
/// note | Заметка
Обратите внимание, что хотя параметр `item` был объявлен таким же способом, как и раньше, теперь предполагается, что он находится внутри тела с ключом `item`.
@@ -104,12 +104,6 @@
q: str | None = None
```
Или в Python 3.9:
```Python
q: Union[str, None] = None
```
Например:
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}

View File

@@ -163,7 +163,7 @@ images: list[Image]
например так:
{* ../../docs_src/body_nested_models/tutorial008_py39.py hl[13] *}
{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}
## Поддержка редактора кода везде { #editor-support-everywhere }
@@ -193,7 +193,7 @@ images: list[Image]
В этом случае вы принимаете любой `dict`, пока у него есть ключи типа `int` со значениями типа `float`:
{* ../../docs_src/body_nested_models/tutorial009_py39.py hl[7] *}
{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}
/// tip | Совет

View File

@@ -72,7 +72,7 @@
* Проведёт валидацию данных.
* Если данные некорректны, вернёт понятную и наглядную ошибку, указывающую, где именно и что было некорректно.
* Передаст полученные данные в параметр `item`.
* Поскольку внутри функции вы объявили его с типом `Item`, у вас будет поддержка со стороны редактора кода (автозавершение и т. п.) для всех атрибутов и их типов.
* Поскольку внутри функции вы объявили его с типом `Item`, у вас будет поддержка со стороны редактора кода (автозавершение и т.п.) для всех атрибутов и их типов.
* Сгенерирует определения <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a> для вашей модели; вы можете использовать их и в других местах, если это имеет смысл для вашего проекта.
* Эти схемы будут частью сгенерированной схемы OpenAPI и будут использоваться автоматической документацией <abbr title="User Interfaces - Пользовательские интерфейсы">UIs</abbr>.
@@ -148,14 +148,14 @@ JSON Schema ваших моделей будет частью сгенериро
Параметры функции будут распознаны следующим образом:
* Если параметр также объявлен в **пути**, он будет использоваться как path-параметр.
* Если параметр имеет **скалярный тип** (например, `int`, `float`, `str`, `bool` и т. п.), он будет интерпретирован как параметр **запроса**.
* Если параметр имеет **скалярный тип** (например, `int`, `float`, `str`, `bool` и т.п.), он будет интерпретирован как параметр **запроса**.
* Если параметр объявлен как тип **модели Pydantic**, он будет интерпретирован как **тело** запроса.
/// note | Заметка
FastAPI понимает, что значение `q` не является обязательным из-за значения по умолчанию `= None`.
Аннотации типов `str | None` (Python 3.10+) или `Union` в `Union[str, None]` (Python 3.9+) не используются FastAPI для определения обязательности; он узнает, что параметр не обязателен, потому что у него есть значение по умолчанию `= None`.
Аннотация типов `str | None` не используется FastAPI для определения обязательности; он узнает, что параметр не обязателен, потому что у него есть значение по умолчанию `= None`.
Но добавление аннотаций типов позволит вашему редактору кода лучше вас поддерживать и обнаруживать ошибки.

View File

@@ -46,7 +46,7 @@
В некоторых случаях (не особо часто встречающихся) вам может понадобиться **ограничить** cookies, которые вы хотите получать.
Теперь ваш API сам решает, <abbr title="Это шутка, на всякий случай. Это не имеет никакого отношения к согласию на использование cookie, но забавно, что даже API теперь может отклонять несчастные cookies. Съешьте печеньку. 🍪">принимать ли cookies</abbr>. 🤪🍪
Теперь у вашего API есть возможность контролировать своё <dfn title="Это шутка, на всякий случай. Это не имеет никакого отношения к согласию на использование cookie, но забавно, что даже API теперь может отклонять несчастные cookies. Съешьте печеньку. 🍪">согласие на использование cookie</dfn>. 🤪🍪
Вы можете сконфигурировать Pydantic-модель так, чтобы запретить (`forbid`) любые дополнительные (`extra`) поля:
@@ -54,9 +54,9 @@
Если клиент попробует отправить **дополнительные cookies**, то в ответ он получит **ошибку**.
Бедные баннеры cookies, они всеми силами пытаются получить ваше согласие — и всё ради того, чтобы <abbr title="Это ещё одна шутка. Не обращайте на меня внимания. Выпейте кофе со своей печенькой. ☕">API его отклонил</abbr>. 🍪
Бедные баннеры cookies, они всеми силами пытаются получить ваше согласие — и всё ради того, чтобы <dfn title="Это ещё одна шутка. Не обращайте на меня внимания. Выпейте кофе со своей печенькой. ☕">API его отклонил</dfn>. 🍪
Например, если клиент попытается отправить cookie `santa_tracker` со значением `good-list-please`, то в ответ он получит **ошибку**, сообщающую ему, что cookie `santa_tracker` <abbr title="Санта не одобряет пропажу печенья. 🎅 Ладно, больше никаких шуток про печенье.">не разрешён</abbr>:
Например, если клиент попытается отправить cookie `santa_tracker` со значением `good-list-please`, то в ответ он получит **ошибку**, сообщающую ему, что `santa_tracker` <dfn title="Санта не одобряет пропажу печенья. 🎅 Ладно, больше никаких шуток про печенье.">cookie не разрешён</dfn>:
```json
{
@@ -73,4 +73,4 @@
## Заключение { #summary }
Вы можете использовать **Pydantic-модели** для объявления <abbr title="Съешьте последнюю печеньку, прежде чем уйти. 🍪">**cookies**</abbr> в **FastAPI**. 😎
Вы можете использовать **Pydantic-модели** для объявления <dfn title="Съешьте последнюю печеньку, прежде чем уйти. 🍪">**cookies**</dfn> в **FastAPI**. 😎

View File

@@ -32,11 +32,11 @@
/// info | Дополнительная информация
Имейте в виду, что, поскольку браузеры обрабатывают cookies особым образом и «за кулисами», они не позволяют JavaScript просто так получать к ним доступ.
Имейте в виду, что, поскольку **браузеры обрабатывают cookies** особым образом и «за кулисами», они **не** позволяют **JavaScript** просто так получать к ним доступ.
Если вы откроете интерфейс документации API на `/docs`, вы сможете увидеть документацию по cookies для ваших операций пути.
Если вы откроете **интерфейс документации API** на `/docs`, вы сможете увидеть **документацию** по cookies для ваших *операции пути*.
Но даже если вы заполните данные и нажмёте «Execute», поскольку UI документации работает с JavaScript, cookies отправлены не будут, и вы увидите сообщение об ошибке, как будто вы не указали никаких значений.
Но даже если вы **заполните данные** и нажмёте «Execute», поскольку UI документации работает с **JavaScript**, cookies отправлены не будут, и вы увидите сообщение об **ошибке**, как будто вы не указали никаких значений.
///

View File

@@ -46,7 +46,7 @@
* Отдельных HTTP-методов (`POST`, `PUT`) или всех вместе, используя `"*"`.
* Отдельных HTTP-заголовков или всех вместе, используя `"*"`.
{* ../../docs_src/cors/tutorial001_py39.py hl[2,6:11,13:19] *}
{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}
`CORSMiddleware` использует "запрещающие" значения по умолчанию, поэтому вам нужно явным образом разрешить использование отдельных источников, методов или заголовков, чтобы браузеры могли использовать их в кросс-доменном контексте.
@@ -77,7 +77,7 @@
## Больше информации { #more-info }
Для получения более подробной информации о <abbr title="Cross-Origin Resource Sharing совместное использование ресурсов между источниками">CORS</abbr> обратитесь к <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">документации CORS от Mozilla</a>.
Для получения более подробной информации о <abbr title="Cross-Origin Resource Sharing - совместное использование ресурсов между источниками">CORS</abbr> обратитесь к <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">документации CORS от Mozilla</a>.
/// note | Технические детали

View File

@@ -6,7 +6,7 @@
В вашем FastAPI приложении, импортируйте и вызовите `uvicorn` напрямую:
{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *}
{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}
### Описание `__name__ == "__main__"` { #about-name-main }
@@ -42,7 +42,7 @@ $ python myapp.py
то встроенная переменная `__name__`, автоматически создаваемая Python в вашем файле, будет иметь значение строкового типа `"__main__"`.
Тогда выполнится условие и эта часть кода:
Тогда эта часть кода:
```Python
uvicorn.run(app, host="0.0.0.0", port=8000)
@@ -59,7 +59,7 @@ $ python myapp.py
```Python
from myapp import app
# Some more code
# Еще немного кода
```
то автоматическая создаваемая внутри файла `myapp.py` переменная `__name__` будет иметь значение отличающееся от `"__main__"`.
@@ -99,7 +99,7 @@ from myapp import app
---
Если используете Pycharm, вы можете выполнить следующие шаги:
Если используете PyCharm, вы можете выполнить следующие шаги:
* Открыть "Run" меню.
* Выбрать опцию "Debug...".

View File

@@ -4,7 +4,7 @@
## `dict` из предыдущего примера { #a-dict-from-the-previous-example }
В предыдущем примере мы возвращали `dict` из нашей зависимости:
В предыдущем примере мы возвращали `dict` из нашей зависимости («dependable»):
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}
@@ -67,7 +67,7 @@ fluffy = Cat(name="Mr Fluffy")
Это относится и к вызываемым объектам без параметров. Работа с ними происходит точно так же, как и для *функций-обработчиков пути* без параметров.
Теперь мы можем изменить зависимость `common_parameters`, указанную выше, на класс `CommonQueryParams`:
Теперь мы можем изменить зависимость («dependable») `common_parameters`, указанную выше, на класс `CommonQueryParams`:
{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}
@@ -101,7 +101,7 @@ fluffy = Cat(name="Mr Fluffy")
Обратите внимание, что в приведенном выше коде мы два раза пишем `CommonQueryParams`:
//// tab | Python 3.9+
//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
@@ -109,7 +109,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
////
//// tab | Python 3.9+ non-Annotated
//// tab | Python 3.10+ без Annotated
/// tip | Подсказка
@@ -137,7 +137,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams)
В этом случае первый `CommonQueryParams`, в:
//// tab | Python 3.9+
//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, ...
@@ -145,7 +145,7 @@ commons: Annotated[CommonQueryParams, ...
////
//// tab | Python 3.9+ non-Annotated
//// tab | Python 3.10+ без Annotated
/// tip | Подсказка
@@ -163,7 +163,7 @@ commons: CommonQueryParams ...
На самом деле можно написать просто:
//// tab | Python 3.9+
//// tab | Python 3.10+
```Python
commons: Annotated[Any, Depends(CommonQueryParams)]
@@ -171,7 +171,7 @@ commons: Annotated[Any, Depends(CommonQueryParams)]
////
//// tab | Python 3.9+ non-Annotated
//// tab | Python 3.10+ без Annotated
/// tip | Подсказка
@@ -197,7 +197,7 @@ commons = Depends(CommonQueryParams)
Но вы видите, что здесь мы имеем некоторое повторение кода, дважды написав `CommonQueryParams`:
//// tab | Python 3.9+
//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
@@ -205,7 +205,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
////
//// tab | Python 3.9+ non-Annotated
//// tab | Python 3.10+ без Annotated
/// tip | Подсказка
@@ -225,7 +225,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams)
Вместо того чтобы писать:
//// tab | Python 3.9+
//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
@@ -233,7 +233,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
////
//// tab | Python 3.9+ non-Annotated
//// tab | Python 3.10+ без Annotated
/// tip | Подсказка
@@ -249,7 +249,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams)
...следует написать:
//// tab | Python 3.9+
//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, Depends()]
@@ -257,7 +257,7 @@ commons: Annotated[CommonQueryParams, Depends()]
////
//// tab | Python 3.9+ non-Annotated
//// tab | Python 3.10+ без Annotated
/// tip | Подсказка

View File

@@ -14,7 +14,7 @@
Это должен быть `list` состоящий из `Depends()`:
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[19] *}
{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}
Зависимости из dependencies выполнятся так же, как и обычные зависимости. Но их значения (если они были) не будут переданы в *функцию операции пути*.
@@ -30,7 +30,7 @@
/// info | Примечание
В этом примере мы используем выдуманные пользовательские заголовки `X-Key` и `X-Token`.
В этом примере мы используем выдуманные пользовательские HTTP-заголовки `X-Key` и `X-Token`.
Но в реальных проектах, при внедрении системы безопасности, вы получите больше пользы используя интегрированные [средства защиты (следующая глава)](../security/index.md){.internal-link target=_blank}.
@@ -42,15 +42,15 @@
### Требования к зависимостям { #dependency-requirements }
Они могут объявлять требования к запросу (например заголовки) или другие подзависимости:
Они могут объявлять требования к запросу (например HTTP-заголовки) или другие подзависимости:
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[8,13] *}
{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}
### Вызов исключений { #raise-exceptions }
Зависимости из dependencies могут вызывать исключения с помощью `raise`, как и обычные зависимости:
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[10,15] *}
{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}
### Возвращаемые значения { #return-values }
@@ -58,7 +58,7 @@
Таким образом, вы можете переиспользовать обычную зависимость (возвращающую значение), которую вы уже используете где-то в другом месте, и хотя значение не будет использоваться, зависимость будет выполнена:
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[11,16] *}
{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}
## Зависимости для группы *операций путей* { #dependencies-for-a-group-of-path-operations }

View File

@@ -1,6 +1,6 @@
# Зависимости с yield { #dependencies-with-yield }
FastAPI поддерживает зависимости, которые выполняют некоторые <abbr title='иногда также называемые "exit code", "cleanup code", "teardown code", "closing code", "context manager exit code" и т.п.'>дополнительные шаги после завершения</abbr>.
FastAPI поддерживает зависимости, которые выполняют некоторые <dfn title='иногда также называемые "код выхода", "код очистки", "код завершения", "код закрытия", "код выхода менеджера контекста" и т.п.'>дополнительные шаги после завершения</dfn>.
Для этого используйте `yield` вместо `return`, а дополнительные шаги (код) напишите после него.
@@ -29,15 +29,15 @@ FastAPI поддерживает зависимости, которые выпо
Перед созданием ответа будет выполнен только код до и включая оператор `yield`:
{* ../../docs_src/dependencies/tutorial007_py39.py hl[2:4] *}
{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}
Значение, полученное из `yield`, внедряется в *операции пути* и другие зависимости:
{* ../../docs_src/dependencies/tutorial007_py39.py hl[4] *}
{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}
Код, следующий за оператором `yield`, выполняется после ответа:
{* ../../docs_src/dependencies/tutorial007_py39.py hl[5:6] *}
{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}
/// tip | Подсказка
@@ -57,7 +57,7 @@ FastAPI поддерживает зависимости, которые выпо
Точно так же можно использовать `finally`, чтобы убедиться, что обязательные шаги при выходе выполнены независимо от того, было ли исключение или нет.
{* ../../docs_src/dependencies/tutorial007_py39.py hl[3,5] *}
{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}
## Подзависимости с `yield` { #sub-dependencies-with-yield }
@@ -67,7 +67,7 @@ FastAPI поддерживает зависимости, которые выпо
Например, `dependency_c` может зависеть от `dependency_b`, а `dependency_b` — от `dependency_a`:
{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[6,14,22] *}
{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}
И все они могут использовать `yield`.
@@ -75,7 +75,7 @@ FastAPI поддерживает зависимости, которые выпо
И, в свою очередь, `dependency_b` нуждается в том, чтобы значение из `dependency_a` (здесь `dep_a`) было доступно для её кода выхода.
{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[18:19,26:27] *}
{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}
Точно так же можно иметь часть зависимостей с `yield`, часть — с `return`, и какие-то из них могут зависеть друг от друга.
@@ -109,7 +109,7 @@ FastAPI поддерживает зависимости, которые выпо
///
{* ../../docs_src/dependencies/tutorial008b_an_py39.py hl[18:22,31] *}
{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}
Если вы хотите перехватывать исключения и формировать на их основе пользовательский ответ, создайте [Пользовательский обработчик исключений](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.
@@ -117,7 +117,7 @@ FastAPI поддерживает зависимости, которые выпо
Если вы ловите исключение с помощью `except` в зависимости с `yield` и не вызываете его снова (или не вызываете новое исключение), FastAPI не сможет заметить, что было исключение — так же, как это происходит в обычном Python:
{* ../../docs_src/dependencies/tutorial008c_an_py39.py hl[15:16] *}
{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}
В этом случае клиент получит *HTTP 500 Internal Server Error*, как и должно быть, поскольку мы не вызываем `HTTPException` или что-то подобное, но на сервере **не будет никаких логов** или других указаний на то, какая была ошибка. 😱
@@ -127,7 +127,7 @@ FastAPI поддерживает зависимости, которые выпо
Вы можете повторно вызвать то же самое исключение с помощью `raise`:
{* ../../docs_src/dependencies/tutorial008d_an_py39.py hl[17] *}
{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}
Теперь клиент получит тот же *HTTP 500 Internal Server Error*, но на сервере в логах будет наше пользовательское `InternalError`. 😎
@@ -190,7 +190,7 @@ participant tasks as Background tasks
Но если вы знаете, что не будете использовать зависимость после возврата из *функции-обработчика пути*, вы можете использовать `Depends(scope="function")`, чтобы сообщить FastAPI, что он должен закрыть зависимость после возврата из *функции-обработчика пути*, но **до того**, как **ответ будет отправлен**.
{* ../../docs_src/dependencies/tutorial008e_an_py39.py hl[12,16] *}
{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}
`Depends()` принимает параметр `scope`, который может быть:
@@ -269,7 +269,7 @@ with open("./somefile.txt") as f:
Их также можно использовать внутри зависимостей **FastAPI** с `yield`, применяя операторы
`with` или `async with` внутри функции зависимости:
{* ../../docs_src/dependencies/tutorial010_py39.py hl[1:9,13] *}
{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *}
/// tip | Подсказка

View File

@@ -6,10 +6,10 @@
В этом случае они будут применяться ко всем *операциям пути* в приложении:
{* ../../docs_src/dependencies/tutorial012_an_py39.py hl[17] *}
{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *}
Все способы [добавления `dependencies` (зависимостей) в *декораторах операций пути*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} по-прежнему применимы, но в данном случае зависимости применяются ко всем *операциям пути* приложения.
## Зависимости для групп *операций пути* { #dependencies-for-groups-of-path-operations }
Позднее, читая о том, как структурировать более крупные [приложения, содержащие много файлов](../../tutorial/bigger-applications.md){.internal-link target=_blank}, вы узнаете, как объявить один параметр `dependencies` для целой группы *операций пути*.
Позднее, читая о том, как структурировать более крупные приложения ([приложения, содержащие много файлов](../../tutorial/bigger-applications.md){.internal-link target=_blank}), возможно, состоящие из нескольких файлов, вы узнаете, как объявить один параметр `dependencies` для целой группы *операций пути*.

View File

@@ -1,6 +1,6 @@
# Зависимости { #dependencies }
**FastAPI** имеет очень мощную, но интуитивную систему **<abbr title="также известно как: компоненты, ресурсы, провайдеры, сервисы, внедряемые зависимости">Инъекция зависимостей</abbr>**.
**FastAPI** имеет очень мощную, но интуитивную систему **<dfn title="также известно как: компоненты, ресурсы, провайдеры, сервисы, внедряемые зависимости">Инъекция зависимостей</dfn>**.
Она спроектирована так, чтобы быть очень простой в использовании и облегчать любому разработчику интеграцию других компонентов с **FastAPI**.

View File

@@ -58,11 +58,11 @@ query_extractor --> query_or_cookie_extractor --> read_query
Если одна из ваших зависимостей объявлена несколько раз для одной и той же *функции операции пути*, например, несколько зависимостей имеют общую подзависимость, **FastAPI** будет знать, что вызывать эту подзависимость нужно только один раз за запрос.
При этом возвращаемое значение будет сохранено в <abbr title="Система для хранения значений, сгенерированных компьютером, для их повторного использования вместо повторного вычисления.">"кэш"</abbr> и будет передано всем "зависимым" функциям, которые нуждаются в нем внутри этого конкретного запроса, вместо того, чтобы вызывать зависимость несколько раз для одного и того же запроса.
При этом возвращаемое значение будет сохранено в <dfn title="Вспомогательная система для хранения вычисленных/сгенерированных значений, чтобы переиспользовать их вместо повторного вычисления.">«кэш»</dfn> и будет передано всем "зависимым" функциям, которые нуждаются в нем внутри этого конкретного запроса, вместо того, чтобы вызывать зависимость несколько раз для одного и того же запроса.
В расширенном сценарии, когда вы знаете, что вам нужно, чтобы зависимость вызывалась на каждом шаге (возможно, несколько раз) в одном и том же запросе, вместо использования "кэшированного" значения, вы можете установить параметр `use_cache=False` при использовании `Depends`:
//// tab | Python 3.9+
//// tab | Python 3.10+
```Python hl_lines="1"
async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):
@@ -71,7 +71,7 @@ async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_ca
////
//// tab | Python 3.9+ без Annotated
//// tab | Python 3.10+ без Annotated
/// tip | Подсказка

View File

@@ -10,9 +10,9 @@
Представим, что у вас есть база данных `fake_db`, которая принимает только JSON-совместимые данные.
Например, он не принимает объекты `datetime`, так как они не совместимы с JSON.
Например, она не принимает объекты `datetime`, так как они не совместимы с JSON.
В таком случае объект `datetime` следует преобразовать в строку соответствующую <a href="https://en.wikipedia.org/wiki/ISO_8601" class="external-link" target="_blank">формату ISO</a>.
В таком случае объект `datetime` следует преобразовать в строку, соответствующую <a href="https://en.wikipedia.org/wiki/ISO_8601" class="external-link" target="_blank">формату ISO</a>.
Точно так же эта база данных не может принять Pydantic-модель (объект с атрибутами), а только `dict`.

View File

@@ -190,9 +190,9 @@ some_variable: PlaneItem | CarItem
Таким же образом вы можете объявлять HTTP-ответы, возвращающие списки объектов.
Для этого используйте стандартный `typing.List` в Python (или просто `list` в Python 3.9 и выше):
Для этого используйте стандартный `list` в Python:
{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *}
{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}
## Ответ с произвольным `dict` { #response-with-arbitrary-dict }
@@ -200,9 +200,9 @@ some_variable: PlaneItem | CarItem
Это полезно, если вы заранее не знаете корректных названий полей/атрибутов (которые будут нужны при использовании Pydantic-модели).
В этом случае вы можете использовать `typing.Dict` (или просто `dict` в Python 3.9 и выше):
В этом случае вы можете использовать `dict`:
{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *}
{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}
## Резюме { #recap }

View File

@@ -2,7 +2,7 @@
Самый простой файл FastAPI может выглядеть так:
{* ../../docs_src/first_steps/tutorial001_py39.py *}
{* ../../docs_src/first_steps/tutorial001_py310.py *}
Скопируйте это в файл `main.py`.
@@ -183,7 +183,7 @@ Deploying to FastAPI Cloud...
### Шаг 1: импортируйте `FastAPI` { #step-1-import-fastapi }
{* ../../docs_src/first_steps/tutorial001_py39.py hl[1] *}
{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}
`FastAPI` — это класс на Python, который предоставляет всю функциональность для вашего API.
@@ -197,7 +197,7 @@ Deploying to FastAPI Cloud...
### Шаг 2: создайте экземпляр `FastAPI` { #step-2-create-a-fastapi-instance }
{* ../../docs_src/first_steps/tutorial001_py39.py hl[3] *}
{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *}
Здесь переменная `app` будет экземпляром класса `FastAPI`.
@@ -266,12 +266,12 @@ https://example.com/items/foo
#### Определите *декоратор операции пути (path operation decorator)* { #define-a-path-operation-decorator }
{* ../../docs_src/first_steps/tutorial001_py39.py hl[6] *}
{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}
`@app.get("/")` сообщает **FastAPI**, что функция прямо под ним отвечает за обработку запросов, поступающих:
* по пути `/`
* с использованием <abbr title="метод HTTP GET"><code>get</code> операции</abbr>
* с использованием <dfn title="метод HTTP GET"><code>get</code> операции</dfn>
/// info | Информация о `@decorator`
@@ -320,7 +320,7 @@ https://example.com/items/foo
* **операция**: `get`.
* **функция**: функция ниже «декоратора» (ниже `@app.get("/")`).
{* ../../docs_src/first_steps/tutorial001_py39.py hl[7] *}
{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}
Это функция на Python.
@@ -332,7 +332,7 @@ https://example.com/items/foo
Вы также можете определить её как обычную функцию вместо `async def`:
{* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *}
{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}
/// note | Примечание
@@ -342,7 +342,7 @@ https://example.com/items/foo
### Шаг 5: верните содержимое { #step-5-return-the-content }
{* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *}
{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}
Вы можете вернуть `dict`, `list`, отдельные значения `str`, `int` и т.д.

View File

@@ -11,7 +11,7 @@
* Элемент, к которому клиент пытался получить доступ, не существует.
* и т.д.
В таких случаях обычно возвращается **HTTP-код статуса ответа** в диапазоне **400** (от 400 до 499).
В таких случаях обычно возвращают **HTTP статус-код** в диапазоне **400** (от 400 до 499).
Они похожи на двухсотые HTTP статус-коды (от 200 до 299), которые означают, что запрос обработан успешно.
@@ -25,7 +25,7 @@
### Импортируйте `HTTPException` { #import-httpexception }
{* ../../docs_src/handling_errors/tutorial001_py39.py hl[1] *}
{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}
### Вызовите `HTTPException` в своем коде { #raise-an-httpexception-in-your-code }
@@ -39,7 +39,7 @@
В данном примере, когда клиент запрашивает элемент по несуществующему ID, возникает исключение со статус-кодом `404`:
{* ../../docs_src/handling_errors/tutorial001_py39.py hl[11] *}
{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}
### Возвращаемый ответ { #the-resulting-response }
@@ -71,13 +71,13 @@
## Добавление пользовательских заголовков { #add-custom-headers }
В некоторых ситуациях полезно иметь возможность добавлять пользовательские заголовки к ошибке HTTP. Например, для некоторых типов безопасности.
В некоторых ситуациях полезно иметь возможность добавлять пользовательские HTTP-заголовки к ошибке HTTP. Например, для некоторых типов безопасности.
Скорее всего, вам не потребуется использовать его непосредственно в коде.
Но в случае, если это необходимо для продвинутого сценария, можно добавить пользовательские заголовки:
{* ../../docs_src/handling_errors/tutorial002_py39.py hl[14] *}
{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}
## Установка пользовательских обработчиков исключений { #install-custom-exception-handlers }
@@ -89,7 +89,7 @@
Можно добавить собственный обработчик исключений с помощью `@app.exception_handler()`:
{* ../../docs_src/handling_errors/tutorial003_py39.py hl[5:7,13:18,24] *}
{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}
Здесь, если запросить `/unicorns/yolo`, то *операция пути* вызовет `UnicornException`.
@@ -127,7 +127,7 @@
Обработчик исключения получит объект `Request` и исключение.
{* ../../docs_src/handling_errors/tutorial004_py39.py hl[2,14:19] *}
{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}
Теперь, если перейти к `/items/foo`, то вместо стандартной JSON-ошибки с:
@@ -159,7 +159,7 @@ Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to pa
Например, для этих ошибок можно вернуть обычный текстовый ответ вместо JSON:
{* ../../docs_src/handling_errors/tutorial004_py39.py hl[3:4,9:11,25] *}
{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}
/// note | Технические детали
@@ -183,7 +183,7 @@ Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to pa
Вы можете использовать его при разработке приложения для регистрации тела и его отладки, возврата пользователю и т.д.
{* ../../docs_src/handling_errors/tutorial005_py39.py hl[14] *}
{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}
Теперь попробуйте отправить недействительный элемент, например:
@@ -239,6 +239,6 @@ from starlette.exceptions import HTTPException as StarletteHTTPException
Если вы хотите использовать исключение вместе с теми же обработчиками исключений по умолчанию из **FastAPI**, вы можете импортировать и повторно использовать обработчики исключений по умолчанию из `fastapi.exception_handlers`:
{* ../../docs_src/handling_errors/tutorial006_py39.py hl[2:5,15,21] *}
{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}
В этом примере вы просто `выводите в терминал` ошибку с очень выразительным сообщением, но идея вам понятна. Вы можете использовать исключение, а затем просто повторно использовать стандартные обработчики исключений.

View File

@@ -18,7 +18,7 @@
Вы можете задать их следующим образом:
{* ../../docs_src/metadata/tutorial001_py39.py hl[3:16, 19:32] *}
{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}
/// tip | Подсказка
@@ -36,7 +36,7 @@
К примеру:
{* ../../docs_src/metadata/tutorial001_1_py39.py hl[31] *}
{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}
## Метаданные для тегов { #metadata-for-tags }
@@ -58,7 +58,7 @@
Создайте метаданные для ваших тегов и передайте их в параметре `openapi_tags`:
{* ../../docs_src/metadata/tutorial004_py39.py hl[3:16,18] *}
{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}
Помните, что вы можете использовать Markdown внутри описания, к примеру "login" будет отображен жирным шрифтом (**login**) и "fancy" будет отображаться курсивом (_fancy_).
@@ -72,7 +72,7 @@
Используйте параметр `tags` с вашими *операциями пути*`APIRouter`ами), чтобы присвоить им различные теги:
{* ../../docs_src/metadata/tutorial004_py39.py hl[21,26] *}
{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}
/// info | Дополнительная информация
@@ -100,7 +100,7 @@
К примеру, чтобы задать её отображение по адресу `/api/v1/openapi.json`:
{* ../../docs_src/metadata/tutorial002_py39.py hl[3] *}
{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}
Если вы хотите отключить схему OpenAPI полностью, вы можете задать `openapi_url=None`, это также отключит пользовательские интерфейсы документации, которые её используют.
@@ -117,4 +117,4 @@
К примеру, чтобы задать отображение Swagger UI по адресу `/documentation` и отключить ReDoc:
{* ../../docs_src/metadata/tutorial003_py39.py hl[3] *}
{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}

View File

@@ -1,10 +1,8 @@
# Middleware (Промежуточный слой) { #middleware }
Вы можете добавить промежуточный слой (middleware) в **FastAPI** приложение.
"Middleware" это функция, которая выполняется с каждым запросом до его обработки какой-либо конкретной *операцией пути*.
А также с каждым ответом перед его возвращением.
Вы можете добавить middleware (промежуточный слой) в **FastAPI** приложение.
"Middleware" - это функция, которая выполняется с каждым **запросом** до его обработки какой-либо конкретной *операцией пути*. А также с каждым **ответом** перед его возвращением.
* Она принимает каждый поступающий **запрос**.
* Может что-то сделать с этим **запросом** или выполнить любой нужный код.
@@ -23,23 +21,23 @@
## Создание middleware { #create-a-middleware }
Для создания middleware используйте декоратор `@app.middleware("http")`.
Для создания middleware используйте декоратор `@app.middleware("http")` поверх функции.
Функция middleware получает:
* `request` (объект запроса).
* `request`.
* Функцию `call_next`, которая получает `request` в качестве параметра.
* Эта функция передаёт `request` соответствующей *операции пути*.
* Затем она возвращает ответ `response`, сгенерированный *операцией пути*.
* Также имеется возможность видоизменить `response`, перед тем как его вернуть.
* Затем она возвращает `response`, сгенерированный соответствующей *операцией пути*.
* Также имеется возможность видоизменить `response` перед тем как его вернуть.
{* ../../docs_src/middleware/tutorial001_py39.py hl[8:9,11,14] *}
{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}
/// tip | Примечание
/// tip | Совет
Имейте в виду, что можно добавлять свои собственные заголовки <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" class="external-link" target="_blank">при помощи префикса 'X-'</a>.
Имейте в виду, что можно добавлять проприетарные HTTP-заголовки <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" class="external-link" target="_blank">с префиксом `X-`</a>.
Если же вы хотите добавить собственные заголовки, которые клиент сможет увидеть в браузере, то вам потребуется добавить их в настройки CORS ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}), используя параметр `expose_headers`, см. документацию <a href="https://www.starlette.dev/middleware/#corsmiddleware" class="external-link" target="_blank">Starlette's CORS docs</a>.
Но если вы хотите, чтобы клиент в браузере мог видеть ваши пользовательские заголовки, необходимо добавить их в настройки CORS ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}), используя параметр `expose_headers`, описанный в <a href="https://www.starlette.dev/middleware/#corsmiddleware" class="external-link" target="_blank">документации по CORS Starlette</a>.
///
@@ -53,17 +51,17 @@
### До и после `response` { #before-and-after-the-response }
Вы можете добавить код, использующий `request` до передачи его какой-либо *операции пути*.
Вы можете добавить код, использующий `request`, до передачи его какой-либо *операции пути*.
А также после формирования `response`, до того, как вы его вернёте.
Например, вы можете добавить собственный заголовок `X-Process-Time`, содержащий время в секундах, необходимое для обработки запроса и генерации ответа:
{* ../../docs_src/middleware/tutorial001_py39.py hl[10,12:13] *}
{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}
/// tip | Примечание
/// tip | Совет
Мы используем <a href="https://docs.python.org/3/library/time.html#time.perf_counter" class="external-link" target="_blank">`time.perf_counter()`</a> вместо `time.time()` для обеспечения большей точности наших примеров. 🤓
Мы используем <a href="https://docs.python.org/3/library/time.html#time.perf_counter" class="external-link" target="_blank">`time.perf_counter()`</a> вместо `time.time()` для обеспечения большей точности в таких случаях. 🤓
///
@@ -94,4 +92,4 @@ app.add_middleware(MiddlewareB)
О других middleware вы можете узнать больше в разделе [Advanced User Guide: Advanced Middleware](../advanced/middleware.md){.internal-link target=_blank}.
В следующем разделе вы можете прочитать, как настроить <abbr title="Cross-Origin Resource Sharing совместное использование ресурсов между источниками">CORS</abbr> с помощью middleware.
В следующем разделе вы можете прочитать, как настроить <abbr title="Cross-Origin Resource Sharing - совместное использование ресурсов между источниками">CORS</abbr> с помощью middleware.

View File

@@ -4,7 +4,7 @@
/// warning | Внимание
Помните, что эти параметры передаются непосредственно *декоратору операций пути*, а не вашей *функции-обработчику операций пути*.
Помните, что эти параметры передаются непосредственно *декоратору операций пути*, а не вашей *функции-обработчику пути*.
///
@@ -46,7 +46,7 @@
**FastAPI** поддерживает это так же, как и в случае с обычными строками:
{* ../../docs_src/path_operation_configuration/tutorial002b_py39.py hl[1,8:10,13,18] *}
{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}
## Краткое и развёрнутое содержание { #summary-and-description }
@@ -56,7 +56,7 @@
## Описание из строк документации { #description-from-docstring }
Так как описания обычно длинные и содержат много строк, вы можете объявить описание *операции пути* в функции <abbr title="многострочный текст, первое выражение внутри функции (не присвоенный какой-либо переменной), используемый для документации">строки документации</abbr> и **FastAPI** прочитает её отсюда.
Так как описания обычно длинные и содержат много строк, вы можете объявить описание *операции пути* в <dfn title="многострочная строка, первое выражение внутри функции (не присвоенное какой-либо переменной), используемая для документации">строке документации</dfn> функции, и **FastAPI** прочитает её оттуда.
Вы можете использовать <a href="https://en.wikipedia.org/wiki/Markdown" class="external-link" target="_blank">Markdown</a> в строке документации, и он будет интерпретирован и отображён корректно (с учетом отступа в строке документации).
@@ -90,9 +90,9 @@ OpenAPI указывает, что каждой *операции пути* не
## Обозначение *операции пути* как устаревшей { #deprecate-a-path-operation }
Если вам необходимо пометить *операцию пути* как <abbr title="устаревшее, не рекомендовано к использованию">устаревшую</abbr>, при этом не удаляя её, передайте параметр `deprecated`:
Если вам необходимо пометить *операцию пути* как <dfn title="устаревшая, рекомендуется не использовать">устаревшую</dfn>, при этом не удаляя её, передайте параметр `deprecated`:
{* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *}
{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}
Он будет четко помечен как устаревший в интерактивной документации:

View File

@@ -44,7 +44,7 @@ Path-параметр всегда является обязательным, п
И если вам больше ничего не нужно указывать для этого параметра, то нет необходимости использовать `Query`.
Но вам по-прежнему нужно использовать `Path` для path-параметра `item_id`. И если по какой-либо причине вы не хотите использовать `Annotated`, то могут возникнуть небольшие сложности.
Но вам по-прежнему нужно использовать `Path` для path-параметра `item_id`. И по какой-либо причине вы не хотите использовать `Annotated`.
Если вы поместите параметр со значением по умолчанию перед другим параметром, у которого нет значения по умолчанию, то Python укажет на ошибку.
@@ -54,11 +54,11 @@ Path-параметр всегда является обязательным, п
Поэтому вы можете определить функцию так:
{* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *}
{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}
Но имейте в виду, что если вы используете `Annotated`, вы не столкнётесь с этой проблемой, так как вы не используете значения по умолчанию параметров функции для `Query()` или `Path()`.
{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py *}
{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}
## Задайте нужный вам порядок параметров, полезные приёмы { #order-the-parameters-as-you-need-tricks }
@@ -83,13 +83,13 @@ Path-параметр всегда является обязательным, п
Python не будет ничего делать с `*`, но он будет знать, что все следующие параметры являются именованными аргументами (парами ключ-значение), также известными как <abbr title="От: K-ey W-ord Arg-uments"><code>kwargs</code></abbr>, даже если у них нет значений по умолчанию.
{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *}
{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}
### Лучше с `Annotated` { #better-with-annotated }
Имейте в виду, что если вы используете `Annotated`, то, поскольку вы не используете значений по умолчанию для параметров функции, у вас не возникнет подобной проблемы и вам, вероятно, не придётся использовать `*`.
{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *}
{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}
## Валидация числовых данных: больше или равно { #number-validations-greater-than-or-equal }
@@ -97,7 +97,7 @@ Python не будет ничего делать с `*`, но он будет з
В этом примере при указании `ge=1`, параметр `item_id` должен быть целым числом "`g`reater than or `e`qual" — больше или равно `1`.
{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *}
{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}
## Валидация числовых данных: больше и меньше или равно { #number-validations-greater-than-and-less-than-or-equal }
@@ -106,7 +106,7 @@ Python не будет ничего делать с `*`, но он будет з
* `gt`: больше (`g`reater `t`han)
* `le`: меньше или равно (`l`ess than or `e`qual)
{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py hl[10] *}
{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}
## Валидация числовых данных: числа с плавающей точкой, больше и меньше { #number-validations-floats-greater-than-and-less-than }
@@ -118,7 +118,7 @@ Python не будет ничего делать с `*`, но он будет з
То же самое справедливо и для <abbr title="less than меньше чем"><code>lt</code></abbr>.
{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *}
{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}
## Резюме { #recap }

View File

@@ -2,7 +2,7 @@
Вы можете определить "параметры" или "переменные" пути, используя синтаксис форматированных строк Python:
{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *}
{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}
Значение параметра пути `item_id` будет передано в функцию в качестве аргумента `item_id`.
@@ -16,7 +16,7 @@
Вы можете объявить тип параметра пути в функции, используя стандартные аннотации типов Python:
{* ../../docs_src/path_params/tutorial002_py39.py hl[7] *}
{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *}
Здесь, `item_id` объявлен типом `int`.
@@ -26,7 +26,7 @@
///
## <abbr title="также известное как: сериализация, парсинг, маршаллинг">Преобразование</abbr> данных { #data-conversion }
## <dfn title="также известно как: сериализация, парсинг, маршаллинг">Преобразование</dfn> данных { #data-conversion }
Если запустите этот пример и перейдёте по адресу: <a href="http://127.0.0.1:8000/items/3" class="external-link" target="_blank">http://127.0.0.1:8000/items/3</a>, то увидите ответ:
@@ -38,7 +38,7 @@
Обратите внимание на значение `3`, которое получила (и вернула) функция. Это целочисленный Python `int`, а не строка `"3"`.
Используя такое объявление типов, **FastAPI** выполняет автоматический <abbr title="преобразование строк из HTTP-запроса в типы данных Python">"парсинг"</abbr> запросов.
Используя такое объявление типов, **FastAPI** выполняет автоматический HTTP-запрос <dfn title="преобразование строки, которая приходит из HTTP-запроса, в данные Python">"парсинг"</dfn>.
///
@@ -118,13 +118,13 @@
Поскольку *операции пути* выполняются в порядке их объявления, необходимо, чтобы путь для `/users/me` был объявлен раньше, чем путь для `/users/{user_id}`:
{* ../../docs_src/path_params/tutorial003_py39.py hl[6,11] *}
{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}
Иначе путь для `/users/{user_id}` также будет соответствовать `/users/me`, "подразумевая", что он получает параметр `user_id` со значением `"me"`.
Аналогично, вы не можете переопределить операцию с путем:
{* ../../docs_src/path_params/tutorial003b_py39.py hl[6,11] *}
{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}
Первый будет выполняться всегда, так как путь совпадает первым.
@@ -140,11 +140,11 @@
Затем создайте атрибуты класса с фиксированными допустимыми значениями:
{* ../../docs_src/path_params/tutorial005_py39.py hl[1,6:9] *}
{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}
/// tip | Подсказка
Если интересно, то "AlexNet", "ResNet" и "LeNet" - это названия <abbr title="Технически, архитектуры моделей глубокого обучения">моделей</abbr> Машинного обучения.
Если интересно, то "AlexNet", "ResNet" и "LeNet" - это названия <dfn title="Технически, архитектуры моделей глубокого обучения">моделей</dfn> Машинного обучения.
///
@@ -152,7 +152,7 @@
Определите *параметр пути*, используя в аннотации типа класс перечисления (`ModelName`), созданный ранее:
{* ../../docs_src/path_params/tutorial005_py39.py hl[16] *}
{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *}
### Проверьте документацию { #check-the-docs }
@@ -168,13 +168,13 @@
Вы можете сравнить это значение с *элементом перечисления* класса `ModelName`:
{* ../../docs_src/path_params/tutorial005_py39.py hl[17] *}
{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *}
#### Получение *значения перечисления* { #get-the-enumeration-value }
Можно получить фактическое значение (в данном случае - `str`) с помощью `model_name.value` или в общем случае `your_enum_member.value`:
{* ../../docs_src/path_params/tutorial005_py39.py hl[20] *}
{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *}
/// tip | Подсказка
@@ -188,8 +188,8 @@
Они будут преобразованы в соответствующие значения (в данном случае - строки) перед их возвратом клиенту:
{* ../../docs_src/path_params/tutorial005_py39.py hl[18,21,23] *}
Вы отправите клиенту такой JSON-ответ:
{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *}
На стороне клиента вы получите такой JSON-ответ:
```JSON
{
@@ -226,7 +226,7 @@ OpenAPI не поддерживает способов объявления *п
Можете использовать так:
{* ../../docs_src/path_params/tutorial004_py39.py hl[6] *}
{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *}
/// tip | Подсказка
@@ -241,7 +241,7 @@ OpenAPI не поддерживает способов объявления *п
Используя **FastAPI** вместе со стандартными объявлениями типов Python (короткими и интуитивно понятными), вы получаете:
* Поддержку редактора кода (проверку ошибок, автозавершение и т.п.)
* "<abbr title="преобразование строк из HTTP-запроса в типы данных Python">Парсинг</abbr>" данных
* "<dfn title="преобразование строки, которая приходит из HTTP-запроса, в данные Python">Парсинг</dfn>" данных
* Валидацию данных
* Аннотации API и автоматическую документацию

View File

@@ -6,7 +6,7 @@
/// note | Заметка
Этот функционал доступен с версии `0.115.0`. 🤓
Это поддерживается начиная с версии FastAPI `0.115.0`. 🤓
///

View File

@@ -47,40 +47,16 @@ FastAPI поймёт, что значение `q` не обязательно,
У нас была такая аннотация типа:
//// tab | Python 3.10+
```Python
q: str | None = None
```
////
//// tab | Python 3.9+
```Python
q: Union[str, None] = None
```
////
Мы «обернём» это в `Annotated`, и получится:
//// tab | Python 3.10+
```Python
q: Annotated[str | None] = None
```
////
//// tab | Python 3.9+
```Python
q: Annotated[Union[str, None]] = None
```
////
Обе версии означают одно и то же: `q` — параметр, который может быть `str` или `None`, и по умолчанию равен `None`.
А теперь к самому интересному. 🎉
@@ -109,7 +85,7 @@ q: Annotated[Union[str, None]] = None
## Альтернатива (устаревшее): `Query` как значение по умолчанию { #alternative-old-query-as-the-default-value }
В предыдущих версиях FastAPI (до <abbr title="до 2023-03">0.95.0</abbr>) требовалось использовать `Query` как значение по умолчанию для параметра вместо помещения его в `Annotated`. Скорее всего вы ещё встретите такой код, поэтому поясню.
В предыдущих версиях FastAPI (до <dfn title="до 2023-03">0.95.0</dfn>) требовалось использовать `Query` как значение по умолчанию для параметра вместо помещения его в `Annotated`. Скорее всего вы ещё встретите такой код, поэтому поясню.
/// tip | Подсказка
@@ -191,7 +167,7 @@ q: str = Query(default="rick")
## Регулярные выражения { #add-regular-expressions }
Вы можете определить <abbr title="Регулярное выражение (regex, regexp) - это последовательность символов, задающая шаблон поиска для строк.">регулярное выражение</abbr> `pattern`, которому должен соответствовать параметр:
Вы можете определить <dfn title="Регулярное выражение (regex, regexp) это последовательность символов, задающая шаблон поиска для строк.">регулярное выражение</dfn> `pattern`, которому должен соответствовать параметр:
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
@@ -211,7 +187,7 @@ q: str = Query(default="rick")
Допустим, вы хотите объявить, что query-параметр `q` должен иметь `min_length` равный `3` и значение по умолчанию `"fixedquery"`:
{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}
{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}
/// note | Примечание
@@ -241,7 +217,7 @@ q: Annotated[str | None, Query(min_length=3)] = None
Поэтому, когда вам нужно объявить значение как обязательное при использовании `Query`, просто не указывайте значение по умолчанию:
{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}
### Обязательный, но может быть `None` { #required-can-be-none }
@@ -292,7 +268,7 @@ http://localhost:8000/items/?q=foo&q=bar
Можно также определить значение по умолчанию как `list`, если ничего не передано:
{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}
{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}
Если вы перейдёте по адресу:
@@ -315,7 +291,7 @@ http://localhost:8000/items/
Можно использовать `list` напрямую вместо `list[str]`:
{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}
/// note | Примечание
@@ -371,7 +347,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
Предположим, этот параметр вам больше не нравится.
Его нужно оставить на какое‑то время, так как клиенты его используют, но вы хотите, чтобы в документации он явно отображался как <abbr title="устаревший, не рекомендуется использовать">устаревший</abbr>.
Его нужно оставить на какое‑то время, так как клиенты его используют, но вы хотите, чтобы в документации он явно отображался как <dfn title="устаревший, не рекомендуется использовать">устаревший</dfn>.
Тогда передайте параметр `deprecated=True` в `Query`:
@@ -401,7 +377,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
///
Например, эта кастомная проверка убеждается, что ID элемента начинается с `isbn-` для номера книги <abbr title="ISBN означает International Standard Book Number - Международный стандартный книжный номер">ISBN</abbr> или с `imdb-` для ID URL фильма на <abbr title="IMDB (Internet Movie Database) - веб‑сайт с информацией о фильмах">IMDB</abbr>:
Например, эта кастомная проверка убеждается, что ID элемента начинается с `isbn-` для номера книги <abbr title="International Standard Book Number - Международный стандартный книжный номер">ISBN</abbr> или с `imdb-` для ID URL фильма на <abbr title="Internet Movie Database - Интернетная база данных фильмов: веб‑сайт с информацией о фильмах">IMDB</abbr>:
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
@@ -435,7 +411,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
#### Случайный элемент { #a-random-item }
С помощью `data.items()` мы получаем <abbr title="Объект, по которому можно итерироваться циклом for, например список, множество и т. п.">итерируемый объект</abbr> с кортежами, содержащими ключ и значение для каждого элемента словаря.
С помощью `data.items()` мы получаем <dfn title="Объект, по которому можно итерироваться циклом for, например список, множество и т.п.">итерируемый объект</dfn> с кортежами, содержащими ключ и значение для каждого элемента словаря.
Мы превращаем этот итерируемый объект в обычный `list` через `list(data.items())`.

View File

@@ -2,7 +2,7 @@
Когда вы объявляете параметры функции, которые не являются параметрами пути, они автоматически интерпретируются как "query"-параметры.
{* ../../docs_src/query_params/tutorial001_py39.py hl[9] *}
{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}
Query-параметры представляют из себя набор пар ключ-значение, которые идут после знака `?` в URL-адресе, разделенные символами `&`.
@@ -24,7 +24,7 @@ http://127.0.0.1:8000/items/?skip=0&limit=10
Все те же правила, которые применяются к path-параметрам, также применяются и query-параметрам:
* Поддержка от редактора кода (очевидно)
* <abbr title="преобразование строки, полученной из HTTP запроса в Python данные">"Парсинг"</abbr> данных
* <dfn title="преобразование строки, полученной из HTTP-запроса в данные Python">"Парсинг"</dfn> данных
* Проверка на соответствие данных (Валидация)
* Автоматическая документация
@@ -121,13 +121,13 @@ http://127.0.0.1:8000/items/foo?short=yes
## Обязательные query-параметры { #required-query-parameters }
Когда вы объявляете значение по умолчанию для параметра, который не является path-параметром (в этом разделе, мы пока что познакомились только с path-параметрами), то он не является обязательным.
Когда вы объявляете значение по умолчанию для параметра, который не является path-параметром (в этом разделе мы пока что рассмотрели только query-параметры), то он не является обязательным.
Если вы не хотите задавать конкретное значение, но хотите сделать параметр необязательным, вы можете установить значение по умолчанию равным `None`.
Но если вы хотите сделать query-параметр обязательным, вы можете просто не указывать значение по умолчанию:
{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *}
{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}
Здесь параметр запроса `needy` является обязательным параметром с типом данных `str`.

View File

@@ -20,13 +20,13 @@ $ pip install python-multipart
Импортируйте `File` и `UploadFile` из модуля `fastapi`:
{* ../../docs_src/request_files/tutorial001_an_py39.py hl[3] *}
{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *}
## Определите параметры `File` { #define-file-parameters }
Создайте параметры `File` так же, как вы это делаете для `Body` или `Form`:
{* ../../docs_src/request_files/tutorial001_an_py39.py hl[9] *}
{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}
/// info | Дополнительная информация
@@ -54,7 +54,7 @@ $ pip install python-multipart
Определите параметр файла с типом `UploadFile`:
{* ../../docs_src/request_files/tutorial001_an_py39.py hl[14] *}
{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *}
Использование `UploadFile` имеет ряд преимуществ перед `bytes`:
@@ -122,7 +122,7 @@ contents = myfile.file.read()
Но когда форма включает файлы, она кодируется как multipart/form-data. Если вы используете `File`, **FastAPI** будет знать, что ему нужно получить файлы из нужной части тела.
Если вы хотите узнать больше об этих кодировках и полях форм, перейдите по ссылке <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><abbr title="Mozilla Developer Network Сеть разработчиков Mozilla">MDN</abbr> web docs for <code>POST</code></a>.
Если вы хотите узнать больше об этих кодировках и полях форм, перейдите по ссылке <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><abbr title="Mozilla Developer Network - Сеть разработчиков Mozilla">MDN</abbr> web docs for <code>POST</code></a>.
///
@@ -144,7 +144,7 @@ contents = myfile.file.read()
Вы также можете использовать `File()` вместе с `UploadFile`, например, для установки дополнительных метаданных:
{* ../../docs_src/request_files/tutorial001_03_an_py39.py hl[9,15] *}
{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *}
## Загрузка нескольких файлов { #multiple-file-uploads }
@@ -154,7 +154,7 @@ contents = myfile.file.read()
Для этого необходимо объявить список `bytes` или `UploadFile`:
{* ../../docs_src/request_files/tutorial002_an_py39.py hl[10,15] *}
{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *}
Вы получите, как и было объявлено, список `list` из `bytes` или `UploadFile`.
@@ -170,7 +170,7 @@ contents = myfile.file.read()
Так же, как и раньше, вы можете использовать `File()` для задания дополнительных параметров, даже для `UploadFile`:
{* ../../docs_src/request_files/tutorial003_an_py39.py hl[11,18:20] *}
{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *}
## Резюме { #recap }

View File

@@ -24,7 +24,7 @@ $ pip install python-multipart
Вам просто нужно объявить **Pydantic-модель** с полями, которые вы хотите получить как **поля формы**, а затем объявить параметр как `Form`:
{* ../../docs_src/request_form_models/tutorial001_an_py39.py hl[9:11,15] *}
{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *}
**FastAPI** **извлечёт** данные для **каждого поля** из **данных формы** в запросе и выдаст вам объявленную Pydantic-модель.
@@ -48,7 +48,7 @@ $ pip install python-multipart
Вы можете сконфигурировать Pydantic-модель так, чтобы запретить (`forbid`) все дополнительные (`extra`) поля:
{* ../../docs_src/request_form_models/tutorial002_an_py39.py hl[12] *}
{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *}
Если клиент попробует отправить дополнительные данные, то в ответ он получит **ошибку**.

View File

@@ -16,13 +16,13 @@ $ pip install python-multipart
## Импортируйте `File` и `Form` { #import-file-and-form }
{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[3] *}
{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *}
## Определите параметры `File` и `Form` { #define-file-and-form-parameters }
Создайте параметры файла и формы таким же образом, как для `Body` или `Query`:
{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[10:12] *}
{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *}
Файлы и поля формы будут загружены в виде данных формы, и вы получите файлы и поля формы.

View File

@@ -18,17 +18,17 @@ $ pip install python-multipart
Импортируйте `Form` из `fastapi`:
{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[3] *}
{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *}
## Определение параметров `Form` { #define-form-parameters }
Создайте параметры формы так же, как это делается для `Body` или `Query`:
{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[9] *}
{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *}
Например, в одном из способов использования спецификации OAuth2 (называемом «потоком пароля») требуется отправить `username` и `password` в виде полей формы.
Например, в одном из способов использования спецификации OAuth2 (называемом «password flow» - аутентификация по паролю) требуется отправить `username` и `password` в виде полей формы.
<abbr title="specification спецификация">spec</abbr> требует, чтобы поля были строго названы `username` и `password` и отправлялись как поля формы, а не JSON.
<dfn title="спецификация">спецификация</dfn> требует, чтобы поля были строго названы `username` и `password` и отправлялись как поля формы, а не JSON.
С помощью `Form` вы можете объявить те же настройки, что и с `Body``Query`, `Path`, `Cookie`), включая валидацию, примеры, псевдоним (например, `user-name` вместо `username`) и т.д.
@@ -56,7 +56,7 @@ $ pip install python-multipart
Но когда форма содержит файлы, она кодируется как `multipart/form-data`. О работе с файлами вы прочтёте в следующей главе.
Если вы хотите узнать больше про эти кодировки и поля формы, обратитесь к <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><abbr title="Mozilla Developer Network Сеть разработчиков Mozilla">MDN</abbr> веб-документации для `POST`</a>.
Если вы хотите узнать больше про эти кодировки и поля формы, обратитесь к <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><abbr title="Mozilla Developer Network - Сеть разработчиков Mozilla">MDN</abbr> веб-документации для `POST`</a>.
///

View File

@@ -183,7 +183,7 @@ FastAPI делает несколько вещей внутри вместе с
Самый распространённый случай — [возвращать Response напрямую, как описано далее в разделах документации для продвинутых](../advanced/response-directly.md){.internal-link target=_blank}.
{* ../../docs_src/response_model/tutorial003_02_py39.py hl[8,10:11] *}
{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}
Этот простой случай обрабатывается FastAPI автоматически, потому что аннотация возвращаемого типа — это класс (или подкласс) `Response`.
@@ -193,7 +193,7 @@ FastAPI делает несколько вещей внутри вместе с
Вы также можете использовать подкласс `Response` в аннотации типа:
{* ../../docs_src/response_model/tutorial003_03_py39.py hl[8:9] *}
{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}
Это тоже сработает, так как `RedirectResponse` — подкласс `Response`, и FastAPI автоматически обработает этот простой случай.
@@ -201,7 +201,7 @@ FastAPI делает несколько вещей внутри вместе с
Но когда вы возвращаете произвольный объект, не являющийся валидным типом Pydantic (например, объект базы данных), и аннотируете его таким образом в функции, FastAPI попытается создать модель ответа Pydantic из этой аннотации типа и потерпит неудачу.
То же произойдёт, если у вас будет что-то вроде <abbr title='Объединение нескольких типов означает «любой из этих типов».'>union</abbr> разных типов, где один или несколько не являются валидными типами Pydantic, например, это приведёт к ошибке 💥:
То же произойдёт, если у вас будет что-то вроде <dfn title="Объединение нескольких типов означает «любой из этих типов».">union</dfn> разных типов, где один или несколько не являются валидными типами Pydantic, например, это приведёт к ошибке 💥:
{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}

View File

@@ -8,7 +8,7 @@
* `@app.delete()`
* и других.
{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *}
{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}
/// note | Примечание
@@ -66,7 +66,7 @@ FastAPI знает об этом и создаст документацию Open
/// tip | Подсказка
Чтобы узнать больше о HTTP кодах статуса и о том, для чего каждый из них предназначен, ознакомьтесь с <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status" class="external-link" target="_blank"><abbr title="Mozilla Developer Network Сеть разработчиков Mozilla">MDN</abbr> документацией об HTTP статус-кодах</a>.
Чтобы узнать больше о HTTP кодах статуса и о том, для чего каждый из них предназначен, ознакомьтесь с <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status" class="external-link" target="_blank"><abbr title="Mozilla Developer Network - Сеть разработчиков Mozilla">MDN</abbr> документацией об HTTP статус-кодах</a>.
///
@@ -74,7 +74,7 @@ FastAPI знает об этом и создаст документацию Open
Рассмотрим предыдущий пример еще раз:
{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *}
{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}
`201` это код статуса "Создано".
@@ -82,7 +82,7 @@ FastAPI знает об этом и создаст документацию Open
Для удобства вы можете использовать переменные из `fastapi.status`.
{* ../../docs_src/response_status_code/tutorial002_py39.py hl[1,6] *}
{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}
Они содержат те же числовые значения, но позволяют использовать автозавершение редактора кода для выбора кода статуса:
@@ -90,7 +90,7 @@ FastAPI знает об этом и создаст документацию Open
/// note | Технические детали
Вы также можете использовать `from starlette import status` вместо `from fastapi import status`.
Вы также можете использовать `from starlette import status`.
**FastAPI** позволяет использовать как `starlette.status`, так и `fastapi.status` исключительно для удобства разработчиков. Но поставляется fastapi.status непосредственно из Starlette.

View File

@@ -74,7 +74,7 @@ OpenAPI 3.1.0 (используется начиная с FastAPI 0.99.0) доб
Когда вы делаете это, примеры становятся частью внутренней **JSON Schema** для данных тела запроса.
Тем не менее, на <abbr title="2023-08-26">момент написания этого</abbr> Swagger UI, инструмент, отвечающий за отображение UI документации, не поддерживает показ нескольких примеров для данных в **JSON Schema**. Но ниже есть обходной путь.
Тем не менее, на <dfn title="2023-08-26">момент написания этого</dfn> Swagger UI, инструмент, отвечающий за отображение UI документации, не поддерживает показ нескольких примеров для данных в **JSON Schema**. Но ниже есть обходной путь.
### Специфические для OpenAPI `examples` { #openapi-specific-examples }

View File

@@ -20,7 +20,7 @@
Скопируйте пример в файл `main.py`:
{* ../../docs_src/security/tutorial001_an_py39.py *}
{* ../../docs_src/security/tutorial001_an_py310.py *}
## Запуск { #run-it }
@@ -132,7 +132,7 @@ OAuth2 был спроектирован так, чтобы бэкенд или
При создании экземпляра класса `OAuth2PasswordBearer` мы передаем параметр `tokenUrl`. Этот параметр содержит URL, который клиент (фронтенд, работающий в браузере пользователя) будет использовать для отправки `username` и `password`, чтобы получить токен.
{* ../../docs_src/security/tutorial001_an_py39.py hl[8] *}
{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *}
/// tip | Подсказка
@@ -170,7 +170,7 @@ oauth2_scheme(some, parameters)
Теперь вы можете передать `oauth2_scheme` как зависимость с `Depends`.
{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}
Эта зависимость предоставит `str`, который будет присвоен параметру `token` *функции-обработчика пути*.

View File

@@ -2,7 +2,7 @@
В предыдущей главе система безопасности (основанная на системе внедрения зависимостей) передавала *функции-обработчику пути* `token` типа `str`:
{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}
Но это всё ещё не слишком полезно.

View File

@@ -1,56 +1,56 @@
# Настройка авторизации { #security }
# Безопасность { #security }
Существует множество способов обеспечения безопасности, аутентификации и авторизации.
Обычно эта тема является достаточно сложной и трудной.
Обычно эта тема является достаточно сложной и «трудной».
Во многих фреймворках и системах только работа с определением доступов к приложению и аутентификацией требует значительных затрат усилий и написания множества кода (во многих случаях его объём может составлять более 50% от всего написанного кода).
Во многих фреймворках и системах только работа с безопасностью и аутентификацией требует значительных затрат усилий и написания множества кода (во многих случаях его объём может составлять 50% или более от всего написанного кода).
**FastAPI** предоставляет несколько инструментов, которые помогут вам настроить **Авторизацию** легко, быстро, стандартным способом, без необходимости изучать все её тонкости.
**FastAPI** предоставляет несколько инструментов, которые помогут вам работать с **безопасностью** легко, быстро, стандартным способом, без необходимости изучать и разбираться во всех спецификациях по безопасности.
Но сначала давайте рассмотрим некоторые небольшие концепции.
Но сначала давайте рассмотрим несколько небольших концепций.
## Куда-то торопишься? { #in-a-hurry }
## Нет времени? { #in-a-hurry }
Если вам не нужна информация о каких-либо из следующих терминов и вам просто нужно добавить защиту с аутентификацией на основе логина и пароля *прямо сейчас*, переходите к следующим главам.
Если вам не важны какие-либо из этих терминов и вам просто нужно добавить защиту с аутентификацией на основе имени пользователя и пароля прямо сейчас, переходите к следующим главам.
## OAuth2 { #oauth2 }
OAuth2 - это протокол, который определяет несколько способов обработки аутентификации и авторизации.
OAuth2 - это спецификация, которая определяет несколько способов обработки аутентификации и авторизации.
Он довольно обширен и охватывает несколько сложных вариантов использования.
Это довольно обширная спецификация, охватывающая несколько сложных вариантов использования.
OAuth2 включает в себя способы аутентификации с использованием "третьей стороны".
Она включает способы аутентификации с использованием «третьей стороны».
Это то, что используют под собой все кнопки "вход с помощью Facebook, Google, X (Twitter), GitHub" на страницах авторизации.
Именно это используется во всех системах с кнопками «войти с помощью Facebook, Google, X (Twitter), GitHub».
### OAuth 1 { #oauth-1 }
Ранее использовался протокол OAuth 1, который сильно отличается от OAuth2 и является более сложным, поскольку он включал прямые описания того, как шифровать сообщение.
Ранее использовался OAuth 1, который сильно отличается от OAuth2 и является более сложным, поскольку он включал прямые спецификации того, как шифровать обмен данными.
В настоящее время он не очень популярен и не используется.
OAuth2 не указывает, как шифровать сообщение, он ожидает, что ваше приложение будет обслуживаться по протоколу HTTPS.
OAuth2 не указывает, как шифровать обмен данными, он ожидает, что ваше приложение будет обслуживаться по протоколу HTTPS.
/// tip | Подсказка
В разделе **Развертывание** вы увидите как настроить протокол HTTPS бесплатно, используя Traefik и Let's Encrypt.
В разделе о **развертывании** вы увидите, как настроить HTTPS бесплатно, используя Traefik и Let's Encrypt.
///
## OpenID Connect { #openid-connect }
OpenID Connect - это еще один протокол, основанный на **OAuth2**.
OpenID Connect это ещё одна спецификация, основанная на **OAuth2**.
Он просто расширяет OAuth2, уточняя некоторые вещи, не имеющие однозначного определения в OAuth2, в попытке сделать его более совместимым.
Она просто расширяет OAuth2, уточняя некоторые вещи, которые относительно неоднозначны в OAuth2, стараясь сделать его более совместимым.
Например, для входа в Google используется OpenID Connect (который под собой использует OAuth2).
Например, для входа в Google используется OpenID Connect (который под капотом использует OAuth2).
Но вход в Facebook не поддерживает OpenID Connect. У него есть собственная вариация OAuth2.
### OpenID (не "OpenID Connect") { #openid-not-openid-connect }
### OpenID (не «OpenID Connect») { #openid-not-openid-connect }
Также ранее использовался стандарт "OpenID", который пытался решить ту же проблему, что и **OpenID Connect**, но не был основан на OAuth2.
Также ранее использовалась спецификация «OpenID», которая пыталась решить ту же задачу, что и **OpenID Connect**, но не была основана на OAuth2.
Таким образом, это была полноценная дополнительная система.
@@ -62,45 +62,45 @@ OpenAPI (ранее известный как Swagger) - это открытая
**FastAPI** основан на **OpenAPI**.
Это то, что делает возможным наличие множества автоматических интерактивных интерфейсов документирования, сгенерированного кода и т.д.
Это то, что делает возможными несколько автоматических интерактивных интерфейсов документации, генерацию кода и т.д.
В OpenAPI есть способ использовать несколько "схем" безопасности.
В OpenAPI есть способ определить несколько «схем» безопасности.
Таким образом, вы можете воспользоваться преимуществами Всех этих стандартных инструментов, включая интерактивные системы документирования.
Используя их, вы можете воспользоваться преимуществами всех этих инструментов, основанных на стандартах, включая интерактивные системы документирования.
OpenAPI может использовать следующие схемы авторизации:
OpenAPI определяет следующие схемы безопасности:
* `apiKey`: уникальный идентификатор для приложения, который может быть получен из:
* Параметров запроса.
* Заголовка.
* Cookies.
* `http`: стандартные системы аутентификации по протоколу HTTP, включая:
* `bearer`: заголовок `Authorization` со значением `Bearer {уникальный токен}`. Это унаследовано от OAuth2.
* Базовая аутентификация по протоколу HTTP.
* `apiKey`: специфичный для приложения ключ, который может поступать из:
* параметра запроса.
* HTTP-заголовка.
* cookie.
* `http`: стандартные системы аутентификации по HTTP, включая:
* `bearer`: HTTP-заголовок `Authorization` со значением `Bearer ` плюс токен. Это унаследовано от OAuth2.
* Базовая аутентификация по HTTP.
* HTTP Digest и т.д.
* `oauth2`: все способы обеспечения безопасности OAuth2 называемые "потоки" (англ. "flows").
* Некоторые из этих "потоков" подходят для реализации аутентификации через сторонний сервис использующий OAuth 2.0 (например, Google, Facebook, X (Twitter), GitHub и т.д.):
* `oauth2`: все способы OAuth2 для обеспечения безопасности (называются «потоками»).
* Несколько из этих «потоков» подходят для построения провайдера аутентификации OAuth 2.0 (например, Google, Facebook, X (Twitter), GitHub и т.д.):
* `implicit`
* `clientCredentials`
* `authorizationCode`
* Но есть один конкретный "поток", который может быть идеально использован для обработки аутентификации непосредственно в том же приложении:
* `password`: в некоторых следующих главах будут рассмотрены примеры этого.
* `openIdConnect`: способ определить, как автоматически обнаруживать данные аутентификации OAuth2.
* Это автоматическое обнаружение определено в спецификации OpenID Connect.
* Но есть один конкретный «поток», который можно идеально использовать для обработки аутентификации непосредственно в этом же приложении:
* `password`: в некоторых следующих главах будут приведены примеры.
* `openIdConnect`: имеет способ определить, как автоматически обнаруживать данные аутентификации OAuth2.
* Именно это автоматическое обнаружение определено в спецификации OpenID Connect.
/// tip | Подсказка
Интеграция сторонних сервисов для аутентификации/авторизации таких как Google, Facebook, X (Twitter), GitHub и т.д. осуществляется достаточно легко.
Интеграция сторонних провайдеров аутентификации/авторизации, таких как Google, Facebook, X (Twitter), GitHub и т.д., также возможна и относительно проста.
Самой сложной проблемой является создание такого провайдера аутентификации/авторизации, но **FastAPI** предоставляет вам инструменты, позволяющие легко это сделать, выполняя при этом всю тяжелую работу за вас.
Самой сложной задачей является создание такого провайдера аутентификации/авторизации, но **FastAPI** предоставляет вам инструменты, позволяющие легко это сделать, выполняя при этом всю тяжёлую работу за вас.
///
## Преимущества **FastAPI** { #fastapi-utilities }
## Инструменты **FastAPI** { #fastapi-utilities }
Fast API предоставляет несколько инструментов для каждой из этих схем безопасности в модуле `fastapi.security`, которые упрощают использование этих механизмов безопасности.
FastAPI предоставляет несколько инструментов для каждой из этих схем безопасности в модуле `fastapi.security`, которые упрощают использование этих механизмов безопасности.
В следующих главах вы увидите, как обезопасить свой API, используя инструменты, предоставляемые **FastAPI**.
В следующих главах вы увидите, как добавить безопасность в ваш API, используя инструменты, предоставляемые **FastAPI**.
И вы также увидите, как он автоматически интегрируется в систему интерактивной документации.
И вы также увидите, как это автоматически интегрируется в систему интерактивной документации.

View File

@@ -1,10 +1,10 @@
# OAuth2 с паролем (и хешированием), Bearer с JWT-токенами { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }
Теперь, когда у нас определен процесс обеспечения безопасности, давайте сделаем приложение действительно безопасным, используя токены <abbr title="JSON Web Tokens веб‑токены JSON">JWT</abbr> и безопасное хеширование паролей.
Теперь, когда у нас определен процесс обеспечения безопасности, давайте сделаем приложение действительно безопасным, используя токены <abbr title="JSON Web Tokens - веб‑токены JSON">JWT</abbr> и безопасное хеширование паролей.
Этот код можно реально использовать в своем приложении, сохранять хэши паролей в базе данных и т.д.
Мы продолжим разбираться, начиная с того места, на котором остановились в предыдущей главе.
Мы продолжим разбираться, начиная с того места, на котором остановились в предыдущей главе, и расширим его.
## Про JWT { #about-jwt }
@@ -43,9 +43,11 @@ $ pip install pyjwt
</div>
/// info | Дополнительная информация
Если вы планируете использовать алгоритмы цифровой подписи, такие как RSA или ECDSA, вам следует установить зависимость библиотеки криптографии `pyjwt[crypto]`.
Подробнее об этом можно прочитать в <a href="https://pyjwt.readthedocs.io/en/latest/installation.html" class="external-link" target="_blank">документации по установке PyJWT</a>.
///
## Хеширование паролей { #password-hashing }
@@ -83,11 +85,13 @@ $ pip install "pwdlib[argon2]"
</div>
/// tip | Подсказка
С помощью `pwdlib` можно даже настроить его на чтение паролей, созданных **Django**, плагином безопасности **Flask** или многими другими библиотеками.
Таким образом, вы сможете, например, совместно использовать одни и те же данные из приложения Django в базе данных с приложением FastAPI. Или постепенно мигрировать Django-приложение, используя ту же базу данных.
При этом пользователи смогут одновременно входить в систему как из приложения Django, так и из приложения **FastAPI**.
///
## Хеширование и проверка паролей { #hash-and-verify-the-passwords }
@@ -97,11 +101,13 @@ $ pip install "pwdlib[argon2]"
Создайте экземпляр PasswordHash с рекомендованными настройками — он будет использоваться для хэширования и проверки паролей.
/// tip | Подсказка
pwdlib также поддерживает алгоритм хеширования bcrypt, но не включает устаревшие алгоритмы — для работы с устаревшими хэшами рекомендуется использовать библиотеку passlib.
Например, вы можете использовать ее для чтения и проверки паролей, сгенерированных другой системой (например, Django), но хэшировать все новые пароли другим алгоритмом, например Argon2 или Bcrypt.
И при этом быть совместимым со всеми этими системами.
///
Создайте служебную функцию для хэширования пароля, поступающего от пользователя.
@@ -110,10 +116,16 @@ pwdlib также поддерживает алгоритм хешировани
И еще одну — для аутентификации и возврата пользователя.
{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *}
{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}
Когда `authenticate_user` вызывается с именем пользователя, которого нет в базе данных, мы все равно запускаем `verify_password` с использованием фиктивного хэша.
Это гарантирует, что эндпоинт отвечает примерно за одно и то же время вне зависимости от того, существует имя пользователя или нет, предотвращая тайминговые атаки (атака по времени), с помощью которых можно было бы перечислять существующие имена пользователей.
/// note | Технические детали
Если проверить новую (фальшивую) базу данных `fake_users_db`, то можно увидеть, как теперь выглядит хэшированный пароль: `"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc"`.
///
## Работа с JWT токенами { #handle-jwt-tokens }
@@ -144,7 +156,7 @@ $ openssl rand -hex 32
Создайте служебную функцию для генерации нового токена доступа.
{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *}
{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}
## Обновление зависимостей { #update-the-dependencies }
@@ -154,7 +166,7 @@ $ openssl rand -hex 32
Если токен недействителен, то сразу же верните HTTP-ошибку.
{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *}
{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}
## Обновление *операции пути* `/token` { #update-the-token-path-operation }
@@ -162,7 +174,7 @@ $ openssl rand -hex 32
Создайте реальный токен доступа JWT и верните его
{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *}
{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}
### Технические подробности о JWT ключе `sub` { #technical-details-about-the-jwt-subject-sub }
@@ -202,7 +214,9 @@ Username: `johndoe`
Password: `secret`
/// check | Проверка
Обратите внимание, что нигде в коде не используется открытый текст пароля "`secret`", мы используем только его хэшированную версию.
///
<img src="/img/tutorial/security/image08.png">
@@ -225,7 +239,9 @@ Password: `secret`
<img src="/img/tutorial/security/image10.png">
/// note | Техническая информация
Обратите внимание на HTTP-заголовок `Authorization`, значение которого начинается с `Bearer `.
///
## Продвинутое использование `scopes` { #advanced-usage-with-scopes }

View File

@@ -236,7 +236,7 @@ UserInDB(
<img src="/img/tutorial/security/image06.png">
Если щёлкнуть на значке замка и выйти из системы, а затем попытаться выполнить ту же операцию ещё раз, будет выдана ошибка HTTP 401:
Если щёлкнуть на значке замка и выйти из системы, а затем попробовать выполнить ту же операцию ещё раз, будет выдана ошибка HTTP 401:
```JSON
{

View File

@@ -8,7 +8,7 @@
/// tip | Подсказка
Вы можете использовать любую другую библиотеку для работы с SQL или NoSQL базами данных (иногда их называют <abbr title="Object Relational Mapper Объектно-реляционный маппер: термин для библиотеки, где некоторые классы представляют SQL-таблицы, а экземпляры представляют строки в этих таблицах">"ORMs"</abbr>), FastAPI ничего не навязывает. 😎
Вы можете использовать любую другую библиотеку для работы с SQL или NoSQL базами данных (иногда их называют <abbr title="Object Relational Mapper - Объектно-реляционный маппер: термин для библиотеки, где некоторые классы представляют SQL-таблицы, а экземпляры представляют строки в этих таблицах">"ORMs"</abbr>), FastAPI ничего не навязывает. 😎
///
@@ -344,7 +344,7 @@ $ fastapi dev main.py
</div>
Если вы перейдёте в UI API `/docs`, вы увидите, что он обновился: теперь при создании героя он не ожидает получить `id` от клиента и т. д.
Если вы перейдёте в UI API `/docs`, вы увидите, что он обновился: теперь при создании героя он не ожидает получить `id` от клиента и т.д.
<div class="screenshot">
<img src="/img/tutorial/sql-databases/image02.png">
@@ -354,4 +354,4 @@ $ fastapi dev main.py
Вы можете использовать <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">**SQLModel**</a> для взаимодействия с SQL базой данных и упростить код с помощью *моделей данных* и *моделей-таблиц*.
Гораздо больше вы можете узнать в документации **SQLModel**, там есть более подробный мини-<a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/" class="external-link" target="_blank">туториал по использованию SQLModel с **FastAPI**</a>. 🚀
Гораздо больше вы можете узнать в документации **SQLModel**, там есть более подробное мини-<a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/" class="external-link" target="_blank">руководство по использованию SQLModel с **FastAPI**</a>. 🚀

View File

@@ -7,7 +7,7 @@
* Импортируйте `StaticFiles`.
* "Примонтируйте" экземпляр `StaticFiles()` к определённому пути.
{* ../../docs_src/static_files/tutorial001_py39.py hl[2,6] *}
{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}
/// note | Технические детали

View File

@@ -30,7 +30,7 @@ $ pip install httpx
Напишите простое утверждение с `assert` дабы проверить истинность Python-выражения (это тоже стандарт `pytest`).
{* ../../docs_src/app_testing/tutorial001_py39.py hl[2,12,15:18] *}
{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}
/// tip | Подсказка
@@ -76,7 +76,7 @@ $ pip install httpx
В файле `main.py` находится Ваше приложение **FastAPI**:
{* ../../docs_src/app_testing/app_a_py39/main.py *}
{* ../../docs_src/app_testing/app_a_py310/main.py *}
### Файл тестов { #testing-file }
@@ -92,7 +92,7 @@ $ pip install httpx
Так как оба файла находятся в одной директории, для импорта объекта приложения из файла `main` в файл `test_main` Вы можете использовать относительный импорт:
{* ../../docs_src/app_testing/app_a_py39/test_main.py hl[3] *}
{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}
...и писать дальше тесты, как и раньше.
@@ -119,7 +119,7 @@ $ pip install httpx
Ещё есть операция `POST`, и она может вернуть несколько ошибок.
Обе *операции пути* требуют наличия в запросе заголовка `X-Token`.
Обе *операции пути* требуют наличия в запросе HTTP-заголовка `X-Token`.
{* ../../docs_src/app_testing/app_b_an_py310/main.py *}
@@ -139,7 +139,7 @@ $ pip install httpx
* Передаёте *path*-параметры или *query*-параметры, вписав их непосредственно в строку URL.
* Передаёте JSON в теле запроса, передав Python-объект (например: `dict`) через именованный параметр `json`.
* Если же Вам необходимо отправить *форму с данными* вместо JSON, то используйте параметр `data` вместо `json`.
* Для передачи *заголовков*, передайте объект `dict` через параметр `headers`.
* Для передачи *HTTP-заголовков*, передайте объект `dict` через параметр `headers`.
* Для передачи *cookies* также передайте `dict`, но через параметр `cookies`.
Для получения дополнительной информации о передаче данных на бэкенд с помощью `httpx` или `TestClient` ознакомьтесь с <a href="https://www.python-httpx.org" class="external-link" target="_blank">документацией HTTPX</a>.

View File

@@ -53,7 +53,7 @@ $ cd awesome-project
## Создание виртуального окружения { #create-a-virtual-environment }
Когда вы начинаете работать над Pythonпроектом **впервые**, создайте виртуальное окружение **<abbr title="есть и другие опции, но это простой ориентир">внутри вашего проекта</abbr>**.
Когда вы начинаете работать над Pythonпроектом **впервые**, создайте виртуальное окружение **<dfn title="есть и другие опции, но это простой ориентир">внутри вашего проекта</dfn>**.
/// tip | Подсказка
@@ -166,7 +166,7 @@ $ source .venv/Scripts/activate
Каждый раз, когда вы устанавливаете **новый пакет** в это окружение, **активируйте** окружение снова.
Это гарантирует, что если вы используете **программу терминала (<abbr title="command line interface интерфейс командной строки">CLI</abbr>)**, установленную этим пакетом, вы будете использовать именно ту, что из вашего виртуального окружения, а не какую‑то глобально установленную, возможно другой версии, чем вам нужна.
Это гарантирует, что если вы используете **программу терминала (<abbr title="command line interface - интерфейс командной строки">CLI</abbr>)**, установленную этим пакетом, вы будете использовать именно ту, что из вашего виртуального окружения, а не какую‑то глобально установленную, возможно другой версии, чем вам нужна.
///

View File

@@ -48,6 +48,8 @@ class UserInDB(User):
password_hash = PasswordHash.recommended()
DUMMY_HASH = password_hash.hash("dummypassword")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
app = FastAPI()
@@ -70,6 +72,7 @@ def get_user(db, username: str):
def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username)
if not user:
verify_password(password, DUMMY_HASH)
return False
if not verify_password(password, user.hashed_password):
return False

View File

@@ -47,6 +47,8 @@ class UserInDB(User):
password_hash = PasswordHash.recommended()
DUMMY_HASH = password_hash.hash("dummypassword")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
app = FastAPI()
@@ -69,6 +71,7 @@ def get_user(db, username: str):
def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username)
if not user:
verify_password(password, DUMMY_HASH)
return False
if not verify_password(password, user.hashed_password):
return False

View File

@@ -60,6 +60,8 @@ class UserInDB(User):
password_hash = PasswordHash.recommended()
DUMMY_HASH = password_hash.hash("dummypassword")
oauth2_scheme = OAuth2PasswordBearer(
tokenUrl="token",
scopes={"me": "Read information about the current user.", "items": "Read items."},
@@ -85,6 +87,7 @@ def get_user(db, username: str):
def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username)
if not user:
verify_password(password, DUMMY_HASH)
return False
if not verify_password(password, user.hashed_password):
return False

View File

@@ -59,6 +59,8 @@ class UserInDB(User):
password_hash = PasswordHash.recommended()
DUMMY_HASH = password_hash.hash("dummypassword")
oauth2_scheme = OAuth2PasswordBearer(
tokenUrl="token",
scopes={"me": "Read information about the current user.", "items": "Read items."},
@@ -84,6 +86,7 @@ def get_user(db, username: str):
def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username)
if not user:
verify_password(password, DUMMY_HASH)
return False
if not verify_password(password, user.hashed_password):
return False