# Модель ответа — Возвращаемый тип { #response-model-return-type }

Вы можете объявить тип, используемый для ответа, указав аннотацию **возвращаемого значения** для *функции-обработчика пути*.

Вы можете использовать **аннотации типов** так же, как и для входных данных в **параметрах** функции: Pydantic-модели, списки, словари, скалярные значения (целые числа, булевы и т.д.).

{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}

FastAPI будет использовать этот возвращаемый тип, чтобы:

* **Валидировать** возвращаемые данные.
    * Если данные невалидны (например, отсутствует поле), это означает, что код *вашего* приложения работает некорректно и возвращает не то, что должен. В таком случае будет возвращена ошибка сервера вместо неправильных данных. Так вы и ваши клиенты можете быть уверены, что получите ожидаемые данные и ожидаемую структуру данных.
* Добавить **JSON Schema** для ответа в OpenAPI *операции пути*.
    * Это будет использовано **автоматической документацией**.
    * Это также будет использовано инструментами автоматической генерации клиентского кода.
* **Сериализовать** возвращаемые данные в JSON с помощью Pydantic, который написан на **Rust**, поэтому это будет **намного быстрее**.

Но самое главное:

* Выходные данные будут **ограничены и отфильтрованы** в соответствии с тем, что определено в возвращаемом типе.
    * Это особенно важно для **безопасности**, ниже мы рассмотрим это подробнее.

## Параметр `response_model` { #response-model-parameter }

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

Например, вы можете хотеть **возвращать словарь** или объект из базы данных, но **объявить его как Pydantic-модель**. Тогда Pydantic-модель выполнит документирование данных, валидацию и т.п. для объекта, который вы вернули (например, словаря или объекта из базы данных).

Если вы добавите аннотацию возвращаемого типа, инструменты и редакторы кода начнут жаловаться (и будут правы), что функция возвращает тип (например, dict), отличный от объявленного (например, Pydantic-модель).

В таких случаях вместо аннотации возвращаемого типа можно использовать параметр `response_model` у *декоратора операции пути*.

Параметр `response_model` можно указать у любой *операции пути*:

* `@app.get()`
* `@app.post()`
* `@app.put()`
* `@app.delete()`
* и т.д.

{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}

/// note | Примечание

Обратите внимание, что `response_model` — это параметр метода «декоратора» (`get`, `post` и т.д.), а не вашей *функции-обработчика пути*, в которой указываются параметры и тело запроса.

///

`response_model` принимает тот же тип, что вы бы объявили для поля Pydantic-модели, то есть это может быть одна Pydantic-модель, а может быть, например, `list` Pydantic-моделей, как `List[Item]`.

FastAPI будет использовать этот `response_model` для документирования, валидации данных и т.п., а также для **конвертации и фильтрации выходных данных** к объявленному типу.

/// tip | Совет

Если у вас в редакторе кода, mypy и т.п. включены строгие проверки типов, вы можете объявить возвращаемый тип функции как `Any`.

Так вы сообщите редактору, что намеренно возвращаете что угодно. Но FastAPI всё равно выполнит документирование, валидацию, фильтрацию данных и т.д. с помощью `response_model`.

///

### Приоритет `response_model` { #response-model-priority }

Если вы объявите и возвращаемый тип, и `response_model`, приоритет будет у `response_model`, именно его использует FastAPI.

Так вы можете добавить корректные аннотации типов к своим функциям, даже если фактически возвращаете тип, отличный от модели ответа, чтобы ими пользовались редактор кода и инструменты вроде mypy. И при этом FastAPI продолжит выполнять валидацию данных, документацию и т.д. с использованием `response_model`.

Вы также можете указать `response_model=None`, чтобы отключить создание модели ответа для данной *операции пути*. Это может понадобиться, если вы добавляете аннотации типов для вещей, не являющихся валидными полями Pydantic. Пример вы увидите ниже.

## Вернуть те же входные данные { #return-the-same-input-data }

Здесь мы объявляем модель `UserIn`, она будет содержать пароль в открытом виде:

{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}

/// info | Информация

Чтобы использовать `EmailStr`, сначала установите [`email-validator`](https://github.com/JoshData/python-email-validator).

Убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md), активировали его, а затем установите пакет, например:

```console
$ pip install email-validator
```

или так:

```console
$ pip install "pydantic[email]"
```

///

И мы используем эту модель для объявления входных данных, и ту же модель — для объявления выходных данных:

{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}

Теперь, когда браузер создаёт пользователя с паролем, API вернёт тот же пароль в ответе.

В этом случае это может быть не проблемой, так как пароль отправляет тот же пользователь.

Но если мы используем ту же модель в другой *операции пути*, мы можем начать отправлять пароли пользователей каждому клиенту.

/// danger | Осторожно

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

///

## Добавить выходную модель { #add-an-output-model }

Вместо этого мы можем создать входную модель с паролем в открытом виде и выходную модель без него:

{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}

