# Query параметри та валідація рядків

**FastAPI** дозволяє оголошувати додаткову інформацію та виконувати валідацію для Ваших параметрів.

Розглянемо цей додаток як приклад:

{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}

Query параметр `q` має тип `str | None`, що означає, що він може бути як `str`, так і `None`. За замовчуванням він має значення `None`, тому FastAPI розуміє, що цей параметр не є обов'язковим.

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

FastAPI знає, що `q` не є обов’язковим, завдяки значенню за замовчуванням `= None`.

Використання `str | None` дозволить Вашому редактору коду надавати кращу підтримку та виявляти помилки.

///

## Додаткова валідація

Ми хочемо, щоб навіть якщо `q` є необов’язковим, **його довжина не перевищувала 50 символів**, якщо він все ж буде переданий.

### Імпорт `Query` та `Annotated`

Щоб це зробити, спочатку імпортуємо:

* `Query` з `fastapi`
* `Annotated` з `typing`

{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}

/// info | Інформація

FastAPI додав підтримку `Annotated` (і почав рекомендувати його) у версії 0.95.0.

Якщо у Вас старіша версія, під час використання `Annotated` можуть виникати помилки.

Переконайтеся, що Ви [оновили версію FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} до принаймні 0.95.1, перш ніж використовувати `Annotated`.

///

## Використання `Annotated` у типі параметра `q`

Пам’ятаєте, як я раніше розповідав, що `Annotated` можна використовувати для додавання метаданих до параметрів у [Вступі до типів Python](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank}?

Зараз саме час використати його разом із FastAPI. 🚀

Раніше ми мали таку анотацію типу:

//// tab | Python 3.10+

```Python
q: str | None = None
```

////

//// tab | Python 3.8+

```Python
q: Union[str, None] = None
```

////

Тепер ми загорнемо її у `Annotated`, і отримаємо:

//// tab | Python 3.10+

```Python
q: Annotated[str | None] = None
```

////

//// tab | Python 3.8+

```Python
q: Annotated[Union[str, None]] = None
```

////

Обидві ці версії означають одне й те саме: `q` — це параметр, який може бути `str` або `None`, і за замовчуванням має значення `None`.

А тепер переходимо до цікавого! 🎉

## Додавання `Query` до `Annotated` у параметр `q`

Тепер, коли у нас є `Annotated`, де ми можемо додавати додаткову інформацію (зокрема валідацію), додамо `Query` всередину `Annotated` і встановимо параметр `max_length` у `50`:

{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}

Зверніть увагу, що значення за замовчуванням усе ще `None`, тому параметр залишається необов'язковим.

Але тепер, додавши `Query(max_length=50)` всередину `Annotated`, ми повідомляємо FastAPI, що хочемо **додаткову валідацію** для цього значення — воно має містити максимум 50 символів. 😎

/// tip | Підказка

Ми використовуємо `Query()`, оскільки це **query параметр**. Далі ми розглянемо інші варіанти, як-от `Path()`, `Body()`, `Header()` та `Cookie()`, які приймають ті самі аргументи, що й `Query()`.

///

Тепер FastAPI:

* **Перевірить** дані, щоб переконатися, що їхня довжина не перевищує 50 символів
* Покажe **чітку помилку** клієнту, якщо дані недійсні
* **Задокументує** параметр в OpenAPI-схемі *операції шляху* (що відобразиться в **автоматично згенерованій документації**)

## Альтернативний (застарілий) метод: Query як значення за замовчуванням

У попередніх версіях FastAPI (до <abbr title="до 2023-03">0.95.0</abbr>) `Query` використовувався як значення за замовчуванням для параметра, а не всередині `Annotated`. Ви, ймовірно, побачите код, який використовує цей підхід, тому варто розглянути його.

/// tip | Підказка

Для нового коду та коли це можливо, використовуйте `Annotated`, як показано вище. Це має багато переваг (пояснених нижче) і не має недоліків. 🍰

///

Раніше ми писали `Query()` як значення за замовчуванням для параметра функції, встановлюючи `max_length` у 50:

{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}

