# Потокова передача даних { #stream-data }

Якщо ви хочете передавати потоком дані, які можна структурувати як JSON, див. [Потокова передача JSON Lines](../tutorial/stream-json-lines.md).

Але якщо ви хочете передавати потоком чисті бінарні дані або строки, ось як це зробити.

/// info | Інформація

Додано у FastAPI 0.134.0.

///

## Варіанти використання { #use-cases }

Це можна використовувати, якщо ви хочете передавати потоком чисті строки, наприклад безпосередньо з виводу сервісу AI LLM.

Також це можна використати для потокової передачі великих бінарних файлів, коли ви надсилаєте кожний фрагмент даних під час читання, без потреби завантажувати все в пам'ять одразу.

Так само можна стрімити відео чи аудіо; їх навіть можна генерувати під час обробки та надсилання.

## `StreamingResponse` з `yield` { #a-streamingresponse-with-yield }

Якщо ви оголосите `response_class=StreamingResponse` у вашій функції операції шляху, ви можете використовувати `yield`, щоб послідовно надсилати кожний фрагмент даних.

{* ../../docs_src/stream_data/tutorial001_py310.py ln[1:23] hl[20,23] *}

FastAPI передаватиме кожний фрагмент даних до `StreamingResponse` як є; він не намагатиметься перетворити його на JSON чи щось подібне.

### Не-async функції операції шляху { #non-async-path-operation-functions }

Можна також використовувати звичайні функції `def` (без `async`) і так само застосовувати `yield`.

{* ../../docs_src/stream_data/tutorial001_py310.py ln[26:29] hl[27] *}

### Без анотації { #no-annotation }

Для потокової передачі бінарних даних немає потреби оголошувати анотацію типу, що повертається.

Оскільки FastAPI не намагатиметься перетворювати дані на JSON за допомогою Pydantic чи серіалізувати їх іншим чином, у цьому випадку анотація типу потрібна лише для вашого редактора та інструментів; FastAPI її не використовуватиме.

{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}

Це також означає, що з `StreamingResponse` у вас є свобода і відповідальність формувати та кодувати байти даних саме так, як їх потрібно надіслати, незалежно від анотацій типів. 🤓

### Потік байтів { #stream-bytes }

Один з основних сценаріїв - передавати потоком `bytes` замість строк; це, звісно, підтримується.

{* ../../docs_src/stream_data/tutorial001_py310.py ln[44:47] hl[47] *}

## Користувацький `PNGStreamingResponse` { #a-custom-pngstreamingresponse }

У наведених вище прикладах байти даних передавалися потоком, але у відповіді не було заголовка `Content-Type`, тому клієнт не знав, який тип даних він отримує.

Можна створити власний підклас `StreamingResponse`, який встановлює заголовок `Content-Type` відповідно до типу даних, що ви стрімите.

Наприклад, можна створити `PNGStreamingResponse`, який встановлює заголовок `Content-Type` у `image/png` за допомогою атрибута `media_type`:

{* ../../docs_src/stream_data/tutorial002_py310.py ln[6,19:20] hl[20] *}

Потім ви можете використати цей новий клас у `response_class=PNGStreamingResponse` у вашій функції операції шляху:

{* ../../docs_src/stream_data/tutorial002_py310.py ln[23:27] hl[23] *}

### Симулювати файл { #simulate-a-file }

У цьому прикладі ми імітуємо файл за допомогою `io.BytesIO` - це об'єкт на кшталт файлу, який існує лише в пам'яті, але надає той самий інтерфейс.

Наприклад, ми можемо ітеруватися по ньому, щоб зчитати вміст, так само як і з файлом.

{* ../../docs_src/stream_data/tutorial002_py310.py ln[1:27] hl[3,12:13,25] *}

/// note | Технічні деталі

Інші дві змінні, `image_base64` та `binary_image`, - це зображення, закодоване в Base64, яке потім перетворюється на байти, щоб передати його в `io.BytesIO`.

Лише для того, щоб усе містилося в одному файлі для цього прикладу, і ви могли скопіювати його та запустити як є. 🥚

///

Використовуючи блок `with`, ми гарантуємо, що об'єкт, подібний до файлу, буде закрито після завершення генераторної функції (функції з `yield`). Тобто після завершення надсилання відповіді.

У цьому конкретному прикладі це не так важливо, адже це фальшивий файл у пам'яті (з `io.BytesIO`), але для справжнього файлу важливо переконатися, що файл закрито після завершення роботи з ним.

### Файли та async { #files-and-async }

У більшості випадків об'єкти, подібні до файлів, за замовчуванням несумісні з `async` та `await`.

Наприклад, у них немає `await file.read()` або `async for chunk in file`.

І часто їх читання є блокувальною операцією (що може блокувати цикл подій), адже дані зчитуються з диска або мережі.

/// info | Інформація

Наведений вище приклад - виняток, адже об'єкт `io.BytesIO` вже в пам'яті, тож читання нічого не блокує.

Але в багатьох випадках читання файлу або схожого на файл об'єкта блокує виконання.

///

Щоб уникнути блокування циклу подій, просто оголосіть функцію операції шляху зі звичайним `def` замість `async def`. Тоді FastAPI виконуватиме її в працівнику пулу потоків, щоб не блокувати головний цикл.

{* ../../docs_src/stream_data/tutorial002_py310.py ln[30:34] hl[31] *}

/// tip | Порада

Якщо вам потрібно викликати блокувальний код усередині async-функції або async-функцію зсередини блокувальної функції, ви можете скористатися [Asyncer](https://asyncer.tiangolo.com) - спорідненою бібліотекою до FastAPI.

///

### `yield from` { #yield-from }

Коли ви ітеруєтеся по чомусь, наприклад по об'єкту, подібному до файлу, і робите `yield` для кожного елемента, можна також використати `yield from`, щоб віддавати кожен елемент напряму і пропустити цикл `for`.

Це не специфічно для FastAPI, це просто Python, але корисний трюк. 😎

{* ../../docs_src/stream_data/tutorial002_py310.py ln[37:40] hl[40] *}
