You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

17 KiB

Користувацька відповідь - HTML, стрім, файл, інше

Типово FastAPI повертатиме JSON-відповіді.

Ви можете переписати це, повернувши Response безпосередньо, як показано в Повернути відповідь безпосередньо.

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

Ви також можете оголосити Response, який слід використовувати (наприклад, будь-який підклас Response), у декораторі операції шляху через параметр response_class.

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

/// note | Примітка

Якщо ви використовуєте клас відповіді без медіа-типу, FastAPI очікуватиме, що у вашої відповіді не буде вмісту, тож формат відповіді не буде задокументовано в згенерованій документації OpenAPI.

///

JSON-відповіді

Типово FastAPI повертає JSON-відповіді.

Якщо ви оголосите Модель відповіді, FastAPI використає її, щоб серіалізувати дані в JSON за допомогою Pydantic.

Якщо ви не оголосите модель відповіді, FastAPI використає jsonable_encoder, пояснений у Сумісний кодувальник JSON, і помістить результат у JSONResponse.

Якщо ви оголосите response_class з JSON медіа-типом (application/json), як у випадку з JSONResponse, дані, що повертаються, будуть автоматично перетворені (і відфільтровані) згідно з будь-якою Pydantic response_model, яку ви оголосили в декораторі операції шляху. Але дані не будуть серіалізовані в JSON-байти за допомогою Pydantic, натомість вони будуть перетворені з jsonable_encoder, а потім передані класу JSONResponse, який і серіалізує їх у байти, використовуючи стандартну JSON-бібліотеку в Python.

Продуктивність JSON

Коротко: якщо вам потрібна максимальна продуктивність, використовуйте Модель відповіді і не оголошуйте response_class у декораторі операції шляху.

{* ../../docs_src/response_model/tutorial001_01_py310.py ln[15:17] hl[16] *}

HTML-відповідь

Щоб повернути відповідь із HTML безпосередньо з FastAPI, використовуйте HTMLResponse.

  • Імпортуйте HTMLResponse.
  • Передайте HTMLResponse як параметр response_class вашого декоратора операції шляху.

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

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

Параметр response_class також визначатиме «медіа-тип» відповіді.

У цьому випадку HTTP-заголовок Content-Type буде встановлено в text/html.

І це буде задокументовано відповідно в OpenAPI.

///

Повернути Response

Як показано в Повернути відповідь безпосередньо, ви також можете переписати відповідь безпосередньо у вашій операції шляху, просто повернувши її.

Той самий приклад вище, що повертає HTMLResponse, може виглядати так:

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

/// warning | Попередження

Response, повернений безпосередньо вашою функцією операції шляху, не буде задокументовано в OpenAPI (наприклад, Content-Type не буде задокументовано) і не буде видно в автоматичній інтерактивній документації.

///

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

Звісно, фактичні заголовок Content-Type, код статусу тощо прийдуть з об'єкта Response, який ви повернули.

///

Задокументуйте в OpenAPI і перепишіть Response

Якщо ви хочете переписати відповідь усередині функції, але водночас задокументувати «медіа-тип» в OpenAPI, ви можете використати параметр response_class І повернути об'єкт Response.

Тоді response_class буде використано лише для документування операції шляху в OpenAPI, а ваша Response буде використана як є.

Повернути HTMLResponse безпосередньо

Наприклад, це може бути щось на кшталт:

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

У цьому прикладі функція generate_html_response() уже генерує та повертає Response замість повернення HTML як str.

Повертаючи результат виклику generate_html_response(), ви вже повертаєте Response, яка перепише типову поведінку FastAPI.

Але оскільки ви також передали HTMLResponse у response_class, FastAPI знатиме, як задокументувати це в OpenAPI та інтерактивній документації як HTML з text/html:

Доступні відповіді

Ось деякі з доступних відповідей.

Майте на увазі, що ви можете використовувати Response, щоб повертати що завгодно інше, або навіть створити власний підклас.

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

Ви також можете використати from starlette.responses import HTMLResponse.

FastAPI надає ті ж starlette.responses як fastapi.responses лише для вашої зручності як розробника. Але більшість доступних відповідей надходять безпосередньо зі Starlette.

///

Response

Головний клас Response, від якого успадковуються всі інші відповіді.

Ви можете повертати його безпосередньо.

Він приймає такі параметри:

  • content - str або bytes.
  • status_code - int - код статусу HTTP.
  • headers - dict строк.
  • media_type - str, що задає медіа-тип, напр. "text/html".

FastAPI (насправді Starlette) автоматично додасть заголовок Content-Length. Також буде додано заголовок Content-Type на основі media_type з додаванням набору символів для текстових типів.

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

HTMLResponse