Здесь, хотя *функция-обработчик пути* возвращает тот же входной объект пользователя, содержащий пароль:

{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}

...мы объявили `response_model` как модель `UserOut`, в которой нет пароля:

{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}

Таким образом, **FastAPI** позаботится о том, чтобы отфильтровать все данные, не объявленные в выходной модели (используя Pydantic).

### `response_model` или возвращаемый тип { #response-model-or-return-type }

В этом случае, поскольку две модели различаются, если бы мы аннотировали возвращаемый тип функции как `UserOut`, редактор кода и инструменты пожаловались бы, что мы возвращаем неверный тип, так как это разные классы.

Поэтому в этом примере мы должны объявить тип ответа в параметре `response_model`.

...но читайте дальше, чтобы узнать, как это обойти.

## Возвращаемый тип и фильтрация данных { #return-type-and-data-filtering }

Продолжим предыдущий пример. Мы хотели **аннотировать функцию одним типом**, но при этом иметь возможность вернуть из функции что-то, что фактически включает **больше данных**.

Мы хотим, чтобы FastAPI продолжал **фильтровать** данные с помощью модели ответа. Так что, даже если функция возвращает больше данных, в ответ будут включены только поля, объявленные в модели ответа.

В предыдущем примере, поскольку классы были разными, нам пришлось использовать параметр `response_model`. Но это также означает, что мы теряем поддержку от редактора кода и инструментов, проверяющих возвращаемый тип функции.

Однако в большинстве таких случаев нам нужно лишь **отфильтровать/убрать** некоторые данные, как в этом примере.

И в этих случаях мы можем использовать классы и наследование, чтобы воспользоваться **аннотациями типов** функций для лучшей поддержки в редакторе кода и инструментах и при этом получить **фильтрацию данных** от FastAPI.

{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}

Так мы получаем поддержку инструментов — редакторов кода и mypy, так как этот код корректен с точки зрения типов — и одновременно получаем фильтрацию данных от FastAPI.

Как это работает? Давайте разберёмся. 🤓

### Аннотации типов и инструменты { #type-annotations-and-tooling }

Сначала посмотрим, как это увидят редактор кода, mypy и другие инструменты.

`BaseUser` содержит базовые поля. Затем `UserIn` наследуется от `BaseUser` и добавляет поле `password`, то есть он будет включать все поля обеих моделей.

Мы аннотируем возвращаемый тип функции как `BaseUser`, но фактически возвращаем экземпляр `UserIn`.

Редактор кода, mypy и другие инструменты не будут возражать, потому что с точки зрения типов `UserIn` — подкласс `BaseUser`, что означает, что это *валидный* тип везде, где ожидается что-то, являющееся `BaseUser`.

### Фильтрация данных FastAPI { #fastapi-data-filtering }

Теперь для FastAPI: он увидит возвращаемый тип и убедится, что то, что вы возвращаете, включает **только** поля, объявленные в этом типе.

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

Таким образом вы получаете лучшее из обоих миров: аннотации типов с **поддержкой инструментов** и **фильтрацию данных**.

## Посмотреть в документации { #see-it-in-the-docs }

В автоматической документации вы увидите, что у входной и выходной моделей есть свои JSON Schema:

<img src="/img/tutorial/response-model/image01.png">

И обе модели будут использоваться в интерактивной документации API:

<img src="/img/tutorial/response-model/image02.png">

## Другие аннотации возвращаемых типов { #other-return-type-annotations }

Бывают случаи, когда вы возвращаете что-то, что не является валидным полем Pydantic, и аннотируете это в функции только ради поддержки инструментов (редактор кода, mypy и т.д.).

### Возврат Response напрямую { #return-a-response-directly }

Самый распространённый случай — [возвращать Response напрямую, как описано далее в разделах документации для продвинутых](../advanced/response-directly.md).

{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}

Этот простой случай обрабатывается FastAPI автоматически, потому что аннотация возвращаемого типа — это класс (или подкласс) `Response`.

И инструменты тоже будут довольны, потому что и `RedirectResponse`, и `JSONResponse` являются подклассами `Response`, так что аннотация типа корректна.

### Аннотировать подкласс Response { #annotate-a-response-subclass }

Вы также можете использовать подкласс `Response` в аннотации типа:

{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}

Это тоже сработает, так как `RedirectResponse` — подкласс `Response`, и FastAPI автоматически обработает этот простой случай.

### Некорректные аннотации возвращаемых типов { #invalid-return-type-annotations }

Но когда вы возвращаете произвольный объект, не являющийся валидным типом Pydantic (например, объект базы данных), и аннотируете его таким образом в функции, FastAPI попытается создать модель ответа Pydantic из этой аннотации типа и потерпит неудачу.

То же произойдёт, если у вас будет что-то вроде <dfn title="Объединение нескольких типов означает «любой из этих типов».">объединение</dfn> разных типов, где один или несколько не являются валидными типами Pydantic, например, это приведёт к ошибке 💥:

{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}

