# 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) до принаймні 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)?

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

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

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

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

```Python
q: Annotated[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 (до <dfn title="до 2023-03">0.95.0</dfn>) потрібно було використовувати `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` може містити кілька анотацій метаданих, тепер ви навіть можете використовувати ту саму функцію з іншими інструментами, такими як [Typer](https://typer.tiangolo.com/). 🚀

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

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

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

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

Ви можете визначити <dfn title="Регулярний вираз, regex або regexp — це послідовність символів, яка визначає шаблон для пошуку в рядках.">регулярний вираз</dfn> `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_py310.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_py310.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_py310.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_py310.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 }

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

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

Тоді передайте параметр `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`).

Це можна досягти за допомогою [Pydantic's `AfterValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) в середині `Annotated`.

/// tip | Порада

Pydantic також має [`BeforeValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator) та інші. 🤓

///

Наприклад, цей кастомний валідатор перевіряє, чи починається ID елемента з `isbn-` для номера книги <abbr title="International Standard Book Number - Міжнародний стандартний номер книги">ISBN</abbr> або з `imdb-` для ID URL фільму на <abbr title="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()` ми отримуємо <dfn title="Щось, що ми можемо ітерувати циклом for, як-от список, множина тощо.">ітерабельний об'єкт</dfn> із кортежами, що містять ключ і значення для кожного елемента словника.

Ми перетворюємо цей ітерабельний об'єкт у звичайний `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`.

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