# 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){.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.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` { #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 (до <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-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` может содержать больше одной аннотации метаданных, теперь вы можете использовать ту же функцию и с другими инструментами, например с <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="Регулярное выражение (regex, regexp) — это последовательность символов, задающая шаблон поиска для строк.">регулярное выражение</abbr> `pattern`, которому должен соответствовать параметр:

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

Данный шаблон регулярного выражения проверяет, что полученное значение параметра:

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

Если вы теряетесь во всех этих идеях про **«регулярные выражения»**, не переживайте. Это сложная тема для многих. Многое можно сделать и без них.

Теперь вы знаете, что когда они понадобятся, вы сможете использовать их в **FastAPI**.

### `regex` из Pydantic v1 вместо `pattern` { #pydantic-v1-regex-instead-of-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`. 🤓

## Значения по умолчанию { #default-values }

Конечно, можно использовать и другие значения по умолчанию, не только `None`.

Допустим, вы хотите объявить, что query-параметр `q` должен иметь `min_length` равный `3` и значение по умолчанию `"fixedquery"`:

{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.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_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
```

вы получите множественные значения query-параметра `q` (`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="устаревший, не рекомендуется использовать">устаревший</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-схемы (и, следовательно, из систем автоматической документации), укажите у `Query` параметр `include_in_schema=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">`AfterValidator` Pydantic</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 означает International Standard Book Number – Международный стандартный книжный номер">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** (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="Объект, по которому можно итерироваться циклом for, например список, множество и т. п.">итерируемый объект</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] *}

## Резюме { #recap }

Вы можете объявлять дополнительные проверки и метаданные для параметров.

Общие метаданные и настройки:

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

Проверки, специфичные для строк:

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

Кастомные проверки с использованием `AfterValidator`.

В этих примерах вы видели, как объявлять проверки для значений типа `str`.

Смотрите следующие главы, чтобы узнать, как объявлять проверки для других типов, например чисел.
