# Кастомные ответы — HTML, поток, файл и другие { #custom-response-html-stream-file-others }

По умолчанию **FastAPI** возвращает ответы с помощью `JSONResponse`.

Вы можете переопределить это, вернув `Response` напрямую, как показано в разделе [Вернуть Response напрямую](response-directly.md){.internal-link target=_blank}.

Но если вы возвращаете `Response` напрямую (или любой его подкласс, например `JSONResponse`), данные не будут автоматически преобразованы (даже если вы объявили `response_model`), и документация не будет автоматически сгенерирована (например, со специфичным «типом содержимого» в HTTP-заголовке `Content-Type` как частью сгенерированного OpenAPI).

Но вы можете также объявить `Response`, который хотите использовать (например, любой подкласс `Response`), в декораторе операции пути, используя параметр `response_class`.

Содержимое, которое вы возвращаете из своей функции-обработчика пути, будет помещено внутрь этого `Response`.

И если у этого `Response` тип содержимого JSON (`application/json`), как в случае с `JSONResponse` и `UJSONResponse`, данные, которые вы возвращаете, будут автоматически преобразованы (и отфильтрованы) любым объявленным вами в декораторе операции пути Pydantic `response_model`.

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

Если вы используете класс ответа без типа содержимого, FastAPI будет ожидать, что у вашего ответа нет содержимого, поэтому он не будет документировать формат ответа в сгенерированной документации OpenAPI.

///

## Используйте `ORJSONResponse` { #use-orjsonresponse }

Например, если вы выжимаете максимум производительности, вы можете установить и использовать <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a> и задать ответ как `ORJSONResponse`.

Импортируйте класс (подкласс) `Response`, который вы хотите использовать, и объявите его в декораторе операции пути.

Для больших ответов возвращать `Response` напрямую значительно быстрее, чем возвращать словарь.

Это потому, что по умолчанию FastAPI проверяет каждый элемент внутри и убеждается, что он сериализуем в JSON, используя тот же [JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank}, объяснённый в руководстве. Это позволяет возвращать **произвольные объекты**, например модели из базы данных.

Но если вы уверены, что содержимое, которое вы возвращаете, **сериализуемо в JSON**, вы можете передать его напрямую в класс ответа и избежать дополнительных накладных расходов, которые FastAPI понёс бы, пропуская возвращаемое содержимое через `jsonable_encoder` перед передачей в класс ответа.

{* ../../docs_src/custom_response/tutorial001b.py hl[2,7] *}

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

Параметр `response_class` также используется для указания «типа содержимого» ответа.

В этом случае HTTP-заголовок `Content-Type` будет установлен в `application/json`.

И это будет задокументировано как таковое в OpenAPI.

///

/// tip | Совет

`ORJSONResponse` доступен только в FastAPI, а не в Starlette.

///

## HTML-ответ { #html-response }

Чтобы вернуть ответ с HTML напрямую из **FastAPI**, используйте `HTMLResponse`.

- Импортируйте `HTMLResponse`.
- Передайте `HTMLResponse` в параметр `response_class` вашего декоратора операции пути.

{* ../../docs_src/custom_response/tutorial002.py hl[2,7] *}

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

Параметр `response_class` также используется для указания «типа содержимого» ответа.

В этом случае HTTP-заголовок `Content-Type` будет установлен в `text/html`.

И это будет задокументировано как таковое в OpenAPI.

///

### Вернуть `Response` { #return-a-response }

Как показано в разделе [Вернуть Response напрямую](response-directly.md){.internal-link target=_blank}, вы также можете переопределить ответ прямо в своей операции пути, просто вернув его.

Тот же пример сверху, возвращающий `HTMLResponse`, может выглядеть так:

{* ../../docs_src/custom_response/tutorial003.py hl[2,7,19] *}

/// warning | Предупреждение

`Response`, возвращённый напрямую вашей функцией-обработчиком пути, не будет задокументирован в OpenAPI (например, `Content-Type` нне будет задокументирова) и не будет виден в автоматически сгенерированной интерактивной документации.

///

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

Разумеется, фактические заголовок `Content-Type`, статус-код и т.д. возьмутся из объекта `Response`, который вы вернули.

///

### Задокументировать в OpenAPI и переопределить `Response` { #document-in-openapi-and-override-response }

