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

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

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

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

FastAPI будет использовать этот тип ответа для:

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

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

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

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

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

Например, вы можете хотеть **возвращать словарь (dict)** или объект из базы данных, но **объявить его как 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`, сначала установите <a href="https://github.com/JoshData/python-email-validator" class="external-link" target="_blank">`email-validator`</a>.

Создайте [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активируйте его и затем установите пакет, например:

```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){.internal-link target=_blank}.

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

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

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

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

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

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

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

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

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

То же произойдёт, если у вас будет что-то вроде <abbr title='Объединение нескольких типов означает «любой из этих типов».'>union</abbr> разных типов, где один или несколько не являются валидными типами 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 | Информация

В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он был помечен как устаревший (но всё ещё поддерживается) и переименован в `.model_dump()`.

Примеры здесь используют `.dict()` для совместимости с Pydantic v1, но если вы используете Pydantic v2, применяйте `.model_dump()`.

///

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

FastAPI использует метод `.dict()` у Pydantic-моделей с <a href="https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict" class="external-link" target="_blank">параметром `exclude_unset`</a>, чтобы добиться такого поведения.

///

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

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

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

как описано в <a href="https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict" class="external-link" target="_blank">документации Pydantic</a> для `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`, чтобы возвращать только те значения, которые были установлены явно.
