Browse Source
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Vladislav Kramorenko <[email protected]>pull/9612/head
committed by
GitHub
2 changed files with 252 additions and 0 deletions
@ -0,0 +1,251 @@ |
|||
# Path-параметры |
|||
|
|||
Вы можете определить "параметры" или "переменные" пути, используя синтаксис форматированных строк Python: |
|||
|
|||
```Python hl_lines="6-7" |
|||
{!../../../docs_src/path_params/tutorial001.py!} |
|||
``` |
|||
|
|||
Значение параметра пути `item_id` будет передано в функцию в качестве аргумента `item_id`. |
|||
|
|||
Если запустите этот пример и перейдёте по адресу: <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a>, то увидите ответ: |
|||
|
|||
```JSON |
|||
{"item_id":"foo"} |
|||
``` |
|||
|
|||
## Параметры пути с типами |
|||
|
|||
Вы можете объявить тип параметра пути в функции, используя стандартные аннотации типов Python. |
|||
|
|||
```Python hl_lines="7" |
|||
{!../../../docs_src/path_params/tutorial002.py!} |
|||
``` |
|||
|
|||
Здесь, `item_id` объявлен типом `int`. |
|||
|
|||
!!! check "Заметка" |
|||
Это обеспечит поддержку редактора внутри функции (проверка ошибок, автодополнение и т.п.). |
|||
|
|||
## <abbr title="Или сериализация, парсинг">Преобразование</abbr> данных |
|||
|
|||
Если запустите этот пример и перейдёте по адресу: <a href="http://127.0.0.1:8000/items/3" class="external-link" target="_blank">http://127.0.0.1:8000/items/3</a>, то увидите ответ: |
|||
|
|||
```JSON |
|||
{"item_id":3} |
|||
``` |
|||
|
|||
!!! check "Заметка" |
|||
Обратите внимание на значение `3`, которое получила (и вернула) функция. Это целочисленный Python `int`, а не строка `"3"`. |
|||
|
|||
Используя определения типов, **FastAPI** выполняет автоматический <abbr title="преобразование строк из HTTP-запроса в типы данных Python">"парсинг"</abbr> запросов. |
|||
|
|||
## <abbr title="Или валидация">Проверка</abbr> данных |
|||
|
|||
Если откроете браузер по адресу <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a>, то увидите интересную HTTP-ошибку: |
|||
|
|||
```JSON |
|||
{ |
|||
"detail": [ |
|||
{ |
|||
"loc": [ |
|||
"path", |
|||
"item_id" |
|||
], |
|||
"msg": "value is not a valid integer", |
|||
"type": "type_error.integer" |
|||
} |
|||
] |
|||
} |
|||
``` |
|||
|
|||
из-за того, что параметр пути `item_id` имеет значение `"foo"`, которое не является типом `int`. |
|||
|
|||
Та же ошибка возникнет, если вместо `int` передать `float` , например: <a href="http://127.0.0.1:8000/items/4.2" class="external-link" target="_blank">http://127.0.0.1:8000/items/4.2</a> |
|||
|
|||
!!! check "Заметка" |
|||
**FastAPI** обеспечивает проверку типов, используя всё те же определения типов. |
|||
|
|||
Обратите внимание, что в тексте ошибки явно указано место не прошедшее проверку. |
|||
|
|||
Это очень полезно при разработке и отладке кода, который взаимодействует с API. |
|||
|
|||
## Документация |
|||
|
|||
И теперь, когда откроете браузер по адресу: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, то увидите вот такую автоматически сгенерированную документацию API: |
|||
|
|||
<img src="/img/tutorial/path-params/image01.png"> |
|||
|
|||
!!! check "Заметка" |
|||
Ещё раз, просто используя определения типов, **FastAPI** обеспечивает автоматическую интерактивную документацию (с интеграцией Swagger UI). |
|||
|
|||
Обратите внимание, что параметр пути объявлен целочисленным. |
|||
|
|||
## Преимущества стандартизации, альтернативная документация |
|||
|
|||
Поскольку сгенерированная схема соответствует стандарту <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md" class="external-link" target="_blank">OpenAPI</a>, её можно использовать со множеством совместимых инструментов. |
|||
|
|||
Именно поэтому, FastAPI сам предоставляет альтернативную документацию API (используя ReDoc), которую можно получить по адресу: <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>. |
|||
|
|||
<img src="/img/tutorial/path-params/image02.png"> |
|||
|
|||
По той же причине, есть множество совместимых инструментов, включая инструменты генерации кода для многих языков. |
|||
|
|||
## Pydantic |
|||
|
|||
Вся проверка данных выполняется под капотом с помощью <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a>. Поэтому вы можете быть уверены в качестве обработки данных. |
|||
|
|||
Вы можете использовать в аннотациях как простые типы данных, вроде `str`, `float`, `bool`, так и более сложные типы. |
|||
|
|||
Некоторые из них рассматриваются в следующих главах данного руководства. |
|||
|
|||
## Порядок имеет значение |
|||
|
|||
При создании *операций пути* можно столкнуться с ситуацией, когда путь является фиксированным. |
|||
|
|||
Например, `/users/me`. Предположим, что это путь для получения данных о текущем пользователе. |
|||
|
|||
У вас также может быть путь `/users/{user_id}`, чтобы получить данные о конкретном пользователе по его ID. |
|||
|
|||
Поскольку *операции пути* выполняются в порядке их объявления, необходимо, чтобы путь для `/users/me` был объявлен раньше, чем путь для `/users/{user_id}`: |
|||
|
|||
|
|||
```Python hl_lines="6 11" |
|||
{!../../../docs_src/path_params/tutorial003.py!} |
|||
``` |
|||
|
|||
Иначе путь для `/users/{user_id}` также будет соответствовать `/users/me`, "подразумевая", что он получает параметр `user_id` со значением `"me"`. |
|||
|
|||
Аналогично, вы не можете переопределить операцию с путем: |
|||
|
|||
```Python hl_lines="6 11" |
|||
{!../../../docs_src/path_params/tutorial003b.py!} |
|||
``` |
|||
|
|||
Первый будет выполняться всегда, так как путь совпадает первым. |
|||
|
|||
## Предопределенные значения |
|||
|
|||
Что если нам нужно заранее определить допустимые *параметры пути*, которые *операция пути* может принимать? В таком случае можно использовать стандартное перечисление <abbr title="Enumeration">`Enum`</abbr> Python. |
|||
|
|||
### Создание класса `Enum` |
|||
|
|||
Импортируйте `Enum` и создайте подкласс, который наследуется от `str` и `Enum`. |
|||
|
|||
Мы наследуемся от `str`, чтобы документация API могла понять, что значения должны быть типа `string` и отображалась правильно. |
|||
|
|||
Затем создайте атрибуты класса с фиксированными допустимыми значениями: |
|||
|
|||
```Python hl_lines="1 6-9" |
|||
{!../../../docs_src/path_params/tutorial005.py!} |
|||
``` |
|||
|
|||
!!! info "Дополнительная информация" |
|||
<a href="https://docs.python.org/3/library/enum.html" class="external-link" target="_blank">Перечисления (enum) доступны в Python</a> начиная с версии 3.4. |
|||
|
|||
!!! tip "Подсказка" |
|||
Если интересно, то "AlexNet", "ResNet" и "LeNet" - это названия <abbr title="Технически, это архитектуры моделей глубокого обучения">моделей</abbr> машинного обучения. |
|||
|
|||
### Определение *параметра пути* |
|||
|
|||
Определите *параметр пути*, используя в аннотации типа класс перечисления (`ModelName`), созданный ранее: |
|||
|
|||
```Python hl_lines="16" |
|||
{!../../../docs_src/path_params/tutorial005.py!} |
|||
``` |
|||
|
|||
### Проверьте документацию |
|||
|
|||
Поскольку доступные значения *параметра пути* определены заранее, интерактивная документация может наглядно их отображать: |
|||
|
|||
<img src="/img/tutorial/path-params/image03.png"> |
|||
|
|||
### Работа с *перечислениями* в Python |
|||
|
|||
Значение *параметра пути* будет *элементом перечисления*. |
|||
|
|||
#### Сравнение *элементов перечисления* |
|||
|
|||
Вы можете сравнить это значение с *элементом перечисления* класса `ModelName`: |
|||
|
|||
```Python hl_lines="17" |
|||
{!../../../docs_src/path_params/tutorial005.py!} |
|||
``` |
|||
|
|||
#### Получение *значения перечисления* |
|||
|
|||
Можно получить фактическое значение (в данном случае - `str`) с помощью `model_name.value` или в общем случае `your_enum_member.value`: |
|||
|
|||
```Python hl_lines="20" |
|||
{!../../../docs_src/path_params/tutorial005.py!} |
|||
``` |
|||
|
|||
!!! tip "Подсказка" |
|||
Значение `"lenet"` также можно получить с помощью `ModelName.lenet.value`. |
|||
|
|||
#### Возврат *элементов перечисления* |
|||
|
|||
Из *операции пути* можно вернуть *элементы перечисления*, даже вложенные в тело JSON (например в `dict`). |
|||
|
|||
Они будут преобразованы в соответствующие значения (в данном случае - строки) перед их возвратом клиенту: |
|||
|
|||
```Python hl_lines="18 21 23" |
|||
{!../../../docs_src/path_params/tutorial005.py!} |
|||
``` |
|||
Вы отправите клиенту такой JSON-ответ: |
|||
|
|||
```JSON |
|||
{ |
|||
"model_name": "alexnet", |
|||
"message": "Deep Learning FTW!" |
|||
} |
|||
``` |
|||
|
|||
## Path-параметры, содержащие пути |
|||
|
|||
Предположим, что есть *операция пути* с путем `/files/{file_path}`. |
|||
|
|||
Но вам нужно, чтобы `file_path` сам содержал *путь*, например, `home/johndoe/myfile.txt`. |
|||
|
|||
Тогда URL для этого файла будет такой: `/files/home/johndoe/myfile.txt`. |
|||
|
|||
### Поддержка OpenAPI |
|||
|
|||
OpenAPI не поддерживает способов объявления *параметра пути*, содержащего внутри *путь*, так как это может привести к сценариям, которые сложно определять и тестировать. |
|||
|
|||
Тем не менее это можно сделать в **FastAPI**, используя один из внутренних инструментов Starlette. |
|||
|
|||
Документация по-прежнему будет работать, хотя и не добавит никакой информации о том, что параметр должен содержать путь. |
|||
|
|||
### Конвертер пути |
|||
|
|||
Благодаря одной из опций Starlette, можете объявить *параметр пути*, содержащий *путь*, используя URL вроде: |
|||
|
|||
``` |
|||
/files/{file_path:path} |
|||
``` |
|||
|
|||
В этом случае `file_path` - это имя параметра, а часть `:path`, указывает, что параметр должен соответствовать любому *пути*. |
|||
|
|||
Можете использовать так: |
|||
|
|||
```Python hl_lines="6" |
|||
{!../../../docs_src/path_params/tutorial004.py!} |
|||
``` |
|||
|
|||
!!! tip "Подсказка" |
|||
Возможно, вам понадобится, чтобы параметр содержал `/home/johndoe/myfile.txt` с ведущим слэшем (`/`). |
|||
|
|||
В этом случае URL будет таким: `/files//home/johndoe/myfile.txt`, с двойным слэшем (`//`) между `files` и `home`. |
|||
|
|||
## Резюме |
|||
Используя **FastAPI** вместе со стандартными объявлениями типов Python (короткими и интуитивно понятными), вы получаете: |
|||
|
|||
* Поддержку редактора (проверку ошибок, автозаполнение и т.п.) |
|||
* "<abbr title="преобразование строк из HTTP-запроса в типы данных Python">Парсинг</abbr>" данных |
|||
* Валидацию данных |
|||
* Автоматическую документацию API с указанием типов параметров. |
|||
|
|||
И объявлять типы достаточно один раз. |
|||
|
|||
Это, вероятно, является главным заметным преимуществом **FastAPI** по сравнению с альтернативными фреймворками (кроме <abbr title="не считая оптимизаций">сырой</abbr> производительности). |
Loading…
Reference in new issue