Приймає текст або байти та повертає HTML-відповідь, як описано вище.

PlainTextResponse

Приймає текст або байти та повертає відповідь звичайним текстом.

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

JSONResponse

Приймає дані та повертає відповідь, закодовану як application/json.

Це типова відповідь, яку використовує FastAPI, як зазначено вище.

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

Але якщо ви оголосите модель відповіді або тип, його буде використано безпосередньо для серіалізації даних у JSON, і відповідь з коректним медіа-типом для JSON буде повернута безпосередньо, без використання класу JSONResponse.

Це ідеальний спосіб отримати найкращу продуктивність.

///

RedirectResponse

Повертає HTTP-перенаправлення. Типово використовує код статусу 307 (Temporary Redirect).

Ви можете повернути RedirectResponse безпосередньо:

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


Або ви можете використати його в параметрі response_class:

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

У такому разі ви можете повертати URL безпосередньо з вашої функції операції шляху.

У цьому випадку status_code буде типовим для RedirectResponse, тобто 307.


Ви також можете використати параметр status_code разом із параметром response_class:

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

StreamingResponse

Приймає async-генератор або звичайний генератор/ітератор (функцію з yield) і потоково передає тіло відповіді.

{* ../../docs_src/custom_response/tutorial007_py310.py hl[3,16] *}

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

Завдання async може бути скасовано лише тоді, коли воно досягає await. Якщо немає await, генератор (функція з yield) не може бути коректно скасований і може продовжувати працювати навіть після запиту на скасування.

Оскільки цьому невеликому прикладу не потрібні жодні оператори await, ми додаємо await anyio.sleep(0), щоб надати циклу подій шанс обробити скасування.

Це ще важливіше для великих або нескінченних потоків.

///

/// tip | Порада

Замість того щоб повертати StreamingResponse безпосередньо, імовірно, краще дотримуватися стилю в Потокова передача даних, це значно зручніше та обробляє скасування «за лаштунками» для вас.

Якщо ви транслюєте JSON Lines, дотримуйтесь навчального посібника Потоки JSON Lines.

///

FileResponse

Асинхронно транслює файл як відповідь.

Приймає інший набір аргументів для створення екземпляра, ніж інші типи відповідей:

  • path - шлях до файлу для трансляції.
  • headers - будь-які користувацькі заголовки як словник.
  • media_type - строка, що задає медіа-тип. Якщо не встановлено, медіа-тип буде виведено з імені файлу або шляху.
  • filename - якщо встановлено, буде включено до Content-Disposition відповіді.

Відповіді з файлами включатимуть відповідні заголовки Content-Length, Last-Modified і ETag.

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

Ви також можете використати параметр response_class:

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

У цьому випадку ви можете повертати шлях до файлу безпосередньо з вашої функції операції шляху.

Власний клас відповіді

Ви можете створити власний клас відповіді, успадкувавши його від Response, і використовувати його.

Наприклад, скажімо, ви хочете використовувати orjson з деякими налаштуваннями.

Припустімо, ви хочете, щоб повертався відформатований із відступами JSON, тож ви хочете використати опцію orjson orjson.OPT_INDENT_2.

Ви можете створити CustomORJSONResponse. Головне, що потрібно зробити, це створити метод Response.render(content), який повертає вміст як bytes:

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

Тепер замість повернення:

{"message": "Hello World"}

...ця відповідь повертатиме:

{
  "message": "Hello World"
}

Звісно, ви, ймовірно, знайдете значно кращі способи скористатися цим, ніж просто форматування JSON. 😉

orjson або Модель відповіді

Якщо ви шукаєте продуктивність, імовірно, краще використати Модель відповіді, ніж відповідь orjson.

З моделлю відповіді FastAPI використає Pydantic, щоб серіалізувати дані в JSON без проміжних кроків, як-от перетворення за допомогою jsonable_encoder, що відбувалося б в іншому випадку.

І «під капотом» Pydantic використовує ті самі внутрішні механізми Rust, що й orjson, для серіалізації в JSON, тож ви вже отримаєте найкращу продуктивність із моделлю відповіді.

Типова відповідь за замовчуванням

Створюючи екземпляр класу FastAPI або APIRouter, ви можете вказати, який клас відповіді використовувати за замовчуванням.

Параметр, що це визначає, - default_response_class.

У прикладі нижче FastAPI використовуватиме HTMLResponse за замовчуванням в усіх операціях шляху, замість JSON.

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

/// tip | Порада

Ви все одно можете переписати response_class в операціях шляху, як і раніше.

///

Додаткова документація

Ви також можете оголосити медіа-тип і багато інших деталей в OpenAPI, використовуючи responses: Додаткові відповіді в OpenAPI.