Если вы хотите переопределить ответ внутри функции, но при этом задокументировать «тип содержимого» в OpenAPI, вы можете использовать параметр `response_class` И вернуть объект `Response`.

Тогда `response_class` будет использоваться только для документирования *операции пути* в OpenAPI, а ваш `Response` будет использован как есть.

#### Вернуть `HTMLResponse` напрямую { #return-an-htmlresponse-directly }

Например, это может быть что-то вроде:

{* ../../docs_src/custom_response/tutorial004.py hl[7,21,23] *}

В этом примере функция `generate_html_response()` уже генерирует и возвращает `Response` вместо возврата HTML в `str`.

Возвращая результат вызова `generate_html_response()`, вы уже возвращаете `Response`, который переопределит поведение **FastAPI** по умолчанию.

Но поскольку вы также передали `HTMLResponse` в `response_class`, **FastAPI** будет знать, как задокументировать это в OpenAPI и интерактивной документации как HTML с `text/html`:

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

## Доступные ответы { #available-responses }

Ниже перечислены некоторые доступные классы ответов.

Учтите, что вы можете использовать `Response`, чтобы вернуть что угодно ещё, или даже создать собственный подкласс.

/// note | Технические детали

Вы также могли бы использовать `from starlette.responses import HTMLResponse`.

**FastAPI** предоставляет те же `starlette.responses` как `fastapi.responses` для вашего удобства как разработчика. Но большинство доступных классов ответов приходят непосредственно из Starlette.

///

### `Response` { #response }

Базовый класс `Response`, от него наследуются все остальные ответы.

Его можно возвращать напрямую.

Он принимает следующие параметры:

- `content` — `str` или `bytes`.
- `status_code` — целое число, HTTP статус-код.
- `headers` — словарь строк.
- `media_type` — строка, задающая тип содержимого. Например, `"text/html"`.

FastAPI (фактически Starlette) автоматически добавит заголовок Content-Length. Также будет добавлен заголовок Content-Type, основанный на `media_type` и с добавлением charset для текстовых типов.

{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *}

### `HTMLResponse` { #htmlresponse }

Принимает текст или байты и возвращает HTML-ответ, как описано выше.

### `PlainTextResponse` { #plaintextresponse }

Принимает текст или байты и возвращает ответ в виде простого текста.

{* ../../docs_src/custom_response/tutorial005.py hl[2,7,9] *}

### `JSONResponse` { #jsonresponse }

Принимает данные и возвращает ответ, кодированный как `application/json`.

Это ответ по умолчанию, используемый в **FastAPI**, как было сказано выше.

### `ORJSONResponse` { #orjsonresponse }

Быстрая альтернативная реализация JSON-ответа с использованием <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>, как было сказано выше.

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

Требуется установка `orjson`, например командой `pip install orjson`.

///

### `UJSONResponse` { #ujsonresponse }

Альтернативная реализация JSON-ответа с использованием <a href="https://github.com/ultrajson/ultrajson" class="external-link" target="_blank">`ujson`</a>.

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

Требуется установка `ujson`, например командой `pip install ujson`.

///

/// warning | Предупреждение

`ujson` менее аккуратен, чем встроенная реализация Python, в обработке некоторых крайних случаев.

///

{* ../../docs_src/custom_response/tutorial001.py hl[2,7] *}

/// tip | Совет

Возможно, `ORJSONResponse` окажется более быстрым вариантом.

///

### `RedirectResponse` { #redirectresponse }

Возвращает HTTP-редирект. По умолчанию использует статус-код 307 (Temporary Redirect — временное перенаправление).

Вы можете вернуть `RedirectResponse` напрямую:

{* ../../docs_src/custom_response/tutorial006.py hl[2,9] *}

---

Или можно использовать его в параметре `response_class`:

{* ../../docs_src/custom_response/tutorial006b.py hl[2,7,9] *}

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

В этом случае будет использован статус-код по умолчанию для `RedirectResponse`, то есть `307`.

---

Также вы можете использовать параметр `status_code` в сочетании с параметром `response_class`:

{* ../../docs_src/custom_response/tutorial006c.py hl[2,7,9] *}

### `StreamingResponse` { #streamingresponse }

