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