# 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 | Дополнительная информация
Поддержка `Annotated` (и рекомендация использовать его) появилась в FastAPI версии 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 символов;
* показывать **понятную ошибку** клиенту, если данные невалидны;
* **документировать** параметр в *операции пути* схемы OpenAPI (он будет показан в **UI автоматической документации**).
## Альтернатива (устаревшее): `Query` как значение по умолчанию { #alternative-old-query-as-the-default-value }
В предыдущих версиях FastAPI (до 0.95.0) требовалось использовать `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 в **других местах** вам нужно **помнить** о том, что надо передать аргументы, чтобы всё работало корректно, иначе значения будут не такими, как вы ожидаете (например, вместо `str` будет `QueryInfo` или что-то подобное). И ни редактор, ни 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 }
Вы можете определить регулярное выражение `pattern`, которому должен соответствовать параметр:
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
Данный шаблон регулярного выражения проверяет, что полученное значение параметра:
* `^`: начинается с следующих символов, до них нет символов.
* `fixedquery`: имеет точное значение `fixedquery`.
* `$`: заканчивается здесь, после `fixedquery` нет никаких символов.
Если вы теряетесь во всех этих идеях про **«регулярные выражения»**, не переживайте. Это сложная тема для многих. Многое можно сделать и без них.
Теперь вы знаете, что когда они понадобятся, вы сможете использовать их в **FastAPI**.
## Значения по умолчанию { #default-values }
Конечно, можно использовать и другие значения по умолчанию, не только `None`.
Допустим, вы хотите объявить, что query-параметр `q` должен иметь `min_length` равный `3` и значение по умолчанию `"fixedquery"`:
{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}
/// note | Примечание
Наличие значения по умолчанию любого типа, включая `None`, делает параметр необязательным.
///
## Обязательные параметры { #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
```
вы получите множественные значения *query-параметров* `q` (`foo` и `bar`) в виде Python-`list` внутри вашей *функции-обработчика пути*, в *параметре функции* `q`.
Таким образом, ответ на этот URL будет:
```JSON
{
"q": [
"foo",
"bar"
]
}
```
/// tip | Совет
Чтобы объявить query-параметр типа `list`, как в примере выше, нужно явно использовать `Query`, иначе он будет интерпретирован как тело запроса.
///
Интерактивная документация API обновится соответствующим образом и позволит передавать несколько значений:
### 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 }
Предположим, этот параметр вам больше не нравится.
Его нужно оставить на какое‑то время, так как клиенты его используют, но вы хотите, чтобы в документации он явно отображался как устаревший.
Тогда передайте параметр `deprecated=True` в `Query`:
{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}
В документации это будет показано так:
## Исключить параметры из OpenAPI { #exclude-parameters-from-openapi }
Чтобы исключить query-параметр из генерируемой OpenAPI-схемы (и, следовательно, из систем автоматической документации), укажите у `Query` параметр `include_in_schema=False`:
{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}
## Кастомная валидация { #custom-validation }
Бывают случаи, когда нужна **кастомная валидация**, которую нельзя выразить параметрами выше.
В таких случаях можно использовать **кастомную функцию-валидатор**, которая применяется после обычной валидации (например, после проверки, что значение — это `str`).
Этого можно добиться, используя [`AfterValidator` Pydantic](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-` для номера книги ISBN или с `imdb-` для ID URL фильма на IMDB:
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
/// info | Дополнительная информация
Это доступно в Pydantic версии 2 и выше. 😎
///
/// tip | Совет
Если вам нужна валидация, требующая общения с каким‑либо **внешним компонентом** — базой данных или другим API — вместо этого используйте **Зависимости FastAPI**, вы познакомитесь с ними позже.
Эти кастомные валидаторы предназначены для проверок, которые можно выполнить, имея **только** те же **данные**, что пришли в запросе.
///
### Понимание этого кода { #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()` мы получаем итерируемый объект с кортежами, содержащими ключ и значение для каждого элемента словаря.
Мы превращаем этот итерируемый объект в обычный `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`.
Смотрите следующие главы, чтобы узнать, как объявлять проверки для других типов, например чисел.