# Параметри шляху { #path-parameters }

Ви можете оголосити «параметри» або «змінні» шляху, використовуючи той самий синтаксис, що й у форматованих рядках Python:

{* ../../docs_src/path_params/tutorial001_py39.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"}
```

## Параметри шляху з типами { #path-parameters-with-types }

Ви можете оголосити тип параметра шляху у функції, використовуючи стандартні анотації типів Python:

{* ../../docs_src/path_params/tutorial002_py39.py hl[7] *}

У цьому випадку `item_id` оголошено як `int`.

/// check | Примітка

Це дасть вам підтримку редактора всередині функції з перевірками помилок, автодоповненням тощо.

///

## <abbr title="also known as: serialization, parsing, marshalling – також відомо як: серіалізація, парсинг, маршалізація">Перетворення</abbr> даних { #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>, то побачите відповідь:

```JSON
{"item_id":3}
```

/// check | Примітка

Зверніть увагу, що значення, яке отримала (і повернула) ваша функція, — це `3`, як Python `int`, а не рядок `"3"`.

Отже, з таким оголошенням типу **FastAPI** надає вам автоматичний <abbr title="converting the string that comes from an HTTP request into Python data – перетворення рядка, що надходить із HTTP-запиту, у дані Python">«parsing»</abbr> запиту.

///

## Валідація даних { #data-validation }

Але якщо ви перейдете у браузері за посиланням <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": [
    {
      "type": "int_parsing",
      "loc": [
        "path",
        "item_id"
      ],
      "msg": "Input should be a valid integer, unable to parse string as an integer",
      "input": "foo"
    }
  ]
}
```

тому що параметр шляху `item_id` мав значення `"foo"`, яке не є `int`.

Та сама помилка з’явиться, якщо ви передасте `float` замість `int`, як у: <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 | Примітка

Отже, з тим самим оголошенням типу в Python **FastAPI** надає вам валідацію даних.

Зверніть увагу, що помилка також чітко вказує саме місце, де валідація не пройшла.

Це неймовірно корисно під час розробки та налагодження коду, що взаємодіє з вашим API.

///

## Документація { #documentation }

А коли ви відкриєте у браузері <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 | Примітка

Знову ж таки, лише з тим самим оголошенням типу в Python **FastAPI** надає вам автоматичну, інтерактивну документацію (з інтеграцією Swagger UI).

Зверніть увагу, що параметр шляху оголошено як ціле число.

///

## Переваги стандартів, альтернативна документація { #standards-based-benefits-alternative-documentation }

І оскільки згенерована схема відповідає стандарту <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.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 { #pydantic }

Уся валідація даних виконується за лаштунками за допомогою <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>, тож ви отримуєте всі переваги від його використання. І ви знаєте, що ви в надійних руках.

Ви можете використовувати ті самі оголошення типів з `str`, `float`, `bool` та багатьма іншими складними типами даних.

Декілька з них розглядаються в наступних розділах посібника.

## Порядок має значення { #order-matters }

Під час створення *операцій шляху* можуть виникати ситуації, коли у вас є фіксований шлях.

Наприклад, `/users/me` — припустімо, це для отримання даних про поточного користувача.

І тоді у вас також може бути шлях `/users/{user_id}` для отримання даних про конкретного користувача за його ID.

Оскільки *операції шляху* оцінюються по черзі, вам потрібно переконатися, що шлях для `/users/me` оголошено перед шляхом для `/users/{user_id}`:

{* ../../docs_src/path_params/tutorial003_py39.py hl[6,11] *}

Інакше шлях для `/users/{user_id}` також відповідатиме `/users/me`, «вважаючи», що отримує параметр `user_id` зі значенням `"me"`.

Так само ви не можете перевизначити операцію шляху:

{* ../../docs_src/path_params/tutorial003b_py39.py hl[6,11] *}

Завжди використовуватиметься перша, оскільки шлях збігається першим.

## Попередньо визначені значення { #predefined-values }

Якщо у вас є *операція шляху*, яка отримує *параметр шляху*, але ви хочете, щоб можливі коректні значення *параметра шляху* були попередньо визначені, ви можете використати стандартний Python <abbr title="Enumeration">`Enum`</abbr>.

### Створіть клас `Enum` { #create-an-enum-class }

Імпортуйте `Enum` і створіть підклас, що наслідується від `str` та `Enum`.

Завдяки наслідуванню від `str` документація API зможе визначити, що значення повинні бути типу `string`, і зможе коректно їх відобразити.

Після цього створіть атрибути класу з фіксованими значеннями, які будуть доступними коректними значеннями:

{* ../../docs_src/path_params/tutorial005_py39.py hl[1,6:9] *}

/// tip | Порада

Якщо вам цікаво, «AlexNet», «ResNet» та «LeNet» — це просто назви Machine Learning <abbr title="Technically, Deep Learning model architectures – технічно, архітектури моделей Deep Learning">models</abbr>.

///

### Оголосіть *параметр шляху* { #declare-a-path-parameter }

Потім створіть *параметр шляху* з анотацією типу, використовуючи створений вами клас enum (`ModelName`):

{* ../../docs_src/path_params/tutorial005_py39.py hl[16] *}

### Перевірте документацію { #check-the-docs }

Оскільки доступні значення для *параметра шляху* визначені заздалегідь, інтерактивна документація може красиво їх показати:

<img src="/img/tutorial/path-params/image03.png">

### Робота з Python *переліченнями* { #working-with-python-enumerations }

Значення *параметра шляху* буде *елементом перелічування*.

#### Порівняйте *елементи перелічування* { #compare-enumeration-members }

Ви можете порівнювати його з *елементом перелічування* у створеному вами enum `ModelName`:

{* ../../docs_src/path_params/tutorial005_py39.py hl[17] *}

#### Отримайте *значення перелічування* { #get-the-enumeration-value }

Ви можете отримати фактичне значення (у цьому випадку це `str`), використовуючи `model_name.value`, або загалом `your_enum_member.value`:

{* ../../docs_src/path_params/tutorial005_py39.py hl[20] *}

/// tip | Порада

Ви також можете отримати доступ до значення `"lenet"` через `ModelName.lenet.value`.

///

#### Поверніть *елементи перелічування* { #return-enumeration-members }

Ви можете повертати *елементи enum* з вашої *операції шляху*, навіть вкладені у JSON-тіло (наприклад, `dict`).

Вони будуть перетворені на відповідні значення (у цьому випадку рядки) перед поверненням клієнту:

{* ../../docs_src/path_params/tutorial005_py39.py hl[18,21,23] *}

На стороні клієнта ви отримаєте відповідь у форматі JSON, наприклад:

```JSON
{
  "model_name": "alexnet",
  "message": "Deep Learning FTW!"
}
```

## Параметри шляху, що містять шляхи { #path-parameters-containing-paths }

Припустімо, у вас є *операція шляху* зі шляхом `/files/{file_path}`.

Але вам потрібно, щоб `file_path` сам містив *шлях*, наприклад `home/johndoe/myfile.txt`.

Отже, URL для цього файлу виглядатиме приблизно так: `/files/home/johndoe/myfile.txt`.

### Підтримка OpenAPI { #openapi-support }

OpenAPI не підтримує спосіб оголошення *параметра шляху*, який має містити всередині *шлях*, оскільки це може призвести до сценаріїв, які складно тестувати та визначати.

Проте ви все одно можете зробити це в **FastAPI**, використовуючи один із внутрішніх інструментів Starlette.

І документація все ще працюватиме, хоча й не додаватиме жодної документації, яка б казала, що параметр має містити шлях.

### Конвертер шляху { #path-convertor }

Використовуючи опцію безпосередньо зі Starlette, ви можете оголосити *параметр шляху*, що містить *шлях*, використовуючи URL на кшталт:

```
/files/{file_path:path}
```

У цьому випадку ім’я параметра — `file_path`, а остання частина `:path` вказує, що параметр має відповідати будь-якому *шляху*.

Отже, ви можете використати його так:

{* ../../docs_src/path_params/tutorial004_py39.py hl[6] *}

/// tip | Порада

Вам може знадобитися, щоб параметр містив `/home/johndoe/myfile.txt` із початковою косою рискою (`/`).

У такому випадку URL виглядатиме так: `/files//home/johndoe/myfile.txt`, із подвійною косою рискою (`//`) між `files` і `home`.

///

## Підсумок { #recap }

З **FastAPI**, використовуючи короткі, інтуїтивно зрозумілі та стандартні оголошення типів Python, ви отримуєте:

* Підтримку редактора: перевірка помилок, автодоповнення тощо.
* Перетворення даних «<abbr title="converting the string that comes from an HTTP request into Python data – перетворення рядка, що надходить з HTTP-запиту, у дані Python">parsing</abbr>»
* Валідацію даних
* Анотацію API та автоматичну документацію

І вам потрібно оголосити їх лише один раз.

Це, ймовірно, основна видима перевага **FastAPI** порівняно з альтернативними фреймворками (окрім сирої продуктивності).
