# 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> производительности).