Оскільки в цьому випадку (без `Annotated`) нам потрібно замінити `None` у функції на `Query()`, тепер ми повинні явно встановити значення за замовчуванням через параметр `Query(default=None)`. Це виконує ту саму роль визначення значення за замовчуванням (принаймні для FastAPI).

Таким чином:

```Python
q: str | None = Query(default=None)
```

...робить параметр необов’язковим зі значенням за замовчуванням `None`, що еквівалентно:


```Python
q: str | None = None
```
Але у версії з `Query`  ми явно вказуємо, що це query параметр.

Далі ми можемо передавати `Query` додаткові параметри, зокрема `max_length`, який застосовується до рядків:

```Python
q: str | None = Query(default=None, max_length=50)
```

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

### `Query` як значення за замовчуванням або всередині `Annotated`

Важливо пам’ятати, якщо використовувати `Query` всередині `Annotated`, не можна задавати параметр `default` у `Query`.

Замість цього використовуйте значення за замовчуванням у самій функції. Інакше це буде нелогічно.

Наприклад, цей варіант є некоректним:

```Python
q: Annotated[str, Query(default="rick")] = "morty"
```

...тому, що не зрозуміло, яке значення має бути значенням за замовчуванням: `"rick"` чи `"morty"`.

Коректні варіанти:

```Python
q: Annotated[str, Query()] = "rick"
```

...або у старих кодових базах Ви знайдете:

```Python
q: str = Query(default="rick")
```

### Переваги використання `Annotated`

**Використання `Annotated` є рекомендованим** замість задання значення за замовчуванням у параметрах функції, оскільки воно **краще** з кількох причин. 🤓

Значення **за замовчуванням** параметра **функції** є його **фактичним значенням за замовчуванням**, що є більш інтуїтивним у Python загалом. 😌

Ви можете **викликати** ту саму функцію **в інших місцях** без FastAPI, і вона **працюватиме очікувано**. Якщо параметр є **обов’язковим** (без значення за замовчуванням), Ваш **редактор** повідомить про помилку, а **Python** також видасть помилку, якщо Ви виконаєте функцію без передавання цього параметра.

Якщо Ви не використовуєте `Annotated`, а використовуєте **(старий) стиль значень за замовчуванням**, то при виклику цієї функції без FastAPI **в інших місцях**, потрібно **не забути** передати їй аргументи, інакше значення будуть відрізнятися від очікуваних (наприклад, Ви отримаєте `QueryInfo` або подібне замість `str`). Ваш редактор не повідомить про помилку, і Python також не видасть помилку при запуску функції, поки не виникне помилка під час виконання операцій усередині.

Оскільки `Annotated` може містити кілька анотацій метаданих, Ви навіть можете використовувати ту саму функцію з іншими інструментами, такими як <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">Typer</a>. 🚀

## Додавання додаткових валідацій

Ви також можете додати параметр `min_length`:

{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}

## Додавання регулярних виразів

Ви можете визначити <abbr title="Регулярний вираз (regex або regexp) — це послідовність символів, яка визначає шаблон для пошуку в рядках.">регулярний вираз</abbr> pattern, якому має відповідати параметр:

{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}

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

* `^`: починається з наступних символів, перед якими немає інших символів.
* `fixedquery`: точно відповідає значенню `fixedquery`.
* `$`: закінчується тут, після `fixedquery` немає жодних символів.

Якщо Ви почуваєтеся розгублено щодо **"регулярних виразів"**, не хвилюйтеся. Вони є складною темою для багатьох людей. Ви все одно можете зробити багато речей без їх використання.

Але тепер Ви знаєте, що коли вони знадобляться, їх можна застосовувати у **FastAPI**.

### Pydantic v1 `regex` замість `pattern`

До версії Pydantic 2 і FastAPI 0.100.0 параметр називався `regex` замість `pattern`, але тепер він застарів.

Ви все ще можете зустріти код, який використовує його:

//// tab | Pydantic v1

{* ../../docs_src/query_params_str_validations/tutorial004_regex_an_py310.py hl[11] *}

////

Але майте на увазі, що він є застарілим і його слід оновити до нового параметра `pattern`. 🤓

