# Query параметри та валідація рядків { #query-parameters-and-string-validations }

**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` дозволить вашому редактору коду надавати кращу підтримку та виявляти помилки.

///

## Додаткова валідація { #additional-validation }

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

### Імпорт `Query` та `Annotated` { #import-query-and-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` { #use-annotated-in-the-type-for-the-q-parameter }

Пам’ятаєте, як я раніше розповідав, що `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.9+

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

////

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

//// tab | Python 3.10+

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

////

//// tab | Python 3.9+

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

////

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

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

## Додавання `Query` до `Annotated` у параметр `q` { #add-query-to-annotated-in-the-q-parameter }

Тепер, коли у нас є `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` як значення за замовчуванням { #alternative-old-query-as-the-default-value }

У попередніх версіях FastAPI (до <abbr title="before 2023-03 – до 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-as-the-default-value-or-in-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` { #advantages-of-annotated }

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

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

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

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

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

## Додавання додаткових валідацій { #add-more-validations }

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

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

## Додавання регулярних виразів { #add-regular-expressions }

Ви можете визначити <abbr title="A regular expression, regex or regexp is a sequence of characters that define a search pattern for strings. – Регулярний вираз (regex або regexp) — це послідовність символів, яка визначає шаблон для пошуку в рядках.">regular expression</abbr> `pattern`, якому має відповідати параметр:

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

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

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

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

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

## Значення за замовчуванням { #default-values }

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

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

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

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

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

///

## Обов’язкові параметри { #required-parameters }

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

```Python
q: str
```

замість:

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

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

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

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

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

### Обов’язковий, може бути `None` { #required-can-be-none }

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

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

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

## Список query параметрів / кілька значень { #query-parameter-list-multiple-values }

Коли ви явно визначаєте query параметр за допомогою `Query`, ви також можете оголосити, що він має приймати список значень, або, іншими словами, кілька значень.

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

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

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

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

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

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

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

/// tip | Порада

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

///

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

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

### Список query параметрів / кілька значень за замовчуванням { #query-parameter-list-multiple-values-with-defaults }

Ви також можете визначити значення за замовчуванням `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` { #using-just-list }

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

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

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

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

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

///

## Оголосити більше метаданих { #declare-more-metadata }

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

Ця інформація буде включена у згенерований 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] *}

## Аліаси параметрів { #alias-parameters }

Уявіть, що ви хочете, щоб параметр називався `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] *}

## Позначення параметрів як застарілих { #deprecating-parameters }

Припустімо, що вам більше не подобається цей параметр.

Вам потрібно залишити його на деякий час, оскільки ним користуються клієнти, але ви хочете, щоб документація чітко показувала, що він є <abbr title="obsolete, recommended not to use it – застарілий, не рекомендується до використання">deprecated</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 { #exclude-parameters-from-openapi }

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

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

## Кастомна валідація { #custom-validation }

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

У таких випадках ви можете використати **кастомну функцію-валідатор**, яка буде застосована після звичайної валідації (наприклад, після перевірки, що значення є типом `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 means International Standard Book Number – ISBN означає Міжнародний стандартний номер книги">ISBN</abbr> або з `imdb-` для ID URL фільму на <abbr title="IMDB (Internet Movie Database) is a website with information about movies – 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** — ви дізнаєтесь про них пізніше.

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

///

### Зрозумійте цей код { #understand-that-code }

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

---

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

#### Рядок із `value.startswith()` { #string-with-value-startswith }

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

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

#### Випадковий елемент { #a-random-item }

За допомогою `data.items()` ми отримуємо <abbr title="Something we can iterate on with a for loop, like a list, set, etc. – Об'єкт, який можна перебирати в циклі, як-от список чи множину.">iterable object</abbr> із кортежами, що містять ключ і значення для кожного елемента словника.

Ми перетворюємо цей iterable object у звичайний `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] *}

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

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

Загальні валідації та метадані:

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

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

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

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

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

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