...это не сработает, потому что аннотация типа не является типом Pydantic и это не единственный класс `Response` или его подкласс, а объединение (`union`) из `Response` и `dict`.

### Отключить модель ответа { #disable-response-model }

Продолжая пример выше, вы можете не хотеть использовать стандартные валидацию данных, документирование, фильтрацию и т.п., выполняемые FastAPI.

Но при этом вы можете хотеть сохранить аннотацию возвращаемого типа в функции, чтобы пользоваться поддержкой инструментов вроде редакторов кода и инструментов проверки типов (например, mypy).

В этом случае вы можете отключить генерацию модели ответа, установив `response_model=None`:

{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}

Так FastAPI пропустит генерацию модели ответа, и вы сможете использовать любые аннотации возвращаемых типов, которые вам нужны, без влияния на ваше приложение FastAPI. 🤓

## Параметры кодирования модели ответа { #response-model-encoding-parameters }

У вашей модели ответа могут быть значения по умолчанию, например:

{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}

* `description: Union[str, None] = None` (или `str | None = None` в Python 3.10) имеет значение по умолчанию `None`.
* `tax: float = 10.5` имеет значение по умолчанию `10.5`.
* `tags: List[str] = []` имеет значение по умолчанию пустого списка: `[]`.

но вы можете захотеть опустить их в результате, если они фактически не были сохранены.

Например, если у вас есть модели с множеством необязательных атрибутов в NoSQL-базе данных, но вы не хотите отправлять очень длинные JSON-ответы, заполненные значениями по умолчанию.

### Используйте параметр `response_model_exclude_unset` { #use-the-response-model-exclude-unset-parameter }

Вы можете установить у *декоратора операции пути* параметр `response_model_exclude_unset=True`:

{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}

и эти значения по умолчанию не будут включены в ответ — только те значения, которые действительно были установлены.

Итак, если вы отправите запрос к этой *операции пути* для элемента с ID `foo`, ответ (без значений по умолчанию) будет таким:

```JSON
{
    "name": "Foo",
    "price": 50.2
}
```

/// info | Информация

Вы также можете использовать:

* `response_model_exclude_defaults=True`
* `response_model_exclude_none=True`

как описано в [документации Pydantic](https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict) для `exclude_defaults` и `exclude_none`.

///

#### Данные со значениями для полей, имеющих значения по умолчанию { #data-with-values-for-fields-with-defaults }

Но если в ваших данных есть значения для полей модели, для которых указаны значения по умолчанию, как у элемента с ID `bar`:

```Python hl_lines="3  5"
{
    "name": "Bar",
    "description": "The bartenders",
    "price": 62,
    "tax": 20.2
}
```

они будут включены в ответ.

#### Данные с такими же значениями, как значения по умолчанию { #data-with-the-same-values-as-the-defaults }

Если данные имеют те же значения, что и значения по умолчанию, как у элемента с ID `baz`:

```Python hl_lines="3  5-6"
{
    "name": "Baz",
    "description": None,
    "price": 50.2,
    "tax": 10.5,
    "tags": []
}
```

FastAPI достаточно умен (на самом деле, это Pydantic), чтобы понять, что хотя `description`, `tax` и `tags` совпадают со значениями по умолчанию, они были установлены явно (а не взяты из значений по умолчанию).

Поэтому они тоже будут включены в JSON-ответ.

/// tip | Совет

Обратите внимание, что значения по умолчанию могут быть любыми, не только `None`.

Это может быть список (`[]`), число с плавающей точкой `10.5` и т.д.

///

### `response_model_include` и `response_model_exclude` { #response-model-include-and-response-model-exclude }

Вы также можете использовать параметры *декоратора операции пути* `response_model_include` и `response_model_exclude`.

Они принимают `set` из `str` с именами атрибутов, которые нужно включить (исключив остальные) или исключить (оставив остальные).

Это можно использовать как быстрый способ, если у вас только одна Pydantic-модель и вы хотите убрать часть данных из ответа.

/// tip | Совет

Но всё же рекомендуется использовать подходы выше — несколько классов — вместо этих параметров.

Потому что JSON Schema, генерируемая в OpenAPI вашего приложения (и документации), всё равно будет соответствовать полной модели, даже если вы используете `response_model_include` или `response_model_exclude`, чтобы опустить некоторые атрибуты.

То же относится к `response_model_by_alias`, который работает аналогично.

///

{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}

/// tip | Совет

Синтаксис `{"name", "description"}` создаёт `set` с этими двумя значениями.

Это эквивалентно `set(["name", "description"])`.

///

#### Использование `list` вместо `set` { #using-lists-instead-of-sets }

Если вы забыли использовать `set` и применили `list` или `tuple` вместо него, FastAPI всё равно преобразует это в `set`, и всё будет работать корректно:

{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}

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

Используйте параметр `response_model` у *декоратора операции пути*, чтобы задавать модели ответа, и особенно — чтобы приватные данные отфильтровывались.

Используйте `response_model_exclude_unset`, чтобы возвращать только те значения, которые были установлены явно.