## Значення за замовчуванням

Ви можете використовувати значення за замовчуванням, відмінні від `None`.

Наприклад, якщо Ви хочете оголосити параметр запиту `q` з `min_length` `3` і значенням за замовчуванням `"fixedquery"`:

{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}

/// note | Технічні деталі

Наявність значення за замовчуванням будь-якого типу, включаючи `None`, робить параметр необов’язковим (not required).

///

## Обов’язкові параметри

Якщо нам не потрібно вказувати додаткові перевірки або метадані, ми можемо зробити параметр `q` обов’язковим, просто не оголошуючи значення за замовчуванням, наприклад:

```Python
q: str
```

замість:

```Python
q: str | None = None
```

Але тепер ми оголошуємо його з `Query`, наприклад:

//// tab | Annotated

```Python
q: Annotated[str | None, Query(min_length=3)] = None
```

////

Тому, якщо Вам потрібно зробити значення обов’язковим, використовуючи `Query`, просто не вказуйте значення за замовчуванням:

{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}

### Обов’язкове значення, яке може бути `None`

Ви можете вказати, що параметр може приймати `None`, але при цьому залишається обов’язковим. Це змусить клієнтів надіслати значення, навіть якщо воно дорівнює `None`.

Щоб зробити це, оголосіть, що `None` є допустимим типом, але не вказуйте значення за замовчуванням:

{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}

## Список параметрів запиту / кілька значень

Якщо Ви визначаєте параметр запиту за допомогою `Query`, Ви також можете дозволити отримання списку значень, тобто дозволити отримання кількох значень.

Наприклад, щоб дозволити параметру запиту `q` з'являтися кілька разів в URL, можна написати:

{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}

Тоді, у випадку запиту за URL:

```
http://localhost:8000/items/?q=foo&q=bar
```

Ви отримаєте кілька значень *query параметра* `q` (`foo` і `bar`) у вигляді списку `list` в Python у Вашій *функції обробки шляху*, у *параметрі функції* `q`.

Отже, відповідь на цей URL буде:

```JSON
{
  "q": [
    "foo",
    "bar"
  ]
}
```

/// tip | Підказка

Щоб оголосити параметр запиту з типом `list`, як у наведеному вище прикладі, потрібно явно використовувати `Query`, інакше він буде інтерпретований як тіло запиту.

///

Інтерактивна API-документація оновиться відповідно, дозволяючи передавати кілька значень:

<img src="/img/tutorial/query-params-str-validations/image02.png">

### Список параметрів запиту / кілька значень за замовчуванням

Ви також можете визначити значення за замовчуванням для `list`, якщо жодне значення не було передане:

{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}

Якщо Ви перейдете за посиланням:

```
http://localhost:8000/items/
```

то значення `q` за замовчуванням буде: `["foo", "bar"]`, і Ваша відповідь виглядатиме так:

```JSON
{
  "q": [
    "foo",
    "bar"
  ]
}
```

#### Використання тільки `list`

Ви також можете використовувати `list` без уточнення типу, замість `list[str]`:

{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}

/// note | Технічні деталі

Майте на увазі, що в цьому випадку FastAPI не перевірятиме вміст списку.

Наприклад, `list[int]`  перевірятиме (і документуватиме), що всі елементи списку є цілими числами. Але `list` без уточнення цього не робитиме.

///

## Додавання додаткових метаданих

Ви можете додати більше інформації про параметр.

Ця інформація буде включена у згенерований OpenAPI та використана в інтерфейсах документації та зовнішніх інструментах.

/// note | Технічні деталі

Майте на увазі, що різні інструменти можуть мати різний рівень підтримки OpenAPI.

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

///

Ви можете додати `title` :

{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}

А також `description`:

{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}

## Аліаси параметрів

Уявіть, що Ви хочете, щоб параметр називався `item-query`.

Наприклад:

```
http://127.0.0.1:8000/items/?item-query=foobaritems
```

Але `item-query` — це некоректна назва змінної в Python.

Найближчий допустимий варіант — `item_query`.

