mirror of https://github.com/tiangolo/fastapi.git
256 lines
14 KiB
Markdown
256 lines
14 KiB
Markdown
# Path-параметры
|
||
|
||
Вы можете определить "параметры" или "переменные" пути, используя синтаксис форматированных строк Python:
|
||
|
||
{* ../../docs_src/path_params/tutorial001.py hl[6:7] *}
|
||
|
||
Значение параметра пути `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.
|
||
|
||
{* ../../docs_src/path_params/tutorial002.py hl[7] *}
|
||
|
||
Здесь, `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://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>. Поэтому вы можете быть уверены в качестве обработки данных.
|
||
|
||
Вы можете использовать в аннотациях как простые типы данных, вроде `str`, `float`, `bool`, так и более сложные типы.
|
||
|
||
Некоторые из них рассматриваются в следующих главах данного руководства.
|
||
|
||
## Порядок имеет значение
|
||
|
||
При создании *операций пути* можно столкнуться с ситуацией, когда путь является фиксированным.
|
||
|
||
Например, `/users/me`. Предположим, что это путь для получения данных о текущем пользователе.
|
||
|
||
У вас также может быть путь `/users/{user_id}`, чтобы получить данные о конкретном пользователе по его ID.
|
||
|
||
Поскольку *операции пути* выполняются в порядке их объявления, необходимо, чтобы путь для `/users/me` был объявлен раньше, чем путь для `/users/{user_id}`:
|
||
|
||
|
||
{* ../../docs_src/path_params/tutorial003.py hl[6,11] *}
|
||
|
||
Иначе путь для `/users/{user_id}` также будет соответствовать `/users/me`, "подразумевая", что он получает параметр `user_id` со значением `"me"`.
|
||
|
||
Аналогично, вы не можете переопределить операцию с путем:
|
||
|
||
{* ../../docs_src/path_params/tutorial003b.py hl[6,11] *}
|
||
|
||
Первый будет выполняться всегда, так как путь совпадает первым.
|
||
|
||
## Предопределенные значения
|
||
|
||
Что если нам нужно заранее определить допустимые *параметры пути*, которые *операция пути* может принимать? В таком случае можно использовать стандартное перечисление <abbr title="Enumeration">`Enum`</abbr> Python.
|
||
|
||
### Создание класса `Enum`
|
||
|
||
Импортируйте `Enum` и создайте подкласс, который наследуется от `str` и `Enum`.
|
||
|
||
Мы наследуемся от `str`, чтобы документация API могла понять, что значения должны быть типа `string` и отображалась правильно.
|
||
|
||
Затем создайте атрибуты класса с фиксированными допустимыми значениями:
|
||
|
||
{* ../../docs_src/path_params/tutorial005.py hl[1,6:9] *}
|
||
|
||
/// 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`), созданный ранее:
|
||
|
||
{* ../../docs_src/path_params/tutorial005.py hl[16] *}
|
||
|
||
### Проверьте документацию
|
||
|
||
Поскольку доступные значения *параметра пути* определены заранее, интерактивная документация может наглядно их отображать:
|
||
|
||
<img src="/img/tutorial/path-params/image03.png">
|
||
|
||
### Работа с *перечислениями* в Python
|
||
|
||
Значение *параметра пути* будет *элементом перечисления*.
|
||
|
||
#### Сравнение *элементов перечисления*
|
||
|
||
Вы можете сравнить это значение с *элементом перечисления* класса `ModelName`:
|
||
|
||
{* ../../docs_src/path_params/tutorial005.py hl[17] *}
|
||
|
||
#### Получение *значения перечисления*
|
||
|
||
Можно получить фактическое значение (в данном случае - `str`) с помощью `model_name.value` или в общем случае `your_enum_member.value`:
|
||
|
||
{* ../../docs_src/path_params/tutorial005.py hl[20] *}
|
||
|
||
/// tip | Подсказка
|
||
|
||
Значение `"lenet"` также можно получить с помощью `ModelName.lenet.value`.
|
||
|
||
///
|
||
|
||
#### Возврат *элементов перечисления*
|
||
|
||
Из *операции пути* можно вернуть *элементы перечисления*, даже вложенные в тело JSON (например в `dict`).
|
||
|
||
Они будут преобразованы в соответствующие значения (в данном случае - строки) перед их возвратом клиенту:
|
||
|
||
{* ../../docs_src/path_params/tutorial005.py hl[18,21,23] *}
|
||
Вы отправите клиенту такой 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`, указывает, что параметр должен соответствовать любому *пути*.
|
||
|
||
Можете использовать так:
|
||
|
||
{* ../../docs_src/path_params/tutorial004.py hl[6] *}
|
||
|
||
/// 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> производительности).
|