Принимает асинхронный генератор или обычный генератор/итератор и отправляет тело ответа потоково.

{* ../../docs_src/custom_response/tutorial007.py hl[2,14] *}

#### Использование `StreamingResponse` с файлоподобными объектами { #using-streamingresponse-with-file-like-objects }

Если у вас есть <a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">файлоподобный</a> объект (например, объект, возвращаемый `open()`), вы можете создать функцию-генератор для итерации по этому файлоподобному объекту.

Таким образом, вам не нужно сначала читать всё в память, вы можете передать эту функцию-генератор в `StreamingResponse` и вернуть его.

Это включает многие библиотеки для работы с облачным хранилищем, обработки видео и т.д.

{* ../../docs_src/custom_response/tutorial008.py hl[2,10:12,14] *}

1. Это функция-генератор. Она является «функцией-генератором», потому что содержит оператор(ы) `yield` внутри.
2. Используя блок `with`, мы гарантируем, что файлоподобный объект будет закрыт после завершения работы функции-генератора. То есть после того, как она закончит отправку ответа.
3. Этот `yield from` говорит функции итерироваться по объекту с именем `file_like`. И затем, для каждой итерации, отдавать эту часть как исходящую из этой функции-генератора (`iterfile`).

   Таким образом, это функция-генератор, которая внутренне передаёт работу по «генерации» чему-то другому.

   Делая это таким образом, мы можем поместить её в блок `with` и тем самым гарантировать, что файлоподобный объект будет закрыт после завершения.

/// tip | Совет

Заметьте, что здесь мы используем стандартный `open()`, который не поддерживает `async` и `await`, поэтому объявляем операцию пути обычной `def`.

///

### `FileResponse` { #fileresponse }

Асинхронно отправляет файл как ответ.

Для создания экземпляра принимает иной набор аргументов, чем другие типы ответов:

- `path` — путь к файлу, который будет отправлен.
- `headers` — любые дополнительные заголовки для включения, в виде словаря.
- `media_type` — строка, задающая тип содержимого. Если не задан, для определения типа содержимого будет использовано имя файла или путь.
- `filename` — если задан, будет включён в заголовок ответа `Content-Disposition`.

Файловые ответы будут содержать соответствующие заголовки `Content-Length`, `Last-Modified` и `ETag`.

{* ../../docs_src/custom_response/tutorial009.py hl[2,10] *}

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

{* ../../docs_src/custom_response/tutorial009b.py hl[2,8,10] *}

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

## Пользовательский класс ответа { #custom-response-class }

Вы можете создать собственный класс ответа, унаследовавшись от `Response`, и использовать его.

Например, предположим, что вы хотите использовать <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>, но с некоторыми пользовательскими настройками, которые не используются во встроенном классе `ORJSONResponse`.

Скажем, вы хотите, чтобы возвращался отформатированный JSON с отступами, то есть хотите использовать опцию orjson `orjson.OPT_INDENT_2`.

Вы могли бы создать `CustomORJSONResponse`. Главное, что вам нужно сделать — реализовать метод `Response.render(content)`, который возвращает содержимое как `bytes`:

{* ../../docs_src/custom_response/tutorial009c.py hl[9:14,17] *}

Теперь вместо того, чтобы возвращать:

```json
{"message": "Hello World"}
```

...этот ответ вернёт:

```json
{
  "message": "Hello World"
}
```

Разумеется, вы наверняка найдёте гораздо более полезные способы воспользоваться этим, чем просто форматирование JSON. 😉

## Класс ответа по умолчанию { #default-response-class }

При создании экземпляра класса **FastAPI** или `APIRouter` вы можете указать, какой класс ответа использовать по умолчанию.

Параметр, который это определяет, — `default_response_class`.

В примере ниже **FastAPI** будет использовать `ORJSONResponse` по умолчанию во всех операциях пути вместо `JSONResponse`.

{* ../../docs_src/custom_response/tutorial010.py hl[2,4] *}

/// tip | Совет

Вы по-прежнему можете переопределять `response_class` в операциях пути, как и раньше.

///

## Дополнительная документация { #additional-documentation }

Вы также можете объявить тип содержимого и многие другие детали в OpenAPI с помощью `responses`: [Дополнительные ответы в OpenAPI](additional-responses.md){.internal-link target=_blank}.