Проте Вам потрібно, щоб параметр залишався саме `item-query`...

У такому випадку можна оголосити `alias`, і саме він буде використовуватися для отримання значення параметра:

{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}

## Виведення параметрів як застарілих

Припустимо, що Ви більше не хочете використовувати цей параметр.

Вам потрібно залишити його на деякий час, оскільки ним користуються клієнти, але Ви хочете, щоб документація чітко показувала, що він є <abbr title="застарілий, не рекомендується до використання">застарілим</abbr>.

Тоді Ви можете передати параметр `deprecated=True` до `Query`:

{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}

Документація буде показувати це таким чином:

<img src="/img/tutorial/query-params-str-validations/image01.png">

## Виняток параметрів з OpenAPI

Щоб виключити параметр запиту зі згенерованої схеми OpenAPI (і, таким чином, з автоматичних систем документації), встановіть параметр `include_in_schema` для `Query` в `False`:

{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}

## Кастомна валідація

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

У таких випадках ви можете використати **кастомну функцію валідації**, яка буде застосована після звичайної валідації (наприклад, після перевірки, що значення є типом `str`).

Це можна досягти за допомогою <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator" class="external-link" target="_blank">Pydantic's `AfterValidator`</a> в середині `Annotated`.

/// tip | Підказка

Pydantic також має <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator" class="external-link" target="_blank">`BeforeValidator`</a> та інші. 🤓

///

Наприклад, цей кастомний валідатор перевіряє, чи починається ID елемента з `isbn-` для номера книги <abbr title="ISBN означає Міжнародний стандартний номер книги">ISBN</abbr> або з `imdb-` для ID URL фільму на <abbr title="IMDB (Internet Movie Database) це вебсайт з інформацією про фільми">IMDB</abbr>:

{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}

/// info | Інформація

Це доступно з версії Pydantic 2 або вище. 😎

///

/// tip | Підказка

Якщо Вам потрібно виконати будь-яку валідацію, яка вимагає взаємодії з будь-яким **зовнішнім компонентом**, таким як база даних чи інший API, ви повинні замість цього використовувати **FastAPI Dependencies**. Ви дізнаєтесь про них пізніше.

Ці кастомні валідатори використовуються для речей, які можна перевірити лише з **тими даними**, що надані в запиті.

///

### Зрозумійте цей код

Головний момент – це використання **`AfterValidator` з функцією всередині `Annotated`**. Можете пропустити цю частину, якщо хочете. 🤸

---

Але якщо Вам цікаво розібратися в цьому конкретному прикладі коду і Вам ще не набридло, ось кілька додаткових деталей.

#### Рядок із `value.startswith()`

Звернули увагу? Рядок із `value.startswith()` може приймати кортеж, і тоді він перевірятиме кожне значення в кортежі:

{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}

#### Випадковий елемент

За допомогою `data.items()` ми отримуємо <abbr title="Об'єкт, який можна перебирати в циклі, як-от список чи множину.">ітерабельний об'єкт</abbr> із кортежами, що містять ключ і значення для кожного елемента словника.

Ми перетворюємо цей ітерабельний об'єкт у звичайний `list` за допомогою `list(data.items())`.

Потім, використовуючи `random.choice()`, ми можемо отримати випадкове значення зі списку, тобто отримуємо кортеж із `(id, name)`. Це може бути щось на зразок `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.

Далі ми **присвоюємо ці два значення** кортежу змінним `id` і `name`.

Тож, якщо користувач не вказав ID елемента, він все одно отримає випадкову рекомендацію.

...і все це реалізовано в **одному рядку коду**. 🤯 Хіба не прекрасний Python? 🐍

{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}

## Підсумок

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

Загальні валідації та метаінформація:

* `alias`
* `title`
* `description`
* `deprecated`

Валідації, специфічні для рядків:

* `min_length`
* `max_length`
* `pattern`

Кастомні валідації за допомогою `AfterValidator`.

У цих прикладах Ви побачили, як оголошувати валідації для значень `str`.

Дивіться наступні розділи, щоб дізнатися, як оголошувати валідації для інших типів, наприклад чисел.
