# Додаткові коди статусу { #additional-status-codes }
За замовчуванням **FastAPI** повертатиме відповіді за допомогою `JSONResponse`, поміщаючи вміст, який ви повертаєте з вашої *операції шляху*, у цей `JSONResponse`.
Він використовуватиме код статусу за замовчуванням або той, який ви встановите у своїй *операції шляху*.
Усе це може здаватися надуманим. І поки що може бути не дуже зрозуміло, навіщо це корисно.
@ -66,7 +66,7 @@ checker(q="somequery")
## Залежності з `yield`, `HTTPException`, `except` та фоновими задачами { #dependencies-with-yield-httpexception-except-and-background-tasks }
/// warning
/// warning | Попередження
Найімовірніше, вам не знадобляться ці технічні деталі.
@ -78,7 +78,7 @@ checker(q="somequery")
### Залежності з `yield` і `scope` { #dependencies-with-yield-and-scope }
У версії 0.121.0 **FastAPI** додано підтримку `Depends(scope="function")` для залежностей з `yield`.
У версії 0.121.0 FastAPI додано підтримку `Depends(scope="function")` для залежностей з `yield`.
З `Depends(scope="function")` завершальний код після `yield` виконується одразу після завершення *функції операції шляху*, до того як відповідь буде надіслана клієнту.
@ -88,7 +88,7 @@ checker(q="somequery")
### Залежності з `yield` і `StreamingResponse`, технічні деталі { #dependencies-with-yield-and-streamingresponse-technical-details }
До **FastAPI** 0.118.0, якщо ви використовували залежність із `yield`, завершальний код виконувався після повернення з *функції операції шляху*, але безпосередньо перед відправленням відповіді.
До FastAPI 0.118.0, якщо ви використовували залежність із `yield`, завершальний код виконувався після повернення з *функції операції шляху*, але безпосередньо перед відправленням відповіді.
Метою було уникнути утримання ресурсів довше, ніж потрібно, очікуючи, поки відповідь пройде мережею.
@ -98,7 +98,7 @@ checker(q="somequery")
Цю поведінку змінено у 0.118.0: завершальний код після `yield` знову виконується після відправлення відповіді.
/// note
/// note | Примітка
Як побачите нижче, це дуже схоже на поведінку до версії 0.106.0, але з кількома покращеннями та виправленнями помилок у крайових випадках.
@ -138,19 +138,19 @@ checker(q="somequery")
### Залежності з `yield` і `except`, технічні деталі { #dependencies-with-yield-and-except-technical-details }
До **FastAPI** 0.110.0, якщо ви використовували залежність із `yield`, перехоплювали виняток через `except` у цій залежності і не піднімали його знову, виняток автоматично піднімався/пересилався до будь-яких обробників винятків або внутрішнього обробника помилок сервера.
До FastAPI 0.110.0, якщо ви використовували залежність із `yield`, перехоплювали виняток через `except` у цій залежності і не піднімали його знову, виняток автоматично піднімався/пересилався до будь-яких обробників винятків або внутрішнього обробника помилок сервера.
Це змінено у версії 0.110.0, щоб усунути неконтрольоване споживання пам'яті від пересланих винятків без обробника (внутрішні помилки сервера) та зробити поведінку узгодженою зі звичайним Python-кодом.
### Фонові задачі та залежності з `yield`, технічні деталі { #background-tasks-and-dependencies-with-yield-technical-details }
До **FastAPI** 0.106.0 піднімати винятки після `yield` було неможливо: завершальний код у залежностях з `yield` виконувався після надсилання відповіді, тож [обробники винятків](../tutorial/handling-errors.md#install-custom-exception-handlers) уже відпрацювали б.
До FastAPI 0.106.0 піднімати винятки після `yield` було неможливо: завершальний код у залежностях з `yield` виконувався після надсилання відповіді, тож [обробники винятків](../tutorial/handling-errors.md#install-custom-exception-handlers) уже відпрацювали б.
Так було спроєктовано головно для того, щоб дозволити використовувати ті самі об'єкти, «віддані» залежностями через `yield`, усередині фонових задач, оскільки завершальний код виконувався після завершення фонових задач.
У **FastAPI** 0.106.0 це змінено, щоб не утримувати ресурси під час очікування, поки відповідь піде мережею.
У FastAPI 0.106.0 це змінено, щоб не утримувати ресурси під час очікування, поки відповідь піде мережею.
/// tip
/// tip | Порада
Крім того, фонова задача зазвичай є незалежним набором логіки, який слід обробляти окремо, з власними ресурсами (наприклад, власним з'єднанням з базою даних).
@ -160,4 +160,4 @@ checker(q="somequery")
Якщо ви раніше покладалися на цю поведінку, тепер слід створювати ресурси для фонових задач усередині самої фонової задачі та використовувати всередині лише дані, що не залежать від ресурсів залежностей із `yield`.
Наприклад, замість використання тієї самої сесії бази даних ви створюватимете нову сесію в самій фоновій задачі та отримуватимете об'єкти з бази даних, використовуючи Цю нову сесію. І далі, замість передавання об'єкта з бази даних як параметра у функцію фонової задачі, ви передасте ідентифікатор цього об'єкта, а потім отримаєте об'єкт знову всередині функції фонової задачі.
Наприклад, замість використання тієї самої сесії бази даних ви створюватимете нову сесію в самій фоновій задачі та отримуватимете об'єкти з бази даних, використовуючи цю нову сесію. І далі, замість передавання об'єкта з бази даних як параметра у функцію фонової задачі, ви передасте ідентифікатор цього об'єкта, а потім отримаєте об'єкт знову всередині функції фонової задачі.
Ви можете визначити логіку (код), яку слід виконати перед тим, як застосунок запуститься. Це означає, що цей код буде виконано один раз, перед тим як застосунок почне отримувати запити.
Ви можете визначити логіку (код), яку слід виконати перед тим, як застосунок **запуститься**. Це означає, що цей код буде виконано **один раз**, **перед** тим як застосунок **почне отримувати запити**.
Так само ви можете визначити логіку (код), яку слід виконати під час вимкнення застосунку. У цьому випадку код буде виконано один раз, після обробки можливо багатьох запитів.
Так само ви можете визначити логіку (код), яку слід виконати під час **вимкнення** застосунку. У цьому випадку код буде виконано **один раз**, після обробки можливо **багатьох запитів**.
Оскільки цей код виконується перед тим, як застосунок почне приймати запити, і одразу після того, як він завершить їх обробку, він охоплює всю тривалість життя застосунку (слово «lifespan» буде важливим за мить 😉).
Оскільки цей код виконується перед тим, як застосунок **почне** приймати запити, і одразу після того, як він **завершить** їх обробку, він охоплює всю **тривалість життя** застосунку (слово «lifespan» буде важливим за мить 😉).
Це дуже корисно для налаштування ресурсів, які потрібні для всього застосунку, які спільні між запитами, та/або які потрібно потім прибрати. Наприклад, пул з’єднань з базою даних або завантаження спільної моделі машинного навчання.
Це дуже корисно для налаштування **ресурсів**, які потрібні для всього застосунку, які **спільні** між запитами, та/або які потрібно потім **прибрати**. Наприклад, пул з’єднань з базою даних або завантаження спільної моделі машинного навчання.
## Випадок використання { #use-case }
Почнемо з прикладу випадку використання, а потім подивимось, як це вирішити.
Почнемо з прикладу **випадку використання**, а потім подивимось, як це вирішити.
Уявімо, що у вас є моделі машинного навчання, якими ви хочете обробляти запити. 🤖
Уявімо, що у вас є **моделі машинного навчання**, якими ви хочете обробляти запити. 🤖
Ті самі моделі спільні між запитами, тобто це не окрема модель на запит чи на користувача.
Уявімо, що завантаження моделі може займати чимало часу, бо треба читати багато даних з диска. Тож ви не хочете робити це для кожного запиту.
Уявімо, що завантаження моделі може **займати чимало часу**, бо треба читати багато **даних з диска**. Тож ви не хочете робити це для кожного запиту.
Ви могли б завантажити її на верхньому рівні модуля/файлу, але це означало б, що модель завантажиться навіть якщо ви просто запускаєте простий автоматизований тест - тоді тест буде повільним, бо йому доведеться чекати завантаження моделі перед виконанням незалежної частини коду.
Ви могли б завантажити її на верхньому рівні модуля/файлу, але це означало б, що модель **завантажиться** навіть якщо ви просто запускаєте простий автоматизований тест - тоді тест буде **повільним**, бо йому доведеться чекати завантаження моделі перед виконанням незалежної частини коду.
Ось це ми й вирішимо: завантажимо модель перед обробкою запитів, але лише безпосередньо перед тим, як застосунок почне отримувати запити, а не під час завантаження коду.
## Тривалість життя { #lifespan }
Ви можете визначити цю логіку запуску і вимкнення за допомогою параметра `lifespan` застосунку `FastAPI` та «менеджера контексту» (зараз покажу, що це).
Ви можете визначити цю логіку *запуску* і *вимкнення* за допомогою параметра `lifespan` застосунку `FastAPI` та «менеджера контексту» (зараз покажу, що це).
Тут ми імітуємо дорогу операцію запуску із завантаженням моделі, поміщаючи (фальшиву) функцію моделі у словник з моделями машинного навчання перед `yield`. Цей код буде виконано перед тим, як застосунок почне приймати запити, під час запуску.
Тут ми імітуємо дорогу операцію *запуску* із завантаженням моделі, поміщаючи (фальшиву) функцію моделі у словник з моделями машинного навчання перед `yield`. Цей код буде виконано **перед** тим, як застосунок **почне приймати запити**, під час *запуску*.
А одразу після `yield` ми розвантажуємо модель. Цей код буде виконано після того, як застосунок завершить обробку запитів, безпосередньо перед вимкненням. Це, наприклад, може звільнити ресурси на кшталт пам’яті або GPU.
А одразу після `yield` ми розвантажуємо модель. Цей код буде виконано **після** того, як застосунок **завершить обробку запитів**, безпосередньо перед *вимкненням*. Це, наприклад, може звільнити ресурси на кшталт пам’яті або GPU.
/// tip | Порада
Подія `shutdown` відбувається, коли ви зупиняєте застосунок.
Подія `shutdown` відбувається, коли ви **зупиняєте** застосунок.
Можливо, вам треба запустити нову версію, або ви просто втомилися її запускати. 🤷
Менеджер контексту в Python - це те, що можна використовувати в операторі `with`, наприклад, `open()` можна використовувати як менеджер контексту:
**Менеджер контексту** в Python - це те, що можна використовувати в операторі `with`, наприклад, `open()` можна використовувати як менеджер контексту:
```Python
with open("file.txt") as file:
file.read()
```
У новіших версіях Python також є асинхронний менеджер контексту. Його використовують з `async with`:
У новіших версіях Python також є **асинхронний менеджер контексту**. Його використовують з `async with`:
```Python
async with lifespan(app):
@ -80,7 +80,7 @@ async with lifespan(app):
У нашому прикладі коду вище ми не використовуємо його напряму, а передаємо його до FastAPI, щоб він його використав.
Параметр `lifespan` застосунку `FastAPI` приймає асинхронний менеджер контексту, тож ми можемо передати йому наш новий асинхронний менеджер контексту `lifespan`.
Параметр `lifespan` застосунку `FastAPI` приймає **асинхронний менеджер контексту**, тож ми можемо передати йому наш новий асинхронний менеджер контексту `lifespan`.
Рекомендований спосіб обробляти запуск і вимкнення - використовувати параметр `lifespan` застосунку `FastAPI`, як описано вище. Якщо ви надаєте параметр `lifespan`, обробники подій `startup` і `shutdown` більше не будуть викликані. Або все через `lifespan`, або все через події - не обидва одночасно.
Рекомендований спосіб обробляти *запуск* і *вимкнення* - використовувати параметр `lifespan` застосунку `FastAPI`, як описано вище. Якщо ви надаєте параметр `lifespan`, обробники подій `startup` і `shutdown` більше не будуть викликані. Або все через `lifespan`, або все через події - не обидва одночасно.
Можете, ймовірно, пропустити цю частину.
///
Є альтернативний спосіб визначити логіку, яку слід виконати під час запуску і під час вимкнення.
Є альтернативний спосіб визначити логіку, яку слід виконати під час *запуску* і під час *вимкнення*.
Ви можете визначити обробники подій (функції), які потрібно виконати перед запуском застосунку або коли застосунок вимикається.
@ -130,7 +130,7 @@ async with lifespan(app):
Зауважте, що в цьому випадку ми використовуємо стандартну Python-функцію `open()`, яка працює з файлом.
Тобто вона включає I/O (input/output), де потрібно «чекати», поки дані буде записано на диск.
Тобто вона включає I/O (введення/виведення), де потрібно «чекати», поки дані буде записано на диск.
Але `open()` не використовує `async` і `await`.
@ -140,7 +140,7 @@ async with lifespan(app):
### Разом `startup` і `shutdown` { #startup-and-shutdown-together }
Велика ймовірність, що логіка для вашого запуску і вимкнення пов’язана: ви можете хотіти щось запустити, а потім завершити, отримати ресурс, а потім звільнити його тощо.
Велика ймовірність, що логіка для вашого *запуску* і *вимкнення* пов’язана: ви можете хотіти щось запустити, а потім завершити, отримати ресурс, а потім звільнити його тощо.
Робити це в окремих функціях, які не діляться логікою чи змінними, складніше - доведеться зберігати значення у глобальних змінних або вдаватися до подібних трюків.
@ -154,7 +154,7 @@ async with lifespan(app):
/// note | Примітка
Ви можете прочитати більше про обробники `lifespan` у [документації Starlette про Lifespan](https://www.starlette.dev/lifespan/).
Ви можете прочитати більше про обробники `lifespan`Starlette у [документації Starlette про Lifespan](https://www.starlette.dev/lifespan/).
Зокрема, як працювати зі станом тривалості життя, який можна використовувати в інших ділянках вашого коду.
Універсальним варіантом є [OpenAPI Generator](https://openapi-generator.tech/), який підтримує **багато мов програмування** та може генерувати SDK з вашої специфікації OpenAPI.
Для **клієнтів TypeScript** [Hey API](https://heyapi.dev/) — спеціалізоване рішення, що надає оптимізований досвід для екосистеми TypeScript.
Для **клієнтів TypeScript** [Hey API](https://heyapi.dev/) - спеціалізоване рішення, що надає оптимізований досвід для екосистеми TypeScript.
Більше генераторів SDK ви можете знайти на [OpenAPI.Tools](https://openapi.tools/#sdk).
## Генератори SDK від спонсорів FastAPI { #sdk-generators-from-fastapi-sponsors }
У цьому розділі представлено рішення від компаній, що спонсорують FastAPI: вони мають **венчурну підтримку** та **корпоративну підтримку**. Ці продукти надають **додаткові можливості** та **інтеграції** поверх високоякісно згенерованих SDK.
Завдяки ✨ [**спонсорству FastAPI**](../help-fastapi.md#sponsor-the-author) ✨ ці компанії допомагають підтримувати фреймворк та його **екосистему** здоровими та **сталими**.
Їхня підтримка також демонструє сильну відданість **спільноті** FastAPI (вам), показуючи, що їм важливо не лише надавати **відмінний сервіс**, а й підтримувати **міцний і процвітаючий фреймворк**, FastAPI. 🙇
Деякі з цих рішень також можуть бути з відкритим кодом або мати безкоштовні тарифи, тож ви можете спробувати їх без фінансових зобов'язань. Інші комерційні генератори SDK також доступні й їх можна знайти онлайн. 🤓
## Створити TypeScript SDK { #create-a-typescript-sdk }
Насамперед розгляньте, чи можете ви використати [Файли запиту](../tutorial/request-files.md) для завантаження двійкових даних і [Користувацька відповідь - FileResponse](./custom-response.md#fileresponse--fileresponse-) для надсилання двійкових даних замість кодування їх у JSON.
Насамперед розгляньте, чи можете ви використати [Файли запиту](../tutorial/request-files.md) для завантаження двійкових даних і [Користувацька відповідь - FileResponse](./custom-response.md#fileresponse) для надсилання двійкових даних замість кодування їх у JSON.
JSON може містити лише строки, закодовані в UTF-8, тому він не може містити «сирі» байти.
@ -14,7 +14,7 @@ Base64 може кодувати двійкові дані у строках, а
## Pydantic `bytes` { #pydantic-bytes }
Ви можете оголосити модель Pydantic з полями `bytes`, а потім використати `val_json_bytes` у конфігурації моделі, щоб вказати їй використовувати base64 для перевірки вхідних даних JSON; як частина цієї перевірки, вона декодує строку base64 у байти.
Ви можете оголосити модель Pydantic з полями `bytes`, а потім використати `val_json_bytes` у конфігурації моделі, щоб вказати їй використовувати base64 для *перевірки* вхідних даних JSON; як частина цієї перевірки, вона декодує строку base64 у байти.
@ -52,12 +52,12 @@ Base64 може кодувати двійкові дані у строках, а
## Pydantic `bytes` для вихідних даних { #pydantic-bytes-for-output-data }
Ви також можете використовувати поля `bytes` з `ser_json_bytes` у конфігурації моделі для вихідних даних, і Pydantic серіалізує байти як base64 під час формування відповіді JSON.
Ви також можете використовувати поля `bytes` з `ser_json_bytes` у конфігурації моделі для вихідних даних, і Pydantic *серіалізує* байти як base64 під час формування відповіді JSON.
## Pydantic `bytes` для вхідних і вихідних даних { #pydantic-bytes-for-input-and-output-data }
І, звісно, ви можете використовувати ту саму модель, налаштовану на base64, щоб обробляти і вхідні дані (перевіряти) з `val_json_bytes`, і вихідні дані (серіалізувати) з `ser_json_bytes` під час отримання та надсилання даних JSON.
І, звісно, ви можете використовувати ту саму модель, налаштовану на base64, щоб обробляти і вхідні дані (*перевіряти*) з `val_json_bytes`, і вихідні дані (*серіалізувати*) з `ser_json_bytes` під час отримання та надсилання даних JSON.
Ви можете створити API з операцією шляху, яка ініціюватиме запит до зовнішнього API, створеного кимось іншим (ймовірно тим самим розробником, який буде використовувати ваш API).
Ви можете створити API з *операцією шляху*, яка ініціюватиме запит до *зовнішнього API*, створеного кимось іншим (ймовірно тим самим розробником, який буде *використовувати* ваш API).
Процес, що відбувається, коли ваш застосунок API викликає зовнішній API, називається «зворотний виклик». Тому що програмне забезпечення, написане зовнішнім розробником, надсилає запит до вашого API, а потім ваш API виконує зворотний виклик, надсилаючи запит до зовнішнього API (його, ймовірно, також створив той самий розробник).
Процес, що відбувається, коли ваш застосунок API викликає *зовнішній API*, називається «зворотний виклик». Тому що програмне забезпечення, написане зовнішнім розробником, надсилає запит до вашого API, а потім ваш API *виконує зворотний виклик*, надсилаючи запит до *зовнішнього API* (його, ймовірно, також створив той самий розробник).
У такому випадку вам може знадобитися задокументувати, яким має бути той зовнішній API: які операції шляху він має мати, яке тіло очікувати, яку відповідь повертати тощо.
У такому випадку вам може знадобитися задокументувати, яким має бути той *зовнішній API*: яку *операцію шляху* він має мати, яке тіло очікувати, яку відповідь повертати тощо.
## Застосунок зі зворотними викликами { #an-app-with-callbacks }
@ -21,13 +21,13 @@
- Надсилати рахунок деякому клієнту зовнішнього розробника.
- Отримувати оплату.
- Надсилати сповіщення назад користувачу API (зовнішньому розробнику).
- Це буде зроблено шляхом надсилання POST-запиту (з вашого API) до деякого зовнішнього API, наданого тим зовнішнім розробником (це і є «зворотний виклик»).
- Це буде зроблено шляхом надсилання POST-запиту (з *вашого API*) до деякого *зовнішнього API*, наданого тим зовнішнім розробником (це і є «зворотний виклик»).
Але, можливо, найважливіша частина зворотного виклику - переконатися, що користувач вашого API (зовнішній розробник) правильно реалізує зовнішній API відповідно до даних, які ваш API надсилатиме в тілі запиту зворотного виклику тощо.
Але, можливо, найважливіша частина зворотного виклику - переконатися, що користувач вашого API (зовнішній розробник) правильно реалізує *зовнішній API* відповідно до даних, які *ваш API* надсилатиме в тілі запиту зворотного виклику тощо.
Тому далі ми додамо код, щоб задокументувати, яким має бути цей зовнішній API, щоб приймати зворотний виклик від вашого API.
Тому далі ми додамо код, щоб задокументувати, яким має бути цей *зовнішній API*, щоб приймати зворотний виклик від *вашого API*.
Ця документація з'явиться в Swagger UI за адресою `/docs` у вашому API і дасть змогу зовнішнім розробникам зрозуміти, як створити зовнішній API.
Ця документація з'явиться в Swagger UI за адресою `/docs` у вашому API і дасть змогу зовнішнім розробникам зрозуміти, як створити *зовнішній API*.
У цьому прикладі сам зворотний виклик не реалізовано (це може бути лише один рядок коду), лише частину з документацією.
## Напишіть код документації для зворотного виклику { #write-the-callback-documentation-code }
Цей код не виконуватиметься у вашому застосунку, він потрібен лише, щоб задокументувати, яким має бути зовнішній API.
Цей код не виконуватиметься у вашому застосунку, він потрібен лише, щоб *задокументувати*, яким має бути *зовнішній API*.
Але ви вже знаєте, як легко створювати автоматичну документацію для API за допомогою FastAPI.
Але ви вже знаєте, як легко створювати автоматичну документацію для API за допомогою **FastAPI**.
Тож ми скористаємося цими знаннями, щоб задокументувати, яким має бути зовнішній API... створивши операції шляху, які має реалізувати зовнішній API (ті, які викликатиме ваш API).
Тож ми скористаємося цими знаннями, щоб задокументувати, яким має бути *зовнішній API*... створивши *операції шляху*, які має реалізувати зовнішній API (ті, які викликатиме ваш API).
/// tip | Порада
Пишучи код для документування зворотного виклику, корисно уявити, що ви - той *зовнішній розробник*. І що ви зараз реалізуєте *зовнішній API*, а не *ваш API*.
Тимчасово прийнявши цю точку зору (*зовнішнього розробника*), вам буде очевидніше, куди помістити параметри, яку Pydantic-модель використати для тіла, для відповіді тощо для того *зовнішнього API*.
Тимчасово прийнявши цю точку зору (*зовнішнього розробника*), вам буде очевидніше, куди помістити параметри, яку Pydantic-модель використати для тіла, для відповіді тощо для того *зовнішнього API*.
Є 2 основні відмінності від звичайної операції шляху:
Є 2 основні відмінності від звичайної *операції шляху*:
- Їй не потрібен реальний код, адже ваш застосунок ніколи не викликатиме цей код. Вона використовується лише для документування зовнішнього API. Тому функція може просто містити `pass`.
- Шлях може містити [вираз OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) (див. нижче), де можна використовувати змінні з параметрами та частини оригінального запиту, надісланого до вашого API.
- Їй не потрібен реальний код, адже ваш застосунок ніколи не викликатиме цей код. Вона використовується лише для документування *зовнішнього API*. Тому функція може просто містити `pass`.
- *Шлях* може містити [вираз OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) (див. нижче), де можна використовувати змінні з параметрами та частини оригінального запиту, надісланого до *вашого API*.
### Вираз шляху зворотного виклику { #the-callback-path-expression }
Шлях зворотного виклику може містити [вираз OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression), який включає частини оригінального запиту, надісланого до вашого API.
*Шлях* зворотного виклику може містити [вираз OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression), який включає частини оригінального запиту, надісланого до *вашого API*.
На цьому етапі ви маєте потрібні операції шляху зворотного виклику (ті, які має реалізувати *зовнішній розробник* у *зовнішньому API*) у створеному вище маршрутизаторі зворотного виклику.
На цьому етапі ви маєте потрібні *операції шляху зворотного виклику* (ті, які має реалізувати *зовнішній розробник* у *зовнішньому API*) у створеному вище маршрутизаторі зворотного виклику.
Тепер використайте параметр `callbacks` у декораторі операції шляху вашого API, щоб передати атрибут `.routes` з цього маршрутизатора зворотного виклику:
Тепер використайте параметр `callbacks` у *декораторі операції шляху вашого API*, щоб передати атрибут `.routes` з цього маршрутизатора зворотного виклику:
Майте на увазі, що власні пропрієтарні заголовки можна додавати [за допомогою префікса `X-`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).
Але якщо у вас є власні заголовки, які клієнт у браузері має бачити, вам потрібно додати їх у вашу конфігурацію CORS (докладніше в [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md)), використовуючи параметр `expose_headers`, задокументований у [документації Starlette щодо CORS](https://www.starlette.dev/middleware/#corsmiddleware).
Але якщо у вас є власні заголовки, які клієнт у браузері має бачити, вам потрібно додати їх у вашу конфігурацію CORS (докладніше в [CORS (спільне використання ресурсів між різними джерелами)](../tutorial/cors.md)), використовуючи параметр `expose_headers`, задокументований у [документації Starlette щодо CORS](https://www.starlette.dev/middleware/#corsmiddleware).
@ -76,7 +76,7 @@ OAuth2 зі scopes - це механізм, який використовуют
Оскільки тепер ми оголошуємо ці scopes, вони з’являться в документації API, коли ви увійдете/авторизуєтеся.
І ви зможете обрати, які scopes надати доступ: `me` і `items`.
І ви зможете обрати, яким scopes надати доступ: `me` і `items`.
Це той самий механізм, який використовується, коли ви надаєте дозволи під час входу через Facebook, Google, GitHub тощо:
@ -132,7 +132,7 @@ OAuth2 зі scopes - це механізм, який використовуют
Але використовуючи `Security` замість `Depends`, **FastAPI** знатиме, що можна оголошувати scopes безпеки, використовувати їх внутрішньо та документувати API через OpenAPI.
Коли ви імпортуєте `Query`, `Path`, `Depends`, `Security` та інші з `fastapi`, це насправді функції, що повертають спеціальні класи.
Але коли ви імпортуєте `Query`, `Path`, `Depends`, `Security` та інші з `fastapi`, це насправді функції, що повертають спеціальні класи.
///
@ -152,7 +152,7 @@ OAuth2 зі scopes - це механізм, який використовуют
Параметр `security_scopes` матиме тип `SecurityScopes`.
@ -194,9 +194,9 @@ OAuth2 зі scopes - це механізм, який використовуют
Ще раз розгляньмо дерево залежностей і scopes.
Оскільки залежність `get_current_active_user` має підзалежність `get_current_user`, scope «me», оголошений у `get_current_active_user`, буде включений до списку потрібних scopes у `security_scopes.scopes`, переданого до `get_current_user`.
Оскільки залежність `get_current_active_user` має підзалежність `get_current_user`, scope `"me"`, оголошений у `get_current_active_user`, буде включений до списку потрібних scopes у `security_scopes.scopes`, переданого до `get_current_user`.
Сама операція шляху також оголошує scope «items», отже він також буде у списку `security_scopes.scopes`, переданому до `get_current_user`.
Сама операція шляху також оголошує scope `"items"`, отже він також буде у списку `security_scopes.scopes`, переданому до `get_current_user`.
## Налаштування в іншому модулі { #settings-in-another-module }
Ви можете розмістити ці налаштування в іншому модулі, як ви бачили в [Більші застосунки - кілька файлів](../tutorial/bigger-applications.md).
Ви можете розмістити ці налаштування в іншому файлі модуля, як ви бачили в [Більші застосунки - кілька файлів](../tutorial/bigger-applications.md).
Наприклад, у вас може бути файл `config.py` з:
@ -297,6 +297,6 @@ participant execute as Execute function
Ви можете використовувати Pydantic Settings для обробки налаштувань або конфігурацій вашого застосунку, з усією потужністю моделей Pydantic.
- Використовуючи залежність, ви можете спростити тестування.
- Ви можете використовувати з ним файли `.env`.
- Використання `@lru_cache` дає змогу уникнути повторного читання файла dotenv для кожного запиту, водночас дозволяючи переписувати його під час тестування.
* Використовуючи залежність, ви можете спростити тестування.
* Ви можете використовувати з ним файли `.env`.
* Використання `@lru_cache` дає змогу уникнути повторного читання файла dotenv для кожного запиту, водночас дозволяючи переписувати його під час тестування.
Якщо ви хочете передавати потоком дані, які можна структурувати як JSON, див. [Потокова передача JSON Lines](../tutorial/stream-json-lines.md).
Але якщо ви хочете передавати потоком чисті бінарні дані або строки, ось як це зробити.
Але якщо ви хочете передавати потоком **чисті бінарні дані** або строки, ось як це зробити.
/// note | Примітка
@ -12,21 +12,21 @@
## Варіанти використання { #use-cases }
Це можна використовувати, якщо ви хочете передавати потоком чисті строки, наприклад безпосередньо з виводу сервісу AI LLM.
Це можна використовувати, якщо ви хочете передавати потоком чисті строки, наприклад безпосередньо з виводу сервісу **AI LLM**.
Також це можна використати для потокової передачі великих бінарних файлів, коли ви надсилаєте кожний фрагмент даних під час читання, без потреби завантажувати все в пам'ять одразу.
Також це можна використати для потокової передачі **великих бінарних файлів**, коли ви надсилаєте кожний фрагмент даних під час читання, без потреби завантажувати все в пам'ять одразу.
Так само можна стрімити відео чи аудіо; їх навіть можна генерувати під час обробки та надсилання.
Так само можна стрімити **відео** чи **аудіо**; їх навіть можна генерувати під час обробки та надсилання.
## `StreamingResponse` з `yield` { #a-streamingresponse-with-yield }
Якщо ви оголосите `response_class=StreamingResponse` у вашій функції операції шляху, ви можете використовувати `yield`, щоб послідовно надсилати кожний фрагмент даних.
Якщо ви оголосите `response_class=StreamingResponse` у вашій *функції операції шляху*, ви можете використовувати `yield`, щоб послідовно надсилати кожний фрагмент даних.
Це також означає, що з `StreamingResponse` у вас є свобода і відповідальність формувати та кодувати байти даних саме так, як їх потрібно надіслати, незалежно від анотацій типів. 🤓
Це також означає, що з `StreamingResponse` у вас є **свобода** і **відповідальність** формувати та кодувати байти даних саме так, як їх потрібно надіслати, незалежно від анотацій типів. 🤓
### Потік байтів { #stream-bytes }
@ -58,7 +58,7 @@ FastAPI передаватиме кожний фрагмент даних до `
@ -98,7 +98,7 @@ FastAPI передаватиме кожний фрагмент даних до `
///
Щоб уникнути блокування циклу подій, просто оголосіть функцію операції шляху зі звичайним `def` замість `async def`. Тоді FastAPI виконуватиме її в працівнику пулу потоків, щоб не блокувати головний цикл.
Щоб уникнути блокування циклу подій, просто оголосіть *функцію операції шляху* зі звичайним `def` замість `async def`. Тоді FastAPI виконуватиме її в працівнику пулу потоків, щоб не блокувати головний цикл.
Flask — це «мікрофреймворк», він не включає інтеграцію бази даних, а також багато речей, які за замовчуванням є в Django.
Flask - це «мікрофреймворк», він не включає інтеграцію бази даних, а також багато речей, які за замовчуванням є в Django.
Ця простота та гнучкість дозволяють використовувати бази даних NoSQL як основну систему зберігання даних.
Оскільки він дуже простий, він порівняно легкий та інтуїтивний для освоєння, хоча в деяких моментах документація стає дещо технічною.
Оскільки він дуже простий, він порівняно інтуїтивний для освоєння, хоча в деяких моментах документація стає дещо технічною.
Він також зазвичай використовується для інших програм, яким не обов’язково потрібна база даних, керування користувачами або будь-яка з багатьох функцій, які є попередньо вбудованими в Django. Хоча багато з цих функцій можна додати за допомогою плагінів.
@ -72,7 +72,7 @@ Flask — це «мікрофреймворк», він не включає ін
Але все ж FastAPI черпав натхнення з Requests.
**Requests** — це бібліотека для *взаємодії* з API (як клієнт), а **FastAPI**— це бібліотека для *створення* API (як сервер).
**Requests** - це бібліотека для *взаємодії* з API (як клієнт), а **FastAPI**- це бібліотека для *створення* API (як сервер).
Вони більш-менш знаходяться на протилежних кінцях, доповнюючи одна одну.
@ -88,7 +88,7 @@ Requests мають дуже простий та інтуїтивно зрозу
Ці два було обрано через те, що вони досить популярні та стабільні, але, виконавши швидкий пошук, ви можете знайти десятки додаткових альтернативних інтерфейсів для OpenAPI (які можна використовувати з **FastAPI**).
@ -157,7 +157,7 @@ Marshmallow створено для забезпечення цих функці
Іншою важливою функцією, необхідною для API, є <dfntitle="читання та перетворення на дані Python">аналіз</dfn> даних із вхідних запитів.
Webargs — це інструмент, створений, щоб забезпечити це поверх кількох фреймворків, включаючи Flask.
Webargs - це інструмент, створений, щоб забезпечити це поверх кількох фреймворків, включаючи Flask.
Він використовує Marshmallow в основі для перевірки даних. І створений тими ж розробниками.
@ -239,7 +239,7 @@ Flask-apispec був створений тими ж розробниками Mar
Falcon — ще один високопродуктивний фреймворк Python, він розроблений як мінімальний і працює як основа інших фреймворків, таких як Hug.
Falcon - ще один високопродуктивний фреймворк Python, він розроблений як мінімальний і працює як основа інших фреймворків, таких як Hug.
Він розроблений таким чином, щоб мати функції, які отримують два параметри, один «запит» і один «відповідь». Потім ви «читаєте» частини запиту та «записуєте» частини у відповідь. Через такий дизайн неможливо оголосити параметри запиту та тіла за допомогою стандартних підказок типу Python як параметри функції.
Starlette — це легкий фреймворк/набір інструментів <dfntitle="Новий стандарт для створення асинхронних вебзастосунків на Python">ASGI</dfn>, який ідеально підходить для створення високопродуктивних asyncio сервісів.
Starlette - це легкий фреймворк/набір інструментів <dfntitle="Новий стандарт для створення асинхронних вебзастосунків на Python">ASGI</dfn>, який ідеально підходить для створення високопродуктивних asyncio сервісів.
Він дуже простий та інтуїтивно зрозумілий. Його розроблено таким чином, щоб його можна було легко розширювати та мати модульні компоненти.
@ -433,7 +433,7 @@ Starlette — це легкий фреймворк/набір інструмен
* CORS, GZip, статичні файли, потокові відповіді.
* Підтримку сеансів і кукі.
* 100% покриття тестом.
* 100% анотовану кодову базу.
* 100% анотовану типами кодову базу.
* Кілька жорстких залежностей.
Starlette наразі є найшвидшим фреймворком Python із перевірених. Перевершує лише Uvicorn, який є не фреймворком, а сервером.
@ -446,7 +446,7 @@ Starlette надає всі основні функції веб-мікрофр
/// note | Технічні деталі
ASGI — це новий «стандарт», який розробляється членами основної команди Django. Це ще не «стандарт Python» (PEP), хоча вони в процесі цього.
ASGI - це новий «стандарт», який розробляється членами основної команди Django. Це ще не «стандарт Python» (PEP), хоча вони в процесі цього.
Тим не менш, він уже використовується як «стандарт» кількома інструментами. Це значно покращує сумісність, оскільки ви можете переключити Uvicorn на будь-який інший сервер ASGI (наприклад, Daphne або Hypercorn), або ви можете додати інструменти, сумісні з ASGI, як-от `python-socketio`.
@ -464,9 +464,9 @@ ASGI — це новий «стандарт», який розробляєтьс
Uvicorn — це блискавичний сервер ASGI, побудований на uvloop і httptools.
Uvicorn - це блискавичний сервер ASGI, побудований на uvloop і httptools.
Це не веб-фреймворк, а сервер. Наприклад, він не надає інструментів для маршрутизації. Це те, що фреймворк на кшталт Starlette (або **FastAPI**) забезпечить поверх нього.
Це не веб-фреймворк, а сервер. Наприклад, він не надає інструментів для маршрутизації за шляхами. Це те, що фреймворк на кшталт Starlette (або **FastAPI**) забезпечить поверх нього.
Це рекомендований сервер для Starlette і **FastAPI**.
# Рівночасність і async / await { #concurrency-and-async-await }
Деталі щодо синтаксису `async def` для функцій операції шляху і деякі відомості про асинхронний код, рівночасність і паралелізм.
Деталі щодо синтаксису `async def` для *функцій операції шляху* і деякі відомості про асинхронний код, рівночасність і паралелізм.
## Поспішаєте? { #in-a-hurry }
@ -12,7 +12,7 @@
results = await some_library()
```
Тоді оголошуйте ваші функції операції шляху з `async def`, наприклад:
Тоді оголошуйте ваші *функції операції шляху* з `async def`, наприклад:
```Python hl_lines="2"
@app.get('/')
@ -29,7 +29,7 @@ async def read_results():
---
Якщо ви використовуєте сторонню бібліотеку, яка взаємодіє з чимось (база даних, API, файлова система тощо) і не підтримує використання `await` (наразі це стосується більшості бібліотек баз даних), тоді оголошуйте ваші функції операції шляху як зазвичай, просто з `def`, наприклад:
Якщо ви використовуєте сторонню бібліотеку, яка взаємодіє з чимось (база даних, API, файлова система тощо) і не підтримує використання `await` (наразі це стосується більшості бібліотек баз даних), тоді оголошуйте ваші *функції операції шляху* як зазвичай, просто з `def`, наприклад:
```Python hl_lines="2"
@app.get('/')
@ -48,7 +48,7 @@ def results():
---
Примітка: ви можете змішувати `def` і `async def` у ваших функціях операції шляху скільки завгодно і визначати кожну з них найкращим для вас способом. FastAPI зробить з ними все правильно.
**Примітка**: ви можете змішувати `def` і `async def` у ваших *функціях операції шляху* скільки завгодно і визначати кожну з них найкращим для вас способом. FastAPI зробить з ними все правильно.
У будь-якому з наведених випадків FastAPI все одно працюватиме асинхронно і буде надзвичайно швидким.
@ -56,17 +56,17 @@ def results():
## Технічні деталі { #technical-details }
Сучасні версії Python мають підтримку «асинхронного коду» за допомогою так званих «співпрограм» з синтаксисом **`async` і `await`**.
Сучасні версії Python мають підтримку **«асинхронного коду»** за допомогою так званих **«співпрограм»** з синтаксисом **`async` і `await`**.
Розгляньмо цю фразу по частинах у секціях нижче:
- Асинхронний код
- `async` і `await`
- Співпрограми
- **Асинхронний код**
- **`async` і `await`**
- **Співпрограми**
## Асинхронний код { #asynchronous-code }
Асинхронний код означає, що мова 💬 має спосіб сказати комп’ютеру/програмі 🤖, що в певний момент у коді він 🤖 має почекати, поки «щось інше» завершиться десь ще. Скажімо, це «щось інше» називається «slow-file» 📝.
Асинхронний код означає, що мова 💬 має спосіб сказати комп’ютеру/програмі 🤖, що в певний момент у коді він 🤖 має почекати, поки *«щось інше»* завершиться десь ще. Скажімо, це *«щось інше»* називається «slow-file» 📝.
Отже, в цей час комп’ютер може піти і зробити іншу роботу, доки «slow-file» 📝 завершується.
@ -97,9 +97,9 @@ def results():
Ідею **асинхронного** коду, описану вище, інколи також називають **«рівночасністю»**. Вона відрізняється від **«паралелізму»**.
І рівночасність, і паралелізм стосуються «різних речей, що відбуваються більш-менш одночасно».
**Рівночасність** і **паралелізм** стосуються «різних речей, що відбуваються більш-менш одночасно».
Але деталі між рівночасністю і паралелізмом досить різні.
Але деталі між *рівночасністю* і *паралелізмом* досить різні.
Щоб побачити різницю, уявімо таку історію про бургери:
@ -257,7 +257,7 @@ def results():
Ні! Це не мораль історії.
Рівночасність відрізняється від паралелізму. І вона краща у конкретних сценаріях, що містять багато очікування. Через це зазвичай вона значно краща за паралелізм для розробки вебзастосунків. Але не для всього.
Рівночасність відрізняється від паралелізму. І вона краща у **конкретних** сценаріях, що містять багато очікування. Через це зазвичай вона значно краща за паралелізм для розробки вебзастосунків. Але не для всього.
Щоб урівноважити це, уявімо коротку історію:
@ -273,15 +273,15 @@ def results():
Завершення займе той самий час із «чергами» чи без (рівночасність), і ви виконаєте той самий обсяг роботи.
Але в цьому випадку, якби ви могли привести 8 колишніх касирів/кухарів/тепер прибиральників, і кожен з них (разом із вами) взяв би свою зону будинку для прибирання, ви могли б виконати всю роботу паралельно — з додатковою допомогою — і завершити значно швидше.
Але в цьому випадку, якби ви могли привести 8 колишніх касирів/кухарів/тепер прибиральників, і кожен з них (разом із вами) взяв би свою зону будинку для прибирання, ви могли б виконати всю роботу **паралельно** - з додатковою допомогою - і завершити значно швидше.
У цьому сценарії кожен з прибиральників (включно з вами) був би процесором, що виконує свою частину роботи.
І оскільки більшість часу виконання займає реальна робота (а не очікування), а роботу на комп’ютері виконує <abbrtitle="Central Processing Unit - Центральний процесор">CPU</abbr>, ці проблеми називають «CPU bound».
І оскільки більшість часу виконання займає реальна робота (а не очікування), а роботу на комп’ютері виконує <abbrtitle="Central Processing Unit - Центральний процесор">CPU</abbr>, ці проблеми називають **«CPU bound»**.
---
Поширені приклади «CPU bound» операцій - це речі, що потребують складної математичної обробки.
Поширені приклади **CPU bound** операцій - це речі, що потребують складної математичної обробки.
Наприклад:
@ -294,7 +294,7 @@ def results():
З **FastAPI** ви можете скористатися рівночасністю, що дуже поширена у веброзробці (та ж головна принада NodeJS).
Але ви також можете використати переваги паралелізму і багатопроцесорності (наявність кількох процесів, що працюють паралельно) для навантажень «CPU bound», як у системах машинного навчання.
Але ви також можете використати переваги паралелізму і багатопроцесорності (наявність кількох процесів, що працюють паралельно) для навантажень **«CPU bound»**, як у системах машинного навчання.
Це, плюс простий факт, що Python є основною мовою для **Data Science**, машинного навчання і особливо глибокого навчання, робить FastAPI дуже вдалим вибором для веб API та застосунків Data Science / машинного навчання (серед багатьох інших).
@ -340,7 +340,7 @@ burgers = get_burgers(2)
---
Отже, якщо ви використовуєте бібліотеку, яку можна викликати з `await`, вам потрібно створити функцію операції шляху, що її використовує, з `async def`, як тут:
Отже, якщо ви використовуєте бібліотеку, яку можна викликати з `await`, вам потрібно створити *функцію операції шляху*, що її використовує, з `async def`, як тут:
```Python hl_lines="2-3"
@app.get('/burgers')
@ -357,7 +357,7 @@ async def read_burgers():
Тож як же викликати першу `async`-функцію - курка чи яйце?
Якщо ви працюєте з **FastAPI**, вам не потрібно про це турбуватися, адже цією «першою» функцією буде ваша функція операції шляху, і FastAPI знатиме, як учинити правильно.
Якщо ви працюєте з **FastAPI**, вам не потрібно про це турбуватися, адже цією «першою» функцією буде ваша *функція операції шляху*, і FastAPI знатиме, як учинити правильно.
Але якщо ви хочете використовувати `async` / `await` без FastAPI, ви також можете це зробити.
@ -395,7 +395,7 @@ Starlette (і **FastAPI**) базуються на [AnyIO](https://anyio.readthe
Погляньмо на ту саму фразу ще раз:
> Сучасні версії Python мають підтримку «асинхронного коду» за допомогою так званих «співпрограм», з синтаксисом **`async` і `await`**.
> Сучасні версії Python мають підтримку **«асинхронного коду»** за допомогою так званих **«співпрограм»**, з синтаксисом **`async` і `await`**.
Тепер це має більше сенсу. ✨
@ -415,11 +415,11 @@ Starlette (і **FastAPI**) базуються на [AnyIO](https://anyio.readthe
### Функції операції шляху { #path-operation-functions }
Коли ви оголошуєте функцію операції шляху зі звичайним `def` замість `async def`, вона виконується у зовнішньому пулі потоків (threadpool), який потім «очікується», замість прямого виклику (оскільки прямий виклик блокував би сервер).
Коли ви оголошуєте *функцію операції шляху* зі звичайним `def` замість `async def`, вона виконується у зовнішньому пулі потоків (threadpool), який потім «очікується», замість прямого виклику (оскільки прямий виклик блокував би сервер).
Якщо ви прийшли з іншого async-фреймворку, який не працює так, як описано вище, і звикли визначати тривіальні, лише обчислювальні функції операції шляху зі звичайним `def` заради крихітного виграшу у продуктивності (близько 100 наносекунд), зверніть увагу, що у **FastAPI** ефект буде протилежним. У таких випадках краще використовувати `async def`, якщо тільки ваші функції операції шляху не використовують код, що виконує блокуюче <abbrtitle="Input/Output - Ввід/Вивід: читання або запис на диск, мережеві комунікації.">I/O</abbr>.
Якщо ви прийшли з іншого async-фреймворку, який не працює так, як описано вище, і звикли визначати тривіальні, лише обчислювальні *функції операції шляху* зі звичайним `def` заради крихітного виграшу у продуктивності (близько 100 наносекунд), зверніть увагу, що у **FastAPI** ефект буде протилежним. У таких випадках краще використовувати `async def`, якщо тільки ваші *функції операції шляху* не використовують код, що виконує блокуюче <abbrtitle="Input/Output - Ввід/Вивід: читання або запис на диск, мережеві комунікації.">I/O</abbr>.
Втім, у будь-якій ситуації є велика ймовірність, що **FastAPI** [все одно буде швидшим](index.md#performance) (або принаймні порівнянним) за ваш попередній фреймворк.
Втім, в обох ситуаціях є велика ймовірність, що **FastAPI** [все одно буде швидшим](index.md#performance) (або принаймні порівнянним) за ваш попередній фреймворк.
### Залежності { #dependencies }
@ -433,7 +433,7 @@ Starlette (і **FastAPI**) базуються на [AnyIO](https://anyio.readthe
Будь-яка інша допоміжна функція, яку ви викликаєте безпосередньо, може бути створена зі звичайним `def` або `async def`, і FastAPI не впливатиме на спосіб її виклику.
Це відрізняється від функцій, які FastAPI викликає за вас: функції операції шляху і залежності.
Це відрізняється від функцій, які FastAPI викликає за вас: *функції операції шляху* і залежності.
Якщо ваша допоміжна функція є звичайною функцією з `def`, її буде викликано безпосередньо (як ви написали у своєму коді), не в пулі потоків; якщо функція створена з `async def`, тоді вам слід використовувати `await` при її виклику у вашому коді.
Тепер, коли ми знаємо різницю між термінами **процес** і **програма**, продовжимо говорити про розгортання.
## Запуск під час старту { #running-on-startup }
## Запуск під час запуску { #running-on-startup }
У більшості випадків, коли ви створюєте веб-API, ви хочете, щоб він **працював постійно**, без перерв, щоб клієнти завжди мали до нього доступ. Звісно, якщо немає особливих причин запускати його лише в певних ситуаціях. Але зазвичай ви хочете, щоб він постійно працював і був **доступний**.
@ -102,15 +102,15 @@
І якщо сервер буде перезавантажено (наприклад, після оновлень або міграцій у хмарного провайдера), ви, ймовірно, **не помітите цього**. І через це ви навіть не знатимете, що треба вручну перезапустити процес. У результаті ваш API просто залишиться «мертвим». 😱
### Автоматичний запуск під час старту { #run-automatically-on-startup }
### Автоматичний запуск під час запуску { #run-automatically-on-startup }
Загалом ви, напевно, захочете, щоб серверна програма (наприклад, Uvicorn) запускалася автоматично під час старту сервера і без будь-якого **людського втручання**, щоб завжди був запущений процес із вашим API (наприклад, Uvicorn із вашим FastAPI-застосунком).
Загалом ви, напевно, захочете, щоб серверна програма (наприклад, Uvicorn) запускалася автоматично під час запуску сервера і без будь-якого **людського втручання**, щоб завжди був запущений процес із вашим API (наприклад, Uvicorn із вашим FastAPI-застосунком).
### Окрема програма { #separate-program }
Щоб цього досягти, зазвичай використовують **окрему програму**, яка гарантує запуск вашого застосунку під час старту. І в багатьох випадках вона також забезпечує запуск інших компонентів або застосунків, наприклад бази даних.
Щоб цього досягти, зазвичай використовують **окрему програму**, яка гарантує запуск вашого застосунку під час запуску. І в багатьох випадках вона також забезпечує запуск інших компонентів або застосунків, наприклад бази даних.
### Приклади інструментів для запуску під час старту { #example-tools-to-run-at-startup }
### Приклади інструментів для запуску під час запуску { #example-tools-to-run-at-startup }
Приклади інструментів, які можуть це робити:
@ -127,7 +127,7 @@
## Перезапуски { #restarts }
Подібно до забезпечення запуску застосунку під час старту системи, ви, ймовірно, також захочете гарантувати його **перезапуск** після збоїв.
Подібно до забезпечення запуску застосунку під час запуску системи, ви, ймовірно, також захочете гарантувати його **перезапуск** після збоїв.
### Ми помиляємося { #we-make-mistakes }
@ -163,7 +163,7 @@
### Приклади інструментів для автоматичного перезапуску { #example-tools-to-restart-automatically }
У більшості випадків той самий інструмент, який використовується для **запуску програми під час старту**, також використовується для автоматичних **перезапусків**.
У більшості випадків той самий інструмент, який використовується для **запуску програми під час запуску**, також використовується для автоматичних **перезапусків**.
Наприклад, це можуть забезпечувати:
@ -192,7 +192,7 @@
Пам'ятаєте з документації [Про HTTPS](https.md), що на сервері лише один процес може слухати певну комбінацію порту та IP-адреси?
Это досі так.
Це досі так.
Отже, щоб мати **кілька процесів** одночасно, має бути **єдиний процес, який слухає порт**, і який далі якимось чином передає комунікацію кожному процесу-працівнику.
@ -247,9 +247,9 @@
///
## Попередні кроки перед стартом { #previous-steps-before-starting }
## Попередні кроки перед запуском { #previous-steps-before-starting }
Є багато випадків, коли потрібно виконати деякі кроки **перед стартом** вашого застосунку.
Є багато випадків, коли потрібно виконати деякі кроки **перед запуском** вашого застосунку.
Наприклад, ви можете захотіти запустити **міграції бази даних**.
@ -310,11 +310,11 @@
Тут ви прочитали про основні концепції, які, ймовірно, потрібно тримати в голові, вирішуючи, як розгортати ваш застосунок:
- Безпека - HTTPS
- Запуск під час старту
- Запуск під час запуску
- Перезапуски
- Реплікація (кількість запущених процесів)
- Пам'ять
- Попередні кроки перед стартом
- Попередні кроки перед запуском
Розуміння цих ідей і того, як їх застосовувати, має дати вам інтуїцію, необхідну для прийняття рішень під час конфігурування і тонкого налаштування ваших розгортань. 🤓
# FastAPI у контейнерах - Docker { #fastapi-in-containers-docker }
Під час розгортання застосунків FastAPI поширений підхід - збирати образи контейнерів Linux. Зазвичай це робиться за допомогою [Docker](https://www.docker.com/). Потім ви можете розгорнути цей образ контейнера кількома різними способами.
Під час розгортання застосунків FastAPI поширений підхід - збирати **образи контейнерів Linux**. Зазвичай це робиться за допомогою [**Docker**](https://www.docker.com/). Потім ви можете розгорнути цей образ контейнера кількома різними способами.
Використання контейнерів Linux має кілька переваг, зокрема безпека, відтворюваність, простота та інші.
Використання контейнерів Linux має кілька переваг, зокрема **безпека**, **відтворюваність**, **простота** та інші.
Контейнери (переважно контейнери Linux) - це дуже легкий спосіб упакувати застосунки з усіма їхніми залежностями та потрібними файлами, ізолювавши їх від інших контейнерів (інших застосунків або компонентів) у тій самій системі.
Контейнери (переважно контейнери Linux) - це дуже **легкий** спосіб упакувати застосунки з усіма їхніми залежностями та потрібними файлами, ізолювавши їх від інших контейнерів (інших застосунків або компонентів) у тій самій системі.
Контейнери Linux працюють, використовуючи той самий ядро Linux, що й хост (машина, віртуальна машина, хмарний сервер тощо). Це означає, що вони дуже легкі (у порівнянні з повними віртуальними машинами, які емулюють цілу операційну систему).
Контейнери Linux працюють, використовуючи те саме ядро Linux, що й хост (машина, віртуальна машина, хмарний сервер тощо). Це означає, що вони дуже легкі (у порівнянні з повними віртуальними машинами, які емулюють цілу операційну систему).
Таким чином контейнери споживають мало ресурсів, приблизно як безпосередньо запущені процеси (віртуальна машина споживала б значно більше).
Таким чином контейнери споживають **мало ресурсів**, приблизно як безпосередньо запущені процеси (віртуальна машина споживала б значно більше).
У контейнерів також є власні ізольовані процеси виконання (зазвичай лише один процес), файлові системи та мережі, що спрощує розгортання, безпеку, розробку тощо.
У контейнерів також є власні **ізольовані** процеси виконання (зазвичай лише один процес), файлові системи та мережі, що спрощує розгортання, безпеку, розробку тощо.
## Що таке образ контейнера { #what-is-a-container-image }
Контейнер запускається з образу контейнера.
**Контейнер** запускається з **образу контейнера**.
Образ контейнера - це статична версія всіх файлів, змінних оточення та типова команда/програма, яка має бути присутня в контейнері. Тут «статична» означає, що образ контейнера не запущений, він не виконується, це лише упаковані файли та метадані.
Образ контейнера - це **статична** версія всіх файлів, змінних оточення та типова команда/програма, яка має бути присутня в контейнері. Тут **«статична»** означає, що **образ** контейнера не запущений, він не виконується, це лише упаковані файли та метадані.
На противагу «образу контейнера», що є збереженим статичним вмістом, «контейнер» зазвичай означає запущений екземпляр, те, що виконується.
На противагу «**образу контейнера**», що є збереженим статичним вмістом, «**контейнер**» зазвичай означає запущений екземпляр, те, що **виконується**.
Коли контейнер запущено (запущений з образу контейнера), він може створювати або змінювати файли, змінні оточення тощо. Ці зміни існуватимуть лише в цьому контейнері, але не збережуться в базовому образі контейнера (не будуть записані на диск).
Коли **контейнер** запущено (запущений з **образу контейнера**), він може створювати або змінювати файли, змінні оточення тощо. Ці зміни існуватимуть лише в цьому контейнері, але не збережуться в базовому образі контейнера (не будуть записані на диск).
Образ контейнера можна порівняти з файлом і вмістом програми, наприклад `python` і файлом `main.py`.
Образ контейнера можна порівняти з файлом і вмістом **програми**, наприклад `python` і файлом `main.py`.
А сам контейнер (на відміну від образу) - це фактично запущений екземпляр образу, порівнянний із процесом. Насправді контейнер працює лише тоді, коли в ньому працює процес (і зазвичай це один процес). Контейнер зупиняється, коли в ньому не працює жоден процес.
А сам **контейнер** (на відміну від **образу контейнера**) - це фактично запущений екземпляр образу, порівнянний із **процесом**. Насправді контейнер працює лише тоді, коли в ньому **працює процес** (і зазвичай це один процес). Контейнер зупиняється, коли в ньому не працює жоден процес.
## Образи контейнерів { #container-images }
Docker був одним з основних інструментів для створення та керування образами контейнерів і контейнерами.
Docker був одним з основних інструментів для створення та керування **образами контейнерів** і **контейнерами**.
Існує публічний [Docker Hub](https://hub.docker.com/) з готовими офіційними образами для багатьох інструментів, середовищ, баз даних і застосунків.
Існує публічний [Docker Hub](https://hub.docker.com/) з готовими **офіційними образами контейнерів** для багатьох інструментів, середовищ, баз даних і застосунків.
Наприклад, є офіційний [образ Python](https://hub.docker.com/_/python).
@ -71,43 +71,43 @@ Docker був одним з основних інструментів для с
* [MongoDB](https://hub.docker.com/_/mongo)
* [Redis](https://hub.docker.com/_/redis) тощо.
Використовуючи готовий образ контейнера, дуже легко поєднувати та використовувати різні інструменти. Наприклад, щоб випробувати нову базу даних. У більшості випадків ви можете використати офіційні образи та просто налаштувати їх змінними оточення.
Використовуючи готовий образ контейнера, дуже легко **поєднувати** та використовувати різні інструменти. Наприклад, щоб випробувати нову базу даних. У більшості випадків ви можете використати **офіційні образи** та просто налаштувати їх змінними оточення.
Таким чином, у багатьох випадках ви зможете навчитися працювати з контейнерами і Docker та повторно використати ці знання з багатьма різними інструментами і компонентами.
Тобто ви запускатимете кілька контейнерів з різними речами, як-от базу даних, застосунок на Python, вебсервер із фронтендом на React, і з’єднаєте їх через внутрішню мережу.
Тобто ви запускатимете **кілька контейнерів** з різними речами, як-от базу даних, застосунок на Python, вебсервер із фронтендом на React, і з’єднаєте їх через внутрішню мережу.
Усі системи керування контейнерами (як Docker чи Kubernetes) мають ці мережеві можливості вбудовано.
## Контейнери і процеси { #containers-and-processes }
Образ контейнера зазвичай містить у своїх метаданих типову програму або команду, яку слід виконати під час запуску контейнера, і параметри для цієї програми. Дуже схоже на те, що ви б виконали в командному рядку.
**Образ контейнера** зазвичай містить у своїх метаданих типову програму або команду, яку слід виконати під час запуску **контейнера**, і параметри для цієї програми. Дуже схоже на те, що ви б виконали в командному рядку.
Коли контейнер запускається, він виконає цю команду/програму (хоча ви можете перевизначити її і запустити іншу команду/програму).
Коли **контейнер** запускається, він виконає цю команду/програму (хоча ви можете перевизначити її і запустити іншу команду/програму).
Контейнер працює доти, доки працює головний процес (команда або програма).
Контейнер працює доти, доки працює **головний процес** (команда або програма).
Зазвичай контейнер має один процес, але також можливо запускати підпроцеси з головного процесу, і таким чином у вас може бути кілька процесів у тому самому контейнері.
Зазвичай контейнер має **один процес**, але також можливо запускати підпроцеси з головного процесу, і таким чином у вас може бути **кілька процесів** у тому самому контейнері.
Але неможливо мати запущений контейнер без принаймні одного запущеного процесу. Якщо головний процес зупиняється, контейнер зупиняється.
Але неможливо мати запущений контейнер без **принаймні одного запущеного процесу**. Якщо головний процес зупиняється, контейнер зупиняється.
## Зібрати Docker-образ для FastAPI { #build-a-docker-image-for-fastapi }
Гаразд, зберімо щось зараз! 🚀
Я покажу вам, як зібрати образ Docker для FastAPI з нуля на основі офіційного образу Python.
Я покажу вам, як зібрати **образ Docker** для FastAPI **з нуля** на основі **офіційного образу Python**.
Це те, що ви захочете робити у більшості випадків, наприклад:
Це те, що ви захочете робити у **більшості випадків**, наприклад:
* Використання Kubernetes або подібних інструментів
* Під час запуску на Raspberry Pi
* Використання **Kubernetes** або подібних інструментів
* Під час запуску на **Raspberry Pi**
* Використання хмарного сервісу, який запустить для вас образ контейнера тощо
### Вимоги до пакетів { #package-requirements }
Зазвичай ви маєте вимоги до пакетів для вашого застосунку в окремому файлі.
Зазвичай ви маєте **вимоги до пакетів** для вашого застосунку в окремому файлі.
Це залежить переважно від інструменту, який ви використовуєте для встановлення цих вимог.
Це залежить переважно від інструменту, який ви використовуєте для **встановлення** цих вимог.
Найпоширеніший спосіб - мати файл `requirements.txt` з назвами пакетів і їхніми версіями, по одному на рядок.
Опція `--upgrade` каже `pip` оновити пакети, якщо вони вже встановлені.
Оскільки попередній крок копіювання файлу може бути виявлений кешем Docker, цей крок також використовуватиме кеш Docker, коли це можливо.
Оскільки попередній крок копіювання файлу може бути виявлений **кешем Docker**, цей крок також **використовуватиме кеш Docker**, коли це можливо.
Використання кешу на цьому кроці збереже вам багато часу під час повторних збірок образу в розробці, замість того щоб завжди завантажувати і встановлювати всі залежності.
Використання кешу на цьому кроці **збереже** вам багато **часу** під час повторних збірок образу в розробці, замість того щоб **завантажувати і встановлювати** всі залежності**щоразу**.
5. Скопіюйте директорію `./app` у директорію `/code`.
Оскільки тут увесь код, який змінюється найчастіше, кеш Docker не буде легко використаний для цього або будь-яких наступних кроків.
Оскільки тут увесь код, який **змінюється найчастіше**, **кеш** Docker не буде легко використаний для цього або будь-яких **наступних кроків**.
Тому важливо розмістити це ближче до кінця `Dockerfile`, щоб оптимізувати час збірки образу контейнера.
Тому важливо розмістити це **ближче до кінця**`Dockerfile`, щоб оптимізувати час збірки образу контейнера.
6. Встановіть команду для використання `fastapi run`, яка всередині використовує Uvicorn.
6. Встановіть **команду** для використання `fastapi run`, яка всередині використовує Uvicorn.
`CMD` приймає список строк, кожна з яких - це те, що ви б набирали в командному рядку, розділене пробілами.
Ця команда буде виконана з поточної робочої директорії, тієї самої `/code`, яку ви вказали вище через `WORKDIR /code`.
Ця команда буде виконана з **поточної робочої директорії**, тієї самої `/code`, яку ви вказали вище через `WORKDIR /code`.
Обов’язково завжди використовуйте exec form, щоб FastAPI міг коректно завершувати роботу та щоб були викликані [події тривалості життя](../advanced/events.md).
Обов’язково завжди використовуйте **exec** form, щоб FastAPI міг коректно завершувати роботу та щоб були викликані [події тривалості життя](../advanced/events.md).
Докладніше про це можна прочитати в [документації Docker про shell та exec form](https://docs.docker.com/reference/dockerfile/#shell-and-exec-form).
У цьому `Dockerfile` є важливий трюк: спочатку ми копіюємо лише файл із залежностями, а не решту коду. Ось чому.
У цьому `Dockerfile` є важливий трюк: спочатку ми копіюємо лише **файл із залежностями**, а не решту коду. Ось чому.
```Dockerfile
COPY ./requirements.txt /code/requirements.txt
```
Docker та інші інструменти збирають ці образи контейнерів інкрементально, додаючи один шар поверх іншого, починаючи з верхньої частини `Dockerfile` і додаючи будь-які файли, створені кожною інструкцією в `Dockerfile`.
Docker та інші інструменти **збирають** ці образи контейнерів **інкрементально**, додаючи **один шар поверх іншого**, починаючи з верхньої частини `Dockerfile` і додаючи будь-які файли, створені кожною інструкцією в `Dockerfile`.
Docker та подібні інструменти також використовують внутрішній кеш під час збірки образу. Якщо файл не змінювався з моменту останньої збірки, тоді він повторно використає той самий шар, створений востанє, замість копіювання файлу знову та створення нового шару з нуля.
Docker та подібні інструменти також використовують **внутрішній кеш** під час збірки образу. Якщо файл не змінювався з моменту останньої збірки, тоді він **повторно використає той самий шар**, створений востаннє, замість копіювання файлу знову та створення нового шару з нуля.
Просте уникнення копіювання файлів не обов’язково суттєво покращує ситуацію, але оскільки для цього кроку використано кеш, він може використати кеш і для наступного кроку. Наприклад, він може використати кеш для інструкції, яка встановлює залежності:
Просте уникнення копіювання файлів не обов’язково суттєво покращує ситуацію, але оскільки для цього кроку використано кеш, він може **використати кеш і для наступного кроку**. Наприклад, він може використати кеш для інструкції, яка встановлює залежності:
```Dockerfile
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
```
Файл із вимогами до пакетів змінюватиметься нечасто. Отже, копіюючи лише цей файл, Docker зможе використати кеш для цього кроку.
Файл із вимогами до пакетів **змінюватиметься нечасто**. Отже, копіюючи лише цей файл, Docker зможе **використати кеш** для цього кроку.
А потім Docker зможе використати кеш і для наступного кроку, який завантажує та встановлює ці залежності. І саме тут ми заощаджуємо багато часу. ✨ ...і уникаємо нудного очікування. 😪😆
А потім Docker зможе **використати кеш і для наступного кроку**, який завантажує та встановлює ці залежності. І саме тут ми **заощаджуємо багато часу**. ✨ ...і уникаємо нудного очікування. 😪😆
Завантаження і встановлення залежностей пакетів може займати хвилини, але використання кешу займе максимум секунди.
Завантаження і встановлення залежностей пакетів **може займати хвилини**, але використання **кешу** займе **максимум секунди**.
І оскільки ви збиратимете образ контейнера знову і знову під час розробки, щоб перевіряти, що зміни у вашому коді працюють, це заощадить багато накопиченого часу.
Потім, ближче до кінця `Dockerfile`, ми копіюємо весь код. Оскільки це те, що змінюється найчастіше, ми розміщуємо це ближче до кінця, адже майже завжди все після цього кроку не зможе використати кеш.
Потім, ближче до кінця `Dockerfile`, ми копіюємо весь код. Оскільки це те, що **змінюється найчастіше**, ми розміщуємо це ближче до кінця, адже майже завжди все після цього кроку не зможе використати кеш.
Поговорімо знову про деякі з тих самих [Концепцій розгортання](concepts.md) у термінах контейнерів.
Контейнери - це переважно інструмент для спрощення процесу збирання та розгортання застосунку, але вони не нав’язують конкретний підхід до обробки цих концепцій розгортання, і існує кілька можливих стратегій.
Контейнери - це переважно інструмент для спрощення процесу **збирання та розгортання** застосунку, але вони не нав’язують конкретний підхід до обробки цих **концепцій розгортання**, і існує кілька можливих стратегій.
Гарна новина полягає в тому, що для кожної стратегії є спосіб покрити всі концепції розгортання. 🎉
**Гарна новина** полягає в тому, що для кожної стратегії є спосіб покрити всі концепції розгортання. 🎉
Розгляньмо ці концепції розгортання в контексті контейнерів:
Розгляньмо ці **концепції розгортання** в контексті контейнерів:
Якщо зосередитись лише на образі контейнера для застосунку FastAPI (а згодом на запущеному контейнері), HTTPS зазвичай обробляється зовнішнім іншим інструментом.
Якщо зосередитись лише на **образі контейнера** для застосунку FastAPI (а згодом на запущеному **контейнері**), HTTPS зазвичай обробляється **зовнішнім** іншим інструментом.
Це може бути інший контейнер, наприклад з [Traefik](https://traefik.io/), що обробляє HTTPS і автоматичне отримання сертифікатів.
Це може бути інший контейнер, наприклад з [Traefik](https://traefik.io/), що обробляє **HTTPS** і **автоматичне** отримання **сертифікатів**.
/// tip | Порада
@ -444,57 +444,57 @@ Traefik має інтеграції з Docker, Kubernetes та іншими, т
## Автозапуск і перезапуски { #running-on-startup-and-restarts }
Зазвичай інший інструмент відповідає за запуск і виконання вашого контейнера.
Зазвичай інший інструмент відповідає за **запуск і виконання** вашого контейнера.
Це може бути безпосередньо Docker, Docker Compose, Kubernetes, хмарний сервіс тощо.
Це може бути безпосередньо **Docker**, **Docker Compose**, **Kubernetes**, **хмарний сервіс** тощо.
У більшості (або всіх) випадків є проста опція, щоб увімкнути запуск контейнера при старті системи та перезапуски у разі збоїв. Наприклад, у Docker це опція командного рядка `--restart`.
Без використання контейнерів змусити застосунки запускатися при старті системи та з перезапусками може бути клопітно і складно. Але під час роботи з контейнерами у більшості випадків ця функціональність вбудована за замовчуванням. ✨
Без використання контейнерів змусити застосунки запускатися при старті системи та з перезапусками може бути клопітно і складно. Але під час **роботи з контейнерами** у більшості випадків ця функціональність вбудована за замовчуванням. ✨
## Реплікація - кількість процесів { #replication-number-of-processes }
Якщо у вас є <dfntitle="Група машин, налаштованих бути з'єднаними та працювати разом певним чином.">кластер</dfn> машин із Kubernetes, Docker Swarm Mode, Nomad або іншою подібною складною системою для керування розподіленими контейнерами на кількох машинах, тоді ви, ймовірно, захочете обробляти реплікацію на рівні кластера замість використання менеджера процесів (як-от Uvicorn з працівниками) у кожному контейнері.
Якщо у вас є <dfntitle="Група машин, налаштованих бути з’єднаними та працювати разом певним чином.">кластер</dfn> машин із **Kubernetes**, Docker Swarm Mode, Nomad або іншою подібною складною системою для керування розподіленими контейнерами на кількох машинах, тоді ви, ймовірно, захочете **обробляти реплікацію** на **рівні кластера** замість використання **менеджера процесів** (як-от Uvicorn з працівниками) у кожному контейнері.
Одна з таких розподілених систем керування контейнерами, як-от Kubernetes, зазвичай має інтегровані способи обробляти реплікацію контейнерів, підтримуючи водночас балансування навантаження для вхідних запитів. Усе це - на рівні кластера.
Одна з таких розподілених систем керування контейнерами, як-от Kubernetes, зазвичай має інтегровані способи обробляти **реплікацію контейнерів**, підтримуючи водночас **балансування навантаження** для вхідних запитів. Усе це - на **рівні кластера**.
У таких випадках ви, ймовірно, захочете зібрати Docker-образ з нуля, як [пояснено вище](#dockerfile), встановивши ваші залежності і запустивши один процес Uvicorn замість використання кількох працівників Uvicorn.
У таких випадках ви, ймовірно, захочете зібрати **Docker-образ з нуля**, як [пояснено вище](#dockerfile), встановивши ваші залежності і запустивши **один процес Uvicorn** замість використання кількох працівників Uvicorn.
При використанні контейнерів зазвичай є якийсь компонент, що слухає на головному порту. Це може бути інший контейнер, який також є представником з термінацією TLS для обробки HTTPS, або подібний інструмент.
При використанні контейнерів зазвичай є якийсь компонент, що **слухає на головному порту**. Це може бути інший контейнер, який також є **представником з термінацією TLS** для обробки **HTTPS**, або подібний інструмент.
Оскільки цей компонент приймає навантаження запитів і розподіляє його між працівниками (сподіваємось) збалансовано, його також часто називають балансувальником навантаження.
Оскільки цей компонент приймає **навантаження** запитів і розподіляє його між працівниками (сподіваємось) **збалансовано**, його також часто називають **балансувальником навантаження**.
/// tip | Порада
Той самий компонент представника з термінацією TLS, що використовується для HTTPS, швидше за все, також буде балансувальником навантаження.
Той самий компонент **представника з термінацією TLS**, що використовується для HTTPS, швидше за все, також буде **балансувальником навантаження**.
///
І під час роботи з контейнерами та сама система, яку ви використовуєте для їх запуску і керування ними, вже матиме внутрішні інструменти для передавання мережевої комунікації (наприклад, HTTP-запитів) від цього балансувальника навантаження (який також може бути представником з термінацією TLS) до контейнерів із вашим застосунком.
І під час роботи з контейнерами та сама система, яку ви використовуєте для їх запуску і керування ними, вже матиме внутрішні інструменти для передавання **мережевої комунікації** (наприклад, HTTP-запитів) від цього **балансувальника навантаження** (який також може бути **представником з термінацією TLS**) до контейнерів із вашим застосунком.
### Один балансувальник навантаження - кілька контейнерів-працівників { #one-load-balancer-multiple-worker-containers }
Під час роботи з Kubernetes або подібними розподіленими системами керування контейнерами використання їхніх внутрішніх мережевих механізмів дозволяє єдиному балансувальнику навантаження, що слухає на головному порту, передавати комунікацію (запити) до кількох контейнерів, у яких запущено ваш застосунок.
Під час роботи з **Kubernetes** або подібними розподіленими системами керування контейнерами використання їхніх внутрішніх мережевих механізмів дозволяє єдиному **балансувальнику навантаження**, що слухає на головному **порту**, передавати комунікацію (запити) до кількох **контейнерів**, у яких запущено ваш застосунок.
Кожен з цих контейнерів із вашим застосунком зазвичай має лише один процес (наприклад, процес Uvicorn, що запускає ваш застосунок FastAPI). Усі вони будуть ідентичними контейнерами, які запускають те саме, але кожен зі своїм процесом, пам’яттю тощо. Таким чином ви використаєте переваги паралелізму на різних ядрах процесора або навіть на різних машинах.
Кожен з цих контейнерів із вашим застосунком зазвичай має **лише один процес** (наприклад, процес Uvicorn, що запускає ваш застосунок FastAPI). Усі вони будуть **ідентичними контейнерами**, які запускають те саме, але кожен зі своїм процесом, пам’яттю тощо. Таким чином ви використаєте переваги **паралелізації** на **різних ядрах** процесора або навіть на **різних машинах**.
А розподілена система контейнерів із балансувальником навантаження розподілятиме запити між кожним із контейнерів із вашим застосунком по черзі. Тож кожен запит може оброблятися одним із кількох реплікованих контейнерів, що запускають ваш застосунок.
А розподілена система контейнерів із **балансувальником навантаження****розподілятиме запити** між кожним із контейнерів із вашим застосунком **по черзі**. Тож кожен запит може оброблятися одним із кількох **реплікованих контейнерів**, що запускають ваш застосунок.
І зазвичай цей балансувальник навантаження зможе обробляти запити, які йдуть до інших застосунків у вашому кластері (наприклад, до іншого домену або під іншим префіксом шляху URL), і передаватиме комунікацію до відповідних контейнерів для того іншого застосунку, що працює у вашому кластері.
І зазвичай цей **балансувальник навантаження** зможе обробляти запити, які йдуть до *інших* застосунків у вашому кластері (наприклад, до іншого домену або під іншим префіксом шляху URL), і передаватиме комунікацію до відповідних контейнерів для *того іншого* застосунку, що працює у вашому кластері.
### Один процес на контейнер { #one-process-per-container }
У такому сценарії ви, ймовірно, захочете мати один (Uvicorn) процес на контейнер, адже ви вже обробляєте реплікацію на рівні кластера.
У такому сценарії ви, ймовірно, захочете мати **один (Uvicorn) процес на контейнер**, адже ви вже обробляєте реплікацію на рівні кластера.
Тобто в цьому випадку ви не захочете мати кількох працівників у контейнері, наприклад через опцію командного рядка `--workers`. Ви захочете мати лише один процес Uvicorn на контейнер (але, ймовірно, кілька контейнерів).
Тобто в цьому випадку ви **не захочете** мати кількох працівників у контейнері, наприклад через опцію командного рядка `--workers`. Ви захочете мати лише **один процес Uvicorn** на контейнер (але, ймовірно, кілька контейнерів).
Наявність іншого менеджера процесів всередині контейнера (як це було б із кількома працівниками) лише додасть зайвої складності, яку, найімовірніше, ви вже вирішуєте на рівні кластера.
Наявність іншого менеджера процесів всередині контейнера (як це було б із кількома працівниками) лише додасть **зайвої складності**, яку, найімовірніше, ви вже вирішуєте на рівні кластера.
### Контейнери з кількоми процесами та особливі випадки { #containers-with-multiple-processes-and-special-cases }
### Контейнери з кількома процесами та особливі випадки { #containers-with-multiple-processes-and-special-cases }
Звісно, є особливі випадки, коли ви можете захотіти мати контейнер із кількома процесами-працівниками Uvicorn всередині.
Звісно, є **особливі випадки**, коли ви можете захотіти мати **контейнер** із кількома **процесами-працівниками Uvicorn** всередині.
У таких випадках ви можете використати опцію командного рядка `--workers`, щоб задати кількість працівників, яких потрібно запустити:
Ви можете захотіти менеджер процесів у контейнері, якщо ваш застосунок достатньо простий, щоб запускати його на одному сервері, а не на кластері.
Ви можете захотіти менеджер процесів у контейнері, якщо ваш застосунок **достатньо простий**, щоб запускати його на **одному сервері**, а не на кластері.
#### Docker Compose { #docker-compose }
Ви можете розгортати на одному сервері (не в кластері) за допомогою Docker Compose, тож у вас не буде простого способу керувати реплікацією контейнерів (у Docker Compose), зберігаючи спільну мережу та балансування навантаження.
Ви можете розгортати на **одному сервері** (не в кластері) за допомогою **Docker Compose**, тож у вас не буде простого способу керувати реплікацією контейнерів (у Docker Compose), зберігаючи спільну мережу та **балансування навантаження**.
Тоді ви можете захотіти мати один контейнер із менеджером процесів, що запускає кілька процесів-працівників всередині.
Тоді ви можете захотіти мати **один контейнер** із **менеджером процесів**, що запускає **кілька процесів-працівників** всередині.
---
Головна думка: це не правила, викарбувані в камені, яких потрібно сліпо дотримуватися. Ви можете використати ці ідеї, щоб оцінити власний кейс і вирішити, який підхід найкращий для вашої системи, розглядаючи, як керувати такими концепціями:
Головна думка: **жодне** з цього не є **правилами, викарбуваними в камені**, яких потрібно сліпо дотримуватися. Ви можете використати ці ідеї, щоб **оцінити власний кейс** і вирішити, який підхід найкращий для вашої системи, розглядаючи, як керувати такими концепціями:
Якщо ви запускаєте один процес на контейнер, ви матимете більш-менш чітко визначений, стабільний і обмежений обсяг пам’яті, що споживається кожним із цих контейнерів (їх може бути більше одного, якщо вони репліковані).
Якщо ви запускаєте **один процес на контейнер**, ви матимете більш-менш чітко визначений, стабільний і обмежений обсяг пам’яті, що споживається кожним із цих контейнерів (їх може бути більше одного, якщо вони репліковані).
Потім ви можете встановити ті самі ліміти та вимоги до пам’яті у ваших конфігураціях для системи керування контейнерами (наприклад, у Kubernetes). Таким чином вона зможе реплікувати контейнери на доступних машинах, враховуючи обсяг пам’яті, потрібний їм, і обсяг доступної пам’яті на машинах у кластері.
Потім ви можете встановити ті самі ліміти та вимоги до пам’яті у ваших конфігураціях для системи керування контейнерами (наприклад, у **Kubernetes**). Таким чином вона зможе **реплікувати контейнери** на **доступних машинах**, враховуючи обсяг пам’яті, потрібний їм, і обсяг доступної пам’яті на машинах у кластері.
Якщо ваш застосунок простий, імовірно, це не буде проблемою, і вам може не знадобитися задавати жорсткі ліміти пам’яті. Але якщо ви використовуєте багато пам’яті (наприклад, із моделями машинного навчання), вам слід перевірити, скільки пам’яті ви споживаєте, і відкоригувати кількість контейнерів, що запускаються на кожній машині (і, можливо, додати більше машин у ваш кластер).
Якщо ваш застосунок **простий**, імовірно, це **не буде проблемою**, і вам може не знадобитися задавати жорсткі ліміти пам’яті. Але якщо ви **використовуєте багато пам’яті** (наприклад, із моделями **машинного навчання**), вам слід перевірити, скільки пам’яті ви споживаєте, і відкоригувати **кількість контейнерів**, що запускаються на **кожній машині** (і, можливо, додати більше машин у ваш кластер).
Якщо ви запускаєте кілька процесів на контейнер, вам потрібно переконатися, що кількість запущених процесів не споживає більше пам’яті, ніж доступно.
Якщо ви запускаєте **кілька процесів на контейнер**, вам потрібно переконатися, що кількість запущених процесів не **споживає більше пам’яті**, ніж доступно.
## Попередні кроки перед запуском і контейнери { #previous-steps-before-starting-and-containers }
Якщо у вас кілька контейнерів, імовірно кожен запускає один процес (наприклад, у кластері Kubernetes), тоді ви, ймовірно, захочете мати окремий контейнер, який виконає попередні кроки в одному контейнері, запустивши один процес, перед запуском реплікованих контейнерів-працівників.
Якщо у вас **кілька контейнерів**, імовірно кожен запускає **один процес** (наприклад, у кластері **Kubernetes**), тоді ви, ймовірно, захочете мати **окремий контейнер**, який виконає **попередні кроки** в одному контейнері, запустивши один процес, **перед** запуском реплікованих контейнерів-працівників.
Якщо у вашому випадку немає проблеми запускати ці попередні кроки кілька разів паралельно (наприклад, якщо ви не виконуєте міграції бази даних, а лише перевіряєте, чи база вже готова), тоді ви також можете просто помістити їх у кожен контейнер безпосередньо перед запуском головного процесу.
Якщо у вашому випадку немає проблеми запускати ці попередні кроки **кілька разів паралельно** (наприклад, якщо ви не виконуєте міграції бази даних, а лише перевіряєте, чи база вже готова), тоді ви також можете просто помістити їх у кожен контейнер безпосередньо перед запуском головного процесу.
### Один контейнер { #single-container }
Якщо у вас просте налаштування з одним контейнером, який потім запускає кілька процесів-працівників (або теж лише один процес), тоді ви можете виконати ці попередні кроки в тому ж контейнері безпосередньо перед запуском процесу із застосунком.
Якщо у вас просте налаштування з **одним контейнером**, який потім запускає кілька **процесів-працівників** (або теж лише один процес), тоді ви можете виконати ці попередні кроки в тому ж контейнері безпосередньо перед запуском процесу із застосунком.
### Базовий образ Docker { #base-docker-image }
Колись існував офіційний образ Docker для FastAPI: [tiangolo/uvicorn-gunicorn-fastapi](https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker). Але зараз він застарілий. ⛔️
Ймовірно, вам не слід використовувати цей базовий образ Docker (або будь-який інший подібний).
Ймовірно, вам **не** слід використовувати цей базовий образ Docker (або будь-який інший подібний).
Якщо ви використовуєте Kubernetes (або інші) і вже налаштовуєте реплікацію на рівні кластера з кількома контейнерами. У таких випадках краще зібрати образ з нуля, як описано вище: [Зібрати Docker-образ для FastAPI](#build-a-docker-image-for-fastapi).
Якщо ви використовуєте **Kubernetes** (або інші) і вже налаштовуєте **реплікацію** на рівні кластера з кількома **контейнерами**. У таких випадках краще **зібрати образ з нуля**, як описано вище: [Зібрати Docker-образ для FastAPI](#build-a-docker-image-for-fastapi).
А якщо вам потрібно мати кілька працівників, ви можете просто використати опцію командного рядка `--workers`.
У більшості випадків ви, ймовірно, не захочете використовувати будь-який базовий образ, а натомість зібрати образ контейнера з нуля на основі офіційного образу Python для Docker.
У більшості випадків ви, ймовірно, не захочете використовувати будь-який базовий образ, а натомість **зібрати образ контейнера з нуля** на основі офіційного образу Python для Docker.
Дотримуючись порядку інструкцій у `Dockerfile` і використовуючи кеш Docker, ви можете мінімізувати час збірки, щоб максимізувати свою продуктивність (і уникнути нудьги). 😎
Дотримуючись **порядку** інструкцій у `Dockerfile` і використовуючи **кеш Docker**, ви можете **мінімізувати час збірки**, щоб максимізувати свою продуктивність (і уникнути нудьги). 😎
Увесь цей процес поновлення, паралельно з обслуговуванням застосунку, - одна з головних причин, чому ви можете захотіти мати **окрему систему для обробки HTTPS** за допомогою TLS Termination Proxy замість того, щоб просто використовувати сертифікати TLS безпосередньо з сервером застосунку (наприклад, Uvicorn).
Коли ви використовуєте проксі для обробки HTTPS, ваш **сервер застосунку** (наприклад, Uvicorn через FastAPI CLI) нічого не знає про процес HTTPS, він спілкується звичайним HTTP із **TLS Termination Proxy**.
Коли ви використовуєте представника для обробки HTTPS, ваш **сервер застосунку** (наприклад, Uvicorn через FastAPI CLI) нічого не знає про процес HTTPS, він спілкується звичайним HTTP із **TLS Termination Proxy**.
Цей **проксі** зазвичай динамічно встановлює деякі HTTP-заголовки перед передачею запиту **серверу застосунку**, щоб дати йому знати, що запит **направляється** проксі.
Цей **представник** зазвичай динамічно встановлює деякі HTTP-заголовки перед передачею запиту **серверу застосунку**, щоб дати йому знати, що запит **направляється** представником.
Втім, оскільки **сервер застосунку** не знає, що він стоїть за довіреним **проксі**, за замовчуванням він не довірятиме цим заголовкам.
Втім, оскільки **сервер застосунку** не знає, що він стоїть за довіреним **представником**, за замовчуванням він не довірятиме цим заголовкам.
Але ви можете налаштувати **сервер застосунку**, щоб довіряти направленим заголовкам, надісланим **проксі**. Якщо ви використовуєте FastAPI CLI, ви можете скористатися курсивною*опцією CLI*`--forwarded-allow-ips`, щоб повідомити, з яких IP-адрес слід довіряти цим направленим заголовкам.
Але ви можете налаштувати **сервер застосунку**, щоб довіряти *направленим* заголовкам, надісланим **представником**. Якщо ви використовуєте FastAPI CLI, ви можете скористатися *опцією CLI*`--forwarded-allow-ips`, щоб повідомити, з яких IP-адрес слід довіряти цим *направленим* заголовкам.
Наприклад, якщо **сервер застосунку** отримує комунікацію лише від довіреного **проксі**, ви можете встановити `--forwarded-allow-ips="*"`, щоб довіряти всім вхідним IP-адресам, оскільки він отримуватиме запити лише з тієї IP-адреси, яку використовує **проксі**.
Наприклад, якщо **сервер застосунку** отримує комунікацію лише від довіреного **представника**, ви можете встановити `--forwarded-allow-ips="*"`, щоб довіряти всім вхідним IP-адресам, оскільки він отримуватиме запити лише з тієї IP-адреси, яку використовує **представник**.
Так застосунок зможе знати свою публічну URL-адресу, чи використовує він HTTPS, домен тощо.
Ви можете дізнатися більше про це в документації [За проксі - Увімкнути направлені заголовки проксі](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers)
Ви можете дізнатися більше про це в документації [За представником - Увімкнути направлені заголовки представника](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers)
@ -40,7 +40,7 @@ $ <font color="#4E9A06">fastapi</font> run <u style="text-decoration-style:solid
Це спрацює в більшості випадків. 😎
Цю команду можна використати, наприклад, щоб запустити ваш застосунок FastAPI у контейнері, на сервері тощо.
Цю команду можна використати, наприклад, щоб запустити ваш застосунок **FastAPI** у контейнері, на сервері тощо.
## Сервери ASGI { #asgi-servers }
@ -61,11 +61,11 @@ FastAPI використовує стандарт для побудови Python
Є невелика деталь щодо назв, яку варто пам'ятати. 💡
Слово «сервер» зазвичай означає і віддалений/хмарний комп'ютер (фізична або віртуальна машина), і програму, що працює на цій машині (наприклад, Uvicorn).
Слово **«сервер»** зазвичай означає і віддалений/хмарний комп'ютер (фізична або віртуальна машина), і програму, що працює на цій машині (наприклад, Uvicorn).
Майте на увазі, що коли ви бачите слово «сервер» загалом, воно може стосуватися будь-якого з цих двох значень.
Коли йдеться про віддалену машину, її часто називають «сервер», а також «машина», «VM» (віртуальна машина), «вузол». Усе це означає різновиди віддаленої машини, зазвичай з Linux, на якій ви запускаєте програми.
Коли йдеться про віддалену машину, її часто називають **«сервер»**, а також **«машина»**, **«VM»** (віртуальна машина), **«вузол»**. Усе це означає різновиди віддаленої машини, зазвичай з Linux, на якій ви запускаєте програми.
## Встановіть серверну програму { #install-the-server-program }
## Запустіть серверну програму { #run-the-server-program }
Якщо ви встановили ASGI-сервер вручну, зазвичай потрібно передати рядок імпорту в спеціальному форматі, щоб він імпортував ваш застосунок FastAPI:
Якщо ви встановили ASGI-сервер вручну, зазвичай потрібно передати строку імпорту в спеціальному форматі, щоб він імпортував ваш застосунок FastAPI:
<divclass="termy">
@ -142,7 +142,7 @@ Uvicorn та інші сервери підтримують опцію `--reload
## Концепції розгортання { #deployment-concepts }
Ці приклади запускають серверну програму (наприклад, Uvicorn), піднімаючи один процес, що слухає всі IP (`0.0.0.0`) на визначеному порту (наприклад, `80`).
Ці приклади запускають серверну програму (наприклад, Uvicorn), піднімаючи **один процес**, що слухає всі IP (`0.0.0.0`) на визначеному порту (наприклад, `80`).
Це базова ідея. Але, ймовірно, вам знадобиться подбати ще про таке:
Офіційне [FastAPI Extension](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) покращує ваш робочий процес розробки FastAPI завдяки виявленню й навігації по *операціях шляху*, а також розгортанню у FastAPI Cloud і потоковому передаванню журналів у реальному часі.
Докладніше про розширення дивіться у README в [репозиторії GitHub](https://github.com/fastapi/fastapi-vscode).
Змінна оточення (також відома як «env var») - це змінна, що існує поза кодом Python, в операційній системі, і може бути прочитана вашим кодом Python (а також іншими програмами).
Змінна оточення (також відома як «**env var**») - це змінна, що існує **поза** кодом Python, в **операційній системі**, і може бути прочитана вашим кодом Python (а також іншими програмами).
Змінні оточення корисні для роботи з налаштуваннями застосунку, як частина встановлення Python тощо.
Змінні оточення корисні для роботи з **налаштуваннями** застосунку, як частина **встановлення** Python тощо.
## Створення і використання змінних оточення { #create-and-use-env-vars }
Ви можете створювати і використовувати змінні оточення в оболонці (терміналі) без участі Python:
Ви можете **створювати** і використовувати змінні оточення в **оболонці (терміналі)** без участі Python:
//// tab | Linux, macOS, Windows Bash
@ -52,7 +52,7 @@ Hello Wade Wilson
## Читання змінних оточення в Python { #read-env-vars-in-python }
Ви також можете створити змінні оточення поза Python, у терміналі (або будь-яким іншим способом), а потім зчитати їх у Python.
Ви також можете створити змінні оточення **поза** Python, у терміналі (або будь-яким іншим способом), а потім **зчитати їх у Python**.
Наприклад, у вас може бути файл `main.py` з:
@ -127,9 +127,9 @@ Hello Wade Wilson from Python
////
Оскільки змінні оточення можна встановлювати поза кодом, але читати в коді, і їх не потрібно зберігати (фіксувати у `git`) разом з іншими файлами, їх часто використовують для конфігурацій або налаштувань.
Оскільки змінні оточення можна встановлювати поза кодом, але читати в коді, і їх не потрібно зберігати (фіксувати у `git`) разом з іншими файлами, їх часто використовують для конфігурацій або **налаштувань**.
Ви також можете створити змінну оточення лише для конкретного запуску програми, вона буде доступна тільки цій програмі і лише на час її виконання.
Ви також можете створити змінну оточення лише для **конкретного запуску програми**, вона буде доступна тільки цій програмі і лише на час її виконання.
Щоб зробити це, створіть її безпосередньо перед командою запуску програми, в тому самому рядку:
@ -159,15 +159,15 @@ Hello World from Python
## Типи і перевірка { #types-and-validation }
Ці змінні оточення можуть містити лише текстові строки, оскільки вони зовнішні щодо Python і мають бути сумісними з іншими програмами та рештою системи (і навіть з різними операційними системами, як-от Linux, Windows, macOS).
Ці змінні оточення можуть містити лише **текстові строки**, оскільки вони зовнішні щодо Python і мають бути сумісними з іншими програмами та рештою системи (і навіть з різними операційними системами, як-от Linux, Windows, macOS).
Це означає, що будь-яке значення, прочитане в Python зі змінної оточення, буде `str`, а будь-яке перетворення до іншого типу або будь-яка перевірка має виконуватися в коді.
Це означає, що **будь-яке значення**, прочитане в Python зі змінної оточення, **буде `str`**, а будь-яке перетворення до іншого типу або будь-яка перевірка має виконуватися в коді.
Ви дізнаєтеся більше про використання змінних оточення для роботи з налаштуваннями застосунку в розділі [Просунутий посібник користувача - Налаштування і змінні оточення](./advanced/settings.md).
Ви дізнаєтеся більше про використання змінних оточення для роботи з **налаштуваннями застосунку** в розділі [Просунутий посібник користувача - Налаштування і змінні оточення](./advanced/settings.md).
### На основі відкритих стандартів { #based-on-open-standards }
* [**OpenAPI**](https://github.com/OAI/OpenAPI-Specification) для створення API, включаючи оголошення <dfntitle="також відомі як: кінцеві точки, маршрути">шляхів</dfn><dfntitle="також відомі як методи HTTP, як-от POST, GET, PUT, DELETE">операцій</dfn>, параметрів, тіл запитів, безпеки тощо.
* Автоматична документація моделей даних за допомогою [**JSON Schema**](https://json-schema.org/) (оскільки OpenAPI базується саме на JSON Schema).
* [**OpenAPI**](https://github.com/OAI/OpenAPI-Specification) для створення API, включаючи оголошення <dfntitle="також відомі як: кінцеві точки, маршрути">шляхових</dfn><dfntitle="також відомі як методи HTTP, як-от POST, GET, PUT, DELETE">операцій</dfn>, параметрів, тіл запитів, безпеки тощо.
* Автоматична документація моделей даних за допомогою [**Схеми JSON**](https://json-schema.org/) (оскільки OpenAPI базується саме на Схемі JSON).
* Розроблено на основі цих стандартів після ретельного аналізу, а не як додатковий рівень поверх основної архітектури.
* Це також дає змогу використовувати автоматичну **генерацію клієнтського коду** багатьма мовами.
@ -15,9 +15,9 @@
Інтерактивна документація API та вебінтерфейси для його дослідження. Оскільки фреймворк базується на OpenAPI, є кілька варіантів, 2 з яких включені за замовчуванням.
* [**Swagger UI**](https://github.com/swagger-api/swagger-ui) — з інтерактивним дослідженням, викликом і тестуванням вашого API прямо з браузера.
* [**Swagger UI**](https://github.com/swagger-api/swagger-ui) - з інтерактивним дослідженням, викликом і тестуванням вашого API прямо з браузера.
* Альтернативна документація API за допомогою [**ReDoc**](https://github.com/Rebilly/ReDoc).
@ -27,7 +27,7 @@
Усе базується на стандартних оголошеннях **типів Python** (завдяки Pydantic). Жодного нового синтаксису для вивчення. Лише стандартний сучасний Python.
Якщо вам потрібно 2-хвилинне нагадування про те, як використовувати типи Python (навіть якщо ви не використовуєте FastAPI), перегляньте короткий підручник: [Типи Python](python-types.md).
Якщо вам потрібно 2-хвилинне нагадування про те, як використовувати типи Python (навіть якщо ви не використовуєте FastAPI), перегляньте короткий навчальний посібник: [Типи Python](python-types.md).
Ви пишете стандартний Python з типами:
@ -85,13 +85,13 @@ my_second_user: User = User(**second_user_data)
* у [Visual Studio Code](https://code.visualstudio.com/):
Ви отримаєте автодоповнення в коді, який раніше могли вважати навіть неможливим. Наприклад, для ключа `price` всередині JSON body (який міг бути вкладеним), що надходить із запиту.
Ви отримаєте автодоповнення в коді, який раніше могли вважати навіть неможливим. Наприклад, для ключа `price` всередині тіла JSON (яке могло бути вкладеним), що надходить із запиту.
Більше не доведеться вводити неправильні назви ключів, постійно повертатися до документації або прокручувати вгору-вниз, щоб знайти, чи ви зрештою використали `username` чи `user_name`.
@ -106,7 +106,7 @@ FastAPI має розумні **налаштування за замовчува
* Підтримка валідації для більшості (або всіх?) **типів даних Python**, зокрема:
* JSON-об'єктів (`dict`).
* JSON-масивів (`list`) із визначенням типів елементів.
* Полів-рядків (`str`) із визначенням мінімальної та максимальної довжини.
* Полів-строк (`str`) із визначенням мінімальної та максимальної довжини.
* Чисел (`int`, `float`) з мінімальними та максимальними значеннями тощо.
* Валідація для більш екзотичних типів, як-от:
@ -124,30 +124,30 @@ FastAPI має розумні **налаштування за замовчува
Підтримуються всі схеми безпеки, визначені в OpenAPI, включно з:
* HTTP Basic.
* **OAuth2** (також із підтримкою **JWT tokens**). Перегляньте підручник: [OAuth2 із JWT](tutorial/security/oauth2-jwt.md).
* **OAuth2** (також із підтримкою **JWT tokens**). Перегляньте навчальний посібник: [OAuth2 із JWT](tutorial/security/oauth2-jwt.md).
* Ключі API в:
* Заголовках.
* Параметрах запиту.
* Cookies тощо.
* Кукі тощо.
А також усі можливості безпеки від Starlette (зокрема **session cookies**).
А також усі можливості безпеки від Starlette (зокрема **сесійні кукі**).
Усе це зроблено як багаторазові інструменти та компоненти, які легко інтегруються з вашими системами, сховищами даних, реляційними та NoSQL базами даних тощо.
### Впровадження залежностей { #dependency-injection }
FastAPI містить надзвичайно просту у використанні, але надзвичайно потужну систему <dfntitle='також відоме як «components», «resources», «services», «providers»'><strong>Впровадження залежностей</strong></dfn>.
FastAPI містить надзвичайно просту у використанні, але надзвичайно потужну систему <dfntitle='також відоме як «компоненти», «ресурси», «сервіси», «провайдери»'><strong>Впровадження залежностей</strong></dfn>.
* Навіть залежності можуть мати власні залежності, утворюючи ієрархію або **«граф» залежностей**.
* Усе **автоматично обробляється** фреймворком.
* Усі залежності можуть вимагати дані із запитів і **розширювати обмеження операції шляху** та автоматичну документацію.
* **Автоматична валідація** навіть для *операції шляху*, визначених у залежностях.
* **Автоматична валідація** навіть для параметрів *операції шляху*, визначених у залежностях.
* Підтримка складних систем автентифікації користувачів, **підключень до баз даних** тощо.
* **Жодних компромісів** із базами даних, фронтендами тощо. Але проста інтеграція з усіма ними.
### Необмежені «плагіни» { #unlimited-plug-ins }
Інакше кажучи, вони не потрібні — імпортуйте та використовуйте код, який вам потрібен.
Інакше кажучи, вони не потрібні - імпортуйте та використовуйте код, який вам потрібен.
Будь-яка інтеграція спроєктована так, щоб її було дуже просто використовувати (із залежностями), тож ви можете створити «плагін» для свого застосунку у 2 рядках коду, використовуючи ту саму структуру та синтаксис, що й для ваших *операцій шляху*.
@ -163,15 +163,15 @@ FastAPI містить надзвичайно просту у використа
`FastAPI` фактично є підкласом `Starlette`. Тому, якщо ви вже знайомі зі Starlette або використовуєте його, більшість функціональності працюватиме так само.
З **FastAPI** ви отримуєте всі можливості **Starlette** (адже FastAPI — це просто Starlette на стероїдах):
З **FastAPI** ви отримуєте всі можливості **Starlette** (адже FastAPI - це просто Starlette на стероїдах):
* Разюча продуктивність. Це [один із найшвидших доступних Python-фреймворків, на рівні з **NodeJS** і **Go**](https://github.com/encode/starlette#performance).
* Підтримка **WebSocket**.
* Фонові задачі у процесі.
* Події запуску та завершення роботи.
* Події запуску та вимкнення.
* Клієнт для тестування, побудований на HTTPX.
* Підтримка **CORS**, **GZip**, статичних файлів, потокових відповідей.
* Підтримка **сесій** і **cookie**.
* Підтримка **сесій і кукі**.
* 100% покриття тестами.
* 100% анотована типами кодова база.
@ -183,7 +183,7 @@ FastAPI містить надзвичайно просту у використа
Це також означає, що в багатьох випадках ви можете передати той самий об'єкт, який отримуєте із запиту, **безпосередньо в базу даних**, оскільки все автоматично перевіряється.
Те саме застосовується й у зворотному напрямку — у багатьох випадках ви можете просто передати об'єкт, який отримуєте з бази даних, **безпосередньо клієнту**.
Те саме застосовується й у зворотному напрямку - у багатьох випадках ви можете просто передати об'єкт, який отримуєте з бази даних, **безпосередньо клієнту**.
З **FastAPI** ви отримуєте всі можливості **Pydantic** (адже FastAPI базується на Pydantic для обробки всіх даних):
@ -193,8 +193,8 @@ FastAPI містить надзвичайно просту у використа
* Легко працює з вашим **<abbrtitle="Integrated Development Environment - Інтегроване середовище розробки: схоже на код-редактор">IDE</abbr>/<dfntitle="Програма, що перевіряє код на помилки">linter</dfn>/мозком**:
* Оскільки структури даних pydantic є просто екземплярами класів, які ви визначаєте; автодоповнення, лінтинг, mypy і ваша інтуїція повинні добре працювати з вашими перевіреними даними.
* Валідує **складні структури**:
* Використання ієрархічних моделей Pydantic, Python `typing`’s `List` і `Dict` тощо.
* Валідатори дають змогу складні схеми даних чітко й просто визначати, перевіряти й документувати як JSON Schema.
* Використання ієрархічних моделей Pydantic, `List` і `Dict` з Python `typing` тощо.
* Валідатори дають змогу складні схеми даних чітко й просто визначати, перевіряти й документувати як Схему JSON.
* Ви можете мати глибоко **вкладені JSON** об'єкти, і всі вони будуть валідовані та анотовані.
* **Розширюваність**:
* Pydantic дозволяє визначати користувацькі типи даних або ви можете розширити валідацію методами в моделі, позначеними декоратором validator.
Це об’єкти **JavaScript**, а не строки, тому ви не можете передати їх безпосередньо з коду Python.
Якщо вам потрібно використати такі налаштування лише для JavaScript, скористайтеся одним із методів вище. Повністю перепишіть операцію шляху Swagger UI та вручну напишіть потрібний JavaScript.
Якщо вам потрібно використати такі налаштування лише для JavaScript, скористайтеся одним із методів вище. Повністю перепишіть *операцію шляху* Swagger UI та вручну напишіть потрібний JavaScript.
Оскільки FastAPI базується на стандарті ASGI, дуже просто інтегрувати будь-яку бібліотеку GraphQL, сумісну з ASGI.
Оскільки **FastAPI** базується на стандарті **ASGI**, дуже просто інтегрувати будь-яку бібліотеку **GraphQL**, сумісну з ASGI.
Ви можете поєднувати звичайні *операції шляху* FastAPI з GraphQL в одному застосунку.
/// tip | Порада
GraphQL розв’язує деякі дуже специфічні сценарії використання.
**GraphQL** розв’язує деякі дуже специфічні сценарії використання.
Порівняно зі звичайними веб-API він має переваги та недоліки.
Порівняно зі звичайними **веб-API** він має **переваги** та **недоліки**.
Переконайтеся, що переваги для вашого випадку використання переважають недоліки. 🤓
Переконайтеся, що **переваги** для вашого випадку використання переважають **недоліки**. 🤓
///
## Бібліотеки GraphQL { #graphql-libraries }
Ось деякі бібліотеки GraphQL з підтримкою ASGI. Ви можете використовувати їх із FastAPI:
Ось деякі бібліотеки **GraphQL** з підтримкою **ASGI**. Ви можете використовувати їх із **FastAPI**:
* [Strawberry](https://strawberry.rocks/) 🍓
* З [документацією для FastAPI](https://strawberry.rocks/docs/integrations/fastapi)
@ -29,23 +29,23 @@ GraphQL розв’язує деякі дуже специфічні сцена
## GraphQL зі Strawberry { #graphql-with-strawberry }
Якщо вам потрібен або ви хочете використовувати GraphQL, [Strawberry](https://strawberry.rocks/) - рекомендована бібліотека, адже її дизайн найближчий до дизайну FastAPI; усе базується на анотаціях типів.
Якщо вам потрібен або ви хочете використовувати **GraphQL**, [**Strawberry**](https://strawberry.rocks/) - **рекомендована** бібліотека, адже її дизайн найближчий до дизайну **FastAPI**; усе базується на **анотаціях типів**.
Залежно від вашого сценарію використання ви можете надати перевагу іншій бібліотеці, але якби ви запитали мене, я, ймовірно, порадив би спробувати Strawberry.
Залежно від вашого сценарію використання ви можете надати перевагу іншій бібліотеці, але якби ви запитали мене, я, ймовірно, порадив би спробувати **Strawberry**.
Ось невеликий приклад того, як інтегрувати Strawberry з FastAPI:
Ось невеликий попередній перегляд того, як ви могли б інтегрувати Strawberry з FastAPI:
Більше про Strawberry ви можете дізнатися в [документації Strawberry](https://strawberry.rocks/).
І також [документацію про Strawberry з FastAPI](https://strawberry.rocks/docs/integrations/fastapi).
І також документацію про [Strawberry з FastAPI](https://strawberry.rocks/docs/integrations/fastapi).
## Застарілий `GraphQLApp` зі Starlette { #older-graphqlapp-from-starlette }
Попередні версії Starlette містили клас `GraphQLApp` для інтеграції з [Graphene](https://graphene-python.org/).
Його вилучено з Starlette як застарілий, але якщо у вас є код, що його використовував, ви можете легко мігрувати на [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3), який покриває той самий сценарій використання та має майже ідентичний інтерфейс.
Його було оголошено застарілим у Starlette, але якщо у вас є код, що його використовував, ви можете легко **мігрувати** на [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3), який покриває той самий сценарій використання та має **майже ідентичний інтерфейс**.
/// tip | Порада
@ -55,6 +55,6 @@ GraphQL розв’язує деякі дуже специфічні сцена
## Дізнайтеся більше { #learn-more }
Ви можете дізнатися більше про GraphQL в [офіційній документації GraphQL](https://graphql.org/).
Ви можете дізнатися більше про **GraphQL** в [офіційній документації GraphQL](https://graphql.org/).
Також ви можете почитати більше про кожну з цих бібліотек за наведеними посиланнями.
Також ви можете почитати більше про кожну з цих бібліотек, описаних вище, за наведеними посиланнями.
Якщо у вас стара програма FastAPI з Pydantic v1, нижче я покажу, як мігрувати на Pydantic v2, а також можливості FastAPI 0.119.0, які допоможуть з поступовою міграцією.
Якщо у вас стара програма FastAPI з Pydantic v1, нижче я покажу, як мігрувати на Pydantic v2, а також **можливості FastAPI 0.119.0**, які допоможуть з поступовою міграцією.
## Офіційний посібник { #official-guide }
@ -54,6 +56,16 @@ Pydantic v2 містить усе з Pydantic v1 як підмодуль `pydant
### Підтримка FastAPI для Pydantic v1 у v2 { #fastapi-support-for-pydantic-v1-in-v2 }
/// warning | Попередження
Цю підтримку FastAPI для моделей `pydantic.v1` було додано у **FastAPI 0.119.0** і видалено у **FastAPI 0.128.0**. Вона була задумана як тимчасова допомога для міграції на Pydantic v2.
У поточних версіях FastAPI використання моделі `pydantic.v1` у вашій програмі спричинить помилку.
Решта цього розділу описує тимчасову підтримку, доступну лише в тих старіших версіях.
///
Починаючи з FastAPI 0.119.0, також є часткова підтримка Pydantic v1 всередині Pydantic v2, щоб спростити перехід на v2.
Тож ви можете оновити Pydantic до останньої версії 2 і змінити імпорти на використання підмодуля `pydantic.v1`, і в багатьох випадках усе просто запрацює.
@ -122,6 +134,12 @@ graph TB
### Покрокова міграція { #migrate-in-steps }
/// warning | Попередження
Поступова міграція з використанням моделей Pydantic v1 і v2 в одній програмі, описана нижче, працює лише у **FastAPI 0.119.0 до 0.127.x**. Її було видалено у **FastAPI 0.128.0**, найновіші версії вимагають моделей **Pydantic v2**.
///
/// tip | Порада
Спершу спробуйте `bump-pydantic`: якщо ваші тести проходять і все працює - ви впоралися однією командою. ✨
Відколи вийшов **Pydantic v2**, згенерований OpenAPI став трохи точнішим і більш **коректним**, ніж раніше. 😎
Насправді подекуди буде навіть **дві схеми JSON** в OpenAPI для тієї самої моделі Pydantic: для введення та для виведення - залежно від наявності значень за замовчуванням.
Насправді подекуди буде навіть **дві Схеми JSON** в OpenAPI для тієї самої моделі Pydantic: для введення та для виведення - залежно від наявності **значень за замовчуванням**.
Розгляньмо, як це працює, і як це змінити за потреби.
…тоді, оскільки `description` має значення за замовчуванням, якщо ви нічого не повернете для цього поля, воно все одно матиме це **значення за замовчуванням**.
…тоді, оскільки `description` має значення за замовчуванням, якщо ви **нічого не повернете** для цього поля, воно все одно матиме це **значення за замовчуванням**.
### Модель для даних відповіді при виведенні { #model-for-output-response-data }
@ -51,12 +51,13 @@
У OpenAPI це описується тим, що поле позначається як **обов'язкове**, адже воно завжди присутнє.
Тому Схема JSON для моделі може відрізнятися залежно від того, чи використовується вона для **введення або виведення**:
- для **введення**`description` не буде обов'язковим
- для **виведення** воно буде **обов'язковим** (і можливо `None`, або в термінах JSON - `null`)
* для **введення**`description` **не буде обов'язковим**
* для **виведення** воно буде **обов'язковим** (і можливо `None`, або в термінах JSON - `null`)
### Модель для виведення в документації { #model-for-output-in-docs }
У документації ви також можете перевірити модель для виведення: **і**`name`, і `description` позначені як **обов'язкові** червоною зірочкою:
У документації ви також можете перевірити модель для виведення: **і**`name`, і `description` позначені як **обов'язкові****червоною зірочкою**:
@ -49,7 +49,7 @@ FastAPI - це сучасний, швидкий (високопродуктив
* **Простий**: спроєктований так, щоб бути простим у використанні та вивченні. Менше часу на читання документації.
* **Короткий**: мінімізує дублювання коду. Кілька можливостей з кожного оголошення параметра. Менше помилок.
* **Надійний**: ви отримуєте код, готовий до продакшну. З автоматичною інтерактивною документацією.
* **Заснований на стандартах**: базується на (і повністю сумісний з) відкритими стандартами для API: [OpenAPI](https://github.com/OAI/OpenAPI-Specification) (раніше відомий як Swagger) та [JSON Schema](https://json-schema.org/).
* **Заснований на стандартах**: базується на (і повністю сумісний з) відкритими стандартами для API: [OpenAPI](https://github.com/OAI/OpenAPI-Specification) (раніше відомий як Swagger) та [Схема JSON](https://json-schema.org/).
<small>* оцінка на основі тестів, проведених внутрішньою командою розробників, що створює продакшн-застосунки.</small>
@ -105,47 +105,47 @@ FastAPI - це сучасний, швидкий (високопродуктив
<blockquoteclass="fastapi-opinions__quote">«Я дуже часто використовую <strong>FastAPI</strong> останнім часом. Я насправді планую використовувати його для всіх <strong>ML-сервісів моєї команди в Microsoft</strong>. Деякі з них інтегруються до основного продукту <strong>Windows</strong> і деякі з продуктів <strong>Office</strong>».</blockquote>
<divclass="fastapi-opinions__attr">— Kabir Khan, <strong>Microsoft</strong><ahref="https://github.com/fastapi/fastapi/pull/26">(ref)</a></div>
<blockquoteclass="fastapi-opinions__quote">«Я дуже часто використовую <strong>FastAPI</strong> останнім часом. Я насправді планую використовувати його для всіх <strong>ML-сервісів моєї команди в Microsoft</strong>. Деякі з них інтегруються до основного продукту <strong>Windows</strong> і деяких продуктів <strong>Office</strong>».</blockquote>
<divclass="fastapi-opinions__attr">- Kabir Khan, <strong>Microsoft</strong><ahref="https://github.com/fastapi/fastapi/pull/26">(джерело)</a></div>
<blockquoteclass="fastapi-opinions__quote">«Ми прийняли бібліотеку <strong>FastAPI</strong>, щоб запустити сервер <strong>REST</strong>, до якого можна надсилати запити для отримання <strong>прогнозів</strong>». <em>[для Ludwig]</em></blockquote>
<divclass="fastapi-opinions__attr">— Piero Molino, Yaroslav Dudin, Sai Sumanth Miryala, <strong>Uber</strong><ahref="https://eng.uber.com/ludwig-v0-2/">(ref)</a></div>
<divclass="fastapi-opinions__attr">- Piero Molino, Yaroslav Dudin, Sai Sumanth Miryala, <strong>Uber</strong><ahref="https://eng.uber.com/ludwig-v0-2/">(джерело)</a></div>
<blockquoteclass="fastapi-opinions__quote">«<strong>Netflix</strong> із задоволенням оголошує про випуск з відкритим кодом нашого фреймворку оркестрації <strong>керування кризами</strong>: <strong>Dispatch</strong>!» <em>[побудовано з FastAPI]</em></blockquote>
<divclass="fastapi-opinions__attr">— Kevin Glisson, Marc Vilanova, Forest Monsen, <strong>Netflix</strong><ahref="https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072">(ref)</a></div>
<divclass="fastapi-opinions__attr">- Kevin Glisson, Marc Vilanova, Forest Monsen, <strong>Netflix</strong><ahref="https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072">(джерело)</a></div>
<blockquoteclass="fastapi-opinions__quote">«Якщо хтось хоче створювати продакшн-API на Python, я дуже рекомендую <strong>FastAPI</strong>. Він <strong>чудово спроєктований</strong>, <strong>простий у використанні</strong> і <strong>дуже масштабований</strong>— він став <strong>ключовим компонентом</strong> у нашій стратегії розробки з пріоритетом API».</blockquote>
<blockquoteclass="fastapi-opinions__quote">«Якщо хтось хоче створювати продакшн-API на Python, я дуже рекомендую <strong>FastAPI</strong>. Він <strong>чудово спроєктований</strong>, <strong>простий у використанні</strong> і <strong>дуже масштабований</strong>- він став <strong>ключовим компонентом</strong> у нашій стратегії розробки з пріоритетом API».</blockquote>
"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._"
"_[...] Я дуже часто використовую **FastAPI** останнім часом. [...] Я насправді планую використовувати його для всіх **ML-сервісів моєї команди в Microsoft**. Деякі з них інтегруються до основного продукту **Windows** і деяких продуктів **Office**._"
"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_"
"_Ми прийняли бібліотеку **FastAPI**, щоб запустити сервер **REST**, до якого можна надсилати запити для отримання **прогнозів**. [для Ludwig]_"
<divstyle="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong><ahref="https://eng.uber.com/ludwig-v0-2/"><small>(ref)</small></a></div>
<divstyle="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong><ahref="https://eng.uber.com/ludwig-v0-2/"><small>(джерело)</small></a></div>
---
"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with**FastAPI**]_"
"_**Netflix** із задоволенням оголошує про випуск з відкритим кодом нашого фреймворку оркестрації **керування кризами**: **Dispatch**! [побудовано з**FastAPI**]_"
"_If anyone is looking to build a production Python API, I would highly recommend **FastAPI**. It is **beautifully designed**, **simple to use** and **highly scalable**, it has become a **key component** in our API first development strategy and is driving many automations and services such as our Virtual TAC Engineer._"
"_Якщо хтось хоче створювати продакшн-API на Python, я дуже рекомендую **FastAPI**. Він **чудово спроєктований**, **простий у використанні** і **дуже масштабований**, він став **ключовим компонентом** у нашій стратегії розробки з пріоритетом API і забезпечує багато автоматизацій та сервісів, як-от наш Virtual TAC Engineer._"
Якщо ви не знаєте, перегляньте розділ _"In a hurry?"_ про [`async` та `await` у документації](https://fastapi.tiangolo.com/uk/async/#in-a-hurry).
Якщо ви не знаєте, перегляньте розділ _«Поспішаєте?»_ про [`async` та `await` у документації](https://fastapi.tiangolo.com/uk/async/#in-a-hurry).
</details>
@ -412,10 +412,10 @@ item: Item
* JSON.
* Параметрів шляху.
* Параметрів запиту.
* Cookies.
* Headers.
* Forms.
* Files.
* Кукі.
* Заголовків.
* Форм.
* Файлів.
* <dfntitle="також відоме як: серіалізація, парсинг, маршалінг">Перетворення</dfn> вихідних даних: перетворення з даних і типів Python у мережеві дані (як JSON):
* Перетворення типів Python (`str`, `int`, `float`, `bool`, `list`, тощо).
* Обʼєктів `datetime`.
@ -477,10 +477,10 @@ item: Item
**Попередження про спойлер**: навчальний посібник - посібник користувача містить:
* Оголошення **параметрів** з інших різних місць, як-от: **headers**, **cookies**, **form fields** та **files**.
* Оголошення **параметрів** з інших різних місць, як-от: **заголовки**, **кукі**, **поля форми** та **файли**.
* Як встановлювати **обмеження валідації** як `maximum_length` або `regex`.
* Дуже потужну і просту у використанні систему **<dfntitle="також відоме як: компоненти, ресурси, провайдери, сервіси, інжектовані залежності">Впровадження залежностей</dfn>**.
* Безпеку та автентифікацію, включно з підтримкою **OAuth2** з **JWT tokens** та **HTTP Basic** auth.
* Безпеку та автентифікацію, включно з підтримкою **OAuth2** з **токенами JWT** та **базовою автентифікацією HTTP**.
* Досконаліші (але однаково прості) техніки для оголошення **глибоко вкладених моделей JSON** (завдяки Pydantic).
* Інтеграцію **GraphQL** з [Strawberry](https://strawberry.rocks) та іншими бібліотеками.
* Багато додаткових можливостей (завдяки Starlette) як-от:
Він спрощує процес **створення**, **розгортання** та **доступу** до API з мінімальними зусиллями.
Він забезпечує той самий **developer experience** створення застосунків на FastAPI під час їх **розгортання** у хмарі. 🎉
Він забезпечує той самий **досвід розробника** створення застосунків на FastAPI під час їх **розгортання** у хмарі. 🎉
FastAPI Cloud - основний спонсор і джерело фінансування open source проєктів *FastAPI and friends*. ✨
FastAPI Cloud - основний спонсор і джерело фінансування проєктів з відкритим кодом*FastAPI and friends*. ✨
#### Розгортання в інших хмарних провайдерів { #deploy-to-other-cloud-providers }
FastAPI - open source проєкт і базується на стандартах. Ви можете розгортати застосунки FastAPI в будь-якому хмарному провайдері, який ви оберете.
FastAPI - проєкт з відкритим кодом і базується на стандартах. Ви можете розгортати застосунки FastAPI в будь-якому хмарному провайдері, який ви оберете.
Дотримуйтеся інструкцій вашого хмарного провайдера, щоб розгорнути застосунки FastAPI у нього. 🤓
@ -532,7 +532,7 @@ FastAPI - open source проєкт і базується на стандарта
Незалежні тести TechEmpower показують застосунки **FastAPI**, які працюють під керуванням Uvicorn, як [одні з найшвидших доступних Python-фреймворків](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7), поступаючись лише Starlette та Uvicorn (які внутрішньо використовуються в FastAPI). (*)
Щоб дізнатися більше, перегляньте розділ [Benchmarks](https://fastapi.tiangolo.com/uk/benchmarks/).
Щоб дізнатися більше, перегляньте розділ [Тести продуктивності](https://fastapi.tiangolo.com/uk/benchmarks/).
# Шаблон Full Stack FastAPI { #full-stack-fastapi-template }
Шаблони, хоча зазвичай постачаються з певним налаштуванням, спроєктовані бути гнучкими та налаштовуваними. Це дає змогу змінювати їх і адаптувати до вимог вашого проєкту, що робить їх чудовою відправною точкою. 🏁
Ви можете використати цей шаблон для старту, адже в ньому вже виконано значну частину початкового налаштування, безпеки, роботи з базою даних і деяких кінцевих точок API.
Python підтримує додаткові «підказки типів» (також звані «анотаціями типів»).
Ці **«підказки типів»** або анотації — це спеціальний синтаксис, що дозволяє оголошувати <dfntitle="наприклад: str, int, float, bool">тип</dfn> змінної.
Ці **«підказки типів»** або анотації - це спеціальний синтаксис, що дозволяє оголошувати <dfntitle="наприклад: str, int, float, bool">тип</dfn> змінної.
За допомогою оголошення типів для ваших змінних редактори та інструменти можуть надати вам кращу підтримку.
@ -50,7 +50,7 @@ John Doe
Це буде `upper`? Чи `uppercase`? `first_uppercase`? `capitalize`?
Тоді ви спробуєте давнього друга програміста — автозаповнення редактора коду.
Тоді ви спробуєте давнього друга програміста - автозаповнення редактора коду.
Ви надрукуєте перший параметр функції, `first_name`, тоді крапку (`.`), а тоді натиснете `Ctrl+Space`, щоб запустити автозаповнення.
Деякі типи можуть приймати «параметри типів» у квадратних дужках, щоб визначити їх внутрішні типи. Наприклад, «list строк» буде оголошений як `list[str]`.
Ці типи, які можуть приймати параметри типів, називаються **generic типами** або **generics**.
Ці типи, які можуть приймати параметри типів, називаються **узагальненими типами** або **дженериками**.
Ви можете використовувати ті самі вбудовані типи як generics (з квадратними дужками та типами всередині):
Ви можете використовувати ті самі вбудовані типи як дженерики (з квадратними дужками та типами всередині):
* `list`
* `tuple`
* `set`
* `dict`
#### List { #list }
#### Список { #list }
Наприклад, давайте визначимо змінну, яка буде `list` із `str`.
* Ключі цього `dict` мають тип `str` (скажімо, назва кожного предмета).
* Значення цього `dict` мають тип `float` (скажімо, ціна кожного предмета).
#### Union { #union }
#### Об’єднання { #union }
Ви можете оголосити, що змінна може бути будь-яким із **кількох типів**, наприклад `int` або `str`.
Щоб визначити це, використовуйте <dfntitle='також називають «побітовим оператором "або"», але це значення тут не актуальне'>вертикальну риску (`|`)</dfn>, щоб розділити обидва типи.
Це називається «union», тому що змінна може бути чимось із об’єднання цих двох множин типів.
Це називається «об’єднанням», тому що змінна може бути чимось із об’єднання цих двох множин типів.
Зверніть увагу, що це означає: «`one_person` — це **екземпляр** класу `Person`».
Зверніть увагу, що це означає: «`one_person` - це **екземпляр** класу `Person`».
Це не означає: «`one_person` — це **клас** з назвою `Person`».
Це не означає: «`one_person` - це **клас** з назвою `Person`».
## Pydantic моделі { #pydantic-models }
## Моделі Pydantic { #pydantic-models }
[Pydantic](https://docs.pydantic.dev/) — це бібліотека Python для валідації даних.
@ -295,7 +295,7 @@ def some_function(data: Any):
## Підказки типів з анотаціями метаданих { #type-hints-with-metadata-annotations }
У Python також є можливість додавати **додаткові <dfn title="Дані про дані, у цьому випадку — інформація про тип, наприклад опис.">метадані</dfn>** до цих підказок типів за допомогою `Annotated`.
У Python також є можливість додавати **додаткові <dfn title="Дані про дані, у цьому випадку - інформація про тип, наприклад опис.">метадані</dfn>** до цих підказок типів за допомогою `Annotated`.
Ви можете імпортувати `Annotated` з `typing`.
@ -305,7 +305,7 @@ def some_function(data: Any):
Але ви можете використати це місце в `Annotated`, щоб надати **FastAPI** додаткові метадані про те, як ви хочете, щоб ваш застосунок поводився.
Важливо пам’ятати, що **перший *параметр типу***, який ви передаєте в `Annotated`, — це **фактичний тип**. Решта — це лише метадані для інших інструментів.
Важливо пам’ятати, що **перший *параметр типу***, який ви передаєте в `Annotated`, - це **фактичний тип**. Решта - це лише метадані для інших інструментів.
Наразі вам просто потрібно знати, що `Annotated` існує і що це стандартний Python. 😎
@ -335,7 +335,7 @@ def some_function(data: Any):
* **Перевірки даних**: що надходять від кожного запиту:
* Генерування **автоматичних помилок**, що повертаються клієнту, коли дані недійсні.
* **Документування** API за допомогою OpenAPI:
* який потім використовується для автоматичної інтерактивної документації користувальницьких інтерфейсів.
* що потім використовується автоматичними інтерактивними користувацькими інтерфейсами документації.
Все це може здатися абстрактним. Не хвилюйтеся. Ви побачите все це в дії в [Навчальний посібник - Посібник користувача](tutorial/index.md).
Це означатиме, що **FastAPI** очікуватиме тіло запиту такого вигляду:
Це означатиме, що **FastAPI** очікуватиме тіло, подібне до:
```JSON
{
@ -85,7 +85,7 @@ my_list: list[str]
}
```
Завдяки такій декларації у**FastAPI** ви отримуєте:
Знову ж, лише завдяки такому оголошенню, з**FastAPI** ви отримуєте:
* Підтримку в редакторі (автозавершення тощо), навіть для вкладених моделей
* Конвертацію даних
@ -94,23 +94,23 @@ my_list: list[str]
## Спеціальні типи та валідація { #special-types-and-validation }
Окрім звичайних типів, таких як `str`, `int`, `float`, та ін. ви можете використовувати складніші типи, які наслідують `str`.
Окрім звичайних одиничних типів, таких як `str`, `int`, `float`, та ін. ви можете використовувати складніші одиничні типи, які наслідують `str`.
Щоб побачити всі доступні варіанти, ознайомтеся з [Оглядом типів у Pydantic](https://docs.pydantic.dev/latest/concepts/types/). Деякі приклади будуть у наступному розділі.
Наприклад, у моделі `Image` є поле `url`, тому ми можемо оголосити його як `HttpUrl` від Pydantic замість `str`:
Наприклад, оскільки в моделі `Image` є поле `url`, ми можемо оголосити його як екземпляр`HttpUrl` від Pydantic замість `str`:
Це означає, що **FastAPI** буде очікувати (конвертувати, валідувати, документувати тощо) JSON тіло запиту у вигляді:
Це очікуватиме (конвертуватиме, валідуватиме, документуватиме тощо) тіло JSON у вигляді:
```JSON hl_lines="11"
{
@ -150,61 +150,61 @@ my_list: list[str]
/// note | Примітка
Зверніть увагу, що в моделі `Offer` є список `Item`ів, які, своєю чергою, можуть мати необов'язковий список `Image`ів.
Зверніть увагу, що `Offer`має список `Item`ів, які, своєю чергою, мають необов'язковий список `Image`ів
///
## Тіла запитів, що складаються зі списків { #bodies-of-pure-lists }
Якщо верхній рівень JSON тіла, яке ви очікуєте, є JSON `масивом` (у Python —`list`), ви можете оголосити тип у параметрі функції, як і в моделях Pydantic:
Якщо значення верхнього рівня JSON тіла, яке ви очікуєте, є JSON `array` (Python`list`), ви можете оголосити тип у параметрі функції так само, як у моделях Pydantic:
Майте на увазі, що в JSON тілі ключі можуть бути лише рядками (`str`).
Майте на увазі, що JSON підтримує лише `str` як ключі.
Але Pydantic автоматично конвертує дані.
Але Pydantic має автоматичну конвертацію даних.
Це означає, що навіть якщо клієнти вашого API надсилатимуть ключі у вигляді рядків, якщо вони містять цілі числа, Pydantic конвертує їх і проведе валідацію.
Це означає, що навіть якщо клієнти вашого API можуть надсилати лише строки як ключі, якщо ці строки містять цілі числа, Pydantic конвертує їх і проведе валідацію.
Тобто`dict`, який ви отримаєте як `weights`, матиме ключі типу `int` та значення типу `float`.
І`dict`, який ви отримаєте як `weights`, фактично матиме ключі типу `int` та значення типу `float`.
///
@ -212,10 +212,10 @@ images: list[Image]
З **FastAPI** ви маєте максимальну гнучкість завдяки моделям Pydantic, зберігаючи при цьому код простим, коротким та елегантним.
А також отримуєте всі переваги:
Але з усіма перевагами:
* Підтримка в редакторі (автодоповнення всюди!)
* Конвертація даних (парсинг/серіалізація)
* Підтримка в редакторі (автозавершення всюди!)
* Конвертація даних (також відома як парсинг/серіалізація)
Тіло **запиту** - це дані, надіслані клієнтом до вашого API. Тіло **відповіді** - це дані, які ваш API надсилає клієнту.
Ваш API майже завжди має надсилати тіло **відповіді**. Але клієнтам не обов’язково потрібно постійно надсилати тіла **запитів**— інколи вони лише запитують шлях, можливо з деякими параметрами запиту, але не надсилають тіло.
Ваш API майже завжди має надсилати тіло **відповіді**. Але клієнтам не обов’язково потрібно постійно надсилати тіла **запитів**- інколи вони лише запитують шлях, можливо з деякими параметрами запиту, але не надсилають тіло.
Щоб оголосити тіло **запиту**, ви використовуєте [Pydantic](https://docs.pydantic.dev/) моделі з усією їх потужністю та перевагами.
@ -63,7 +63,7 @@ FastAPI підтримує залежності, які виконують де
Ви можете мати підзалежності та «дерева» підзалежностей будь-якого розміру і форми, і будь-яка або всі з них можуть використовувати `yield`.
**FastAPI** гарантує, що «exit code» у кожній залежності з `yield` буде виконано в правильному порядку.
**FastAPI** гарантує, що «код виходу» у кожній залежності з `yield` буде виконано в правильному порядку.
Наприклад, `dependency_c` може залежати від `dependency_b`, а `dependency_b` - від `dependency_a`:
@ -194,7 +194,7 @@ participant tasks as Background tasks
`Depends()` приймає параметр `scope`, який може бути:
* `"function"`: запустити залежність перед *функцією операції шляху*, що обробляє запит, завершити залежність після завершення *функції операції шляху*, але **до** того, як відповідь буде відправлена клієнту. Тобто функція залежності буде виконуватися **навколо***функції операції **шляху***.
* `"function"`: запустити залежність перед *функцією операції шляху*, що обробляє запит, завершити залежність після завершення *функції операції шляху*, але **до** того, як відповідь буде відправлена клієнту. Тобто функція залежності буде виконуватися **навколо*****функції** операції шляху*.
* `"request"`: запустити залежність перед *функцією операції шляху*, що обробляє запит (подібно до `"function"`), але завершити **після** того, як відповідь буде відправлена клієнту. Тобто функція залежності буде виконуватися **навколо** циклу **запиту** та відповіді.
Якщо не вказано, і залежність має `yield`, за замовчуванням `scope` дорівнює `"request"`.
@ -234,6 +234,7 @@ participant operation as Path Operation
Залежності з `yield` еволюціонували з часом, щоб покрити різні сценарії та виправити деякі проблеми.
Якщо ви хочете дізнатися, що змінювалося в різних версіях FastAPI, прочитайте про це в просунутому посібнику користувача: [Розширені залежності - Залежності з `yield`, `HTTPException`, `except` і фоновими задачами](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks).
## Менеджери контексту { #context-managers }
### Що таке «Менеджери контексту» { #what-are-context-managers }
* Стандартний "Універсальний унікальний ідентифікатор", який часто використовується як ID у багатьох базах даних та системах.
* Стандартний «Універсальний унікальний ідентифікатор», який часто використовується як ID у багатьох базах даних та системах.
* У запитах та відповідях буде представлений як `str`.
* `datetime.datetime`:
* Пайтонівський `datetime.datetime`.
@ -36,16 +36,16 @@
* `datetime.timedelta`:
* Пайтонівський `datetime.timedelta`.
* У запитах та відповідях буде представлений як `float` загальної кількості секунд.
* Pydantic також дозволяє представляти це як "ISO 8601 time diff encoding", [дивіться документацію для отримання додаткової інформації](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers).
* Pydantic також дозволяє представляти це як «ISO 8601 time diff encoding», [дивіться документацію для отримання додаткової інформації](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers).
* `frozenset`:
* У запитах і відповідях це буде оброблено так само, як і `set`:
* У запитах список буде зчитано, дублікати буде видалено, і його буде перетворено на `set`.
* У відповідях `set` буде перетворено на `list`.
* Згенерована схема буде вказувати, що значення `set` є унікальними (з використанням JSON Schema's `uniqueItems`).
* Згенерована схема буде вказувати, що значення `set` є унікальними (з використанням `uniqueItems` Схеми JSON).
* `bytes`:
* Стандартний Пайтонівський `bytes`.
* У запитах і відповідях це буде оброблено як `str`.
* Згенерована схема буде вказувати, що це `str` з "форматом"`binary`.
* Згенерована схема буде вказувати, що це `str` з «форматом»`binary`.
* `Decimal`:
* Стандартний Пайтонівський `Decimal`.
* У запитах і відповідях це буде оброблено так само, як і `float`.
Якщо взяти `dict`, наприклад `user_dict`, і передати його у функцію (або клас) як `**user_dict`, Python «розпакує» його. Ключі та значення `user_dict` будуть передані безпосередньо як іменовані аргументи.
Якщо взяти `dict`, наприклад `user_dict`, і передати його у функцію (або клас) як `**user_dict`, Python «розпакує» його. Ключі та значення `user_dict` будуть передані безпосередньо як аргументи ключ-значення.
Отже, продовжуючи з `user_dict` вище, запис:
@ -176,7 +176,7 @@ UserInDB(
У цьому прикладі ми передаємо `Union[PlaneItem, CarItem]` як значення аргументу `response_model`.
Оскільки ми передаємо його як значення аргументу, а не в анотації типу, потрібно використовувати `Union` навіть у Python 3.10.
Оскільки ми передаємо його як **значення аргументу**, а не розміщуємо в **анотації типу**, потрібно використовувати `Union` навіть у Python 3.10.
Якби це була анотація типу, можна було б використати вертикальну риску, наприклад:
@ -184,7 +184,7 @@ UserInDB(
some_variable: PlaneItem | CarItem
```
Але якщо записати це як присвоєння `response_model=PlaneItem | CarItem`, отримаємо помилку, тому що Python спробує виконати невалідну операцію між `PlaneItem` і `CarItem`, замість того щоб трактувати це як анотацію типу.
Але якщо записати це як присвоєння `response_model=PlaneItem | CarItem`, отримаємо помилку, тому що Python спробує виконати **невалідну операцію** між `PlaneItem` і `CarItem`, замість того щоб трактувати це як анотацію типу.
Використовуйте кілька моделей Pydantic і вільно наслідуйте для кожного випадку.
Не обов’язково мати одну модель даних на сутність, якщо ця сутність може мати різні «стани». Як у випадку сутності користувача зі станами: з `password`, з `password_hash` і без пароля.
Не обов’язково мати одну модель даних на сутність, якщо ця сутність повинна мати різні «стани». «Сутність» **користувач** є прикладом зі станами, що включають `password`, `password_hash` або відсутність пароля.
@ -88,13 +88,13 @@ INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
#### «Схема» { #schema }
«Схема» — це визначення або опис чогось. Це не код, який його реалізує, а просто абстрактний опис.
«Схема» - це визначення або опис чогось. Це не код, який його реалізує, а просто абстрактний опис.
#### API «схема» { #api-schema }
У цьому випадку, [OpenAPI](https://github.com/OAI/OpenAPI-Specification) є специфікацією, яка визначає, як описати схему вашого API.
Це визначення схеми включає шляхи (paths) вашого API, можливі параметри, які вони приймають, тощо.
Це визначення схеми включає шляхи вашого API, можливі параметри, які вони приймають, тощо.
#### «Схема» даних { #data-schema }
@ -102,13 +102,13 @@ INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
У цьому випадку це означає атрибути JSON і типи даних, які вони мають, тощо.
#### OpenAPI і JSON Schema { #openapi-and-json-schema }
#### OpenAPI і Схема JSON { #openapi-and-json-schema }
OpenAPI описує схему API для вашого API. І ця схема включає визначення (або «схеми») даних, що надсилаються та отримуються вашим API, за допомогою **JSON Schema**, стандарту для схем даних JSON.
OpenAPI описує схему API для вашого API. І ця схема включає визначення (або «схеми») даних, що надсилаються та отримуються вашим API, за допомогою **Схеми JSON**, стандарту для схем даних JSON.
Якщо вас цікавить, як виглядає «сирий» OpenAPI schema, FastAPI автоматично генерує JSON (schema) з описами всього вашого API.
Якщо вас цікавить, як виглядає «сирa» схема OpenAPI, FastAPI автоматично генерує JSON (схему) з описами всього вашого API.
Ви можете побачити це напряму тут: [http://127.0.0.1:8000/openapi.json](http://127.0.0.1:8000/openapi.json).
@ -137,7 +137,7 @@ OpenAPI описує схему API для вашого API. І ця схема
#### Для чого потрібний OpenAPI { #what-is-openapi-for }
OpenAPI schema — це те, на чому працюють дві включені системи інтерактивної документації.
Схема OpenAPI - це те, на чому працюють дві включені системи інтерактивної документації.
Також існують десятки альтернатив, і всі вони засновані на OpenAPI. Ви можете легко додати будь-яку з цих альтернатив до вашого застосунку, створеного з **FastAPI**.
`FastAPI`— це клас у Python, який надає всю функціональність для вашого API.
`FastAPI`- це клас у Python, який надає всю функціональність для вашого API.
/// note | Технічні деталі
`FastAPI`— це клас, який успадковується безпосередньо від `Starlette`.
`FastAPI`- це клас, який успадковується безпосередньо від `Starlette`.
Ви також можете використовувати всю функціональність [Starlette](https://www.starlette.dev/) у `FastAPI`.
@ -312,7 +312,7 @@ https://example.com/items/foo
Декоратор `@app.get("/")` повідомляє **FastAPI**, що функція одразу нижче відповідає за обробку запитів, які надходять до:
* шляху `/`
* використовуючи <dfntitle="HTTP метод GET"><code>get</code> операція</dfn>
* використовуючи <dfntitle="HTTP метод GET">операцію <code>get</code></dfn>
/// note | `@decorator` Інформація
@ -389,7 +389,7 @@ https://example.com/items/foo
Також можна повернути моделі Pydantic (про це ви дізнаєтесь пізніше).
Існує багато інших обʼєктів і моделей, які будуть автоматично конвертовані в JSON (зокрема ORM тощо). Спробуйте використати свої улюблені — велика ймовірність, що вони вже підтримуються.
Існує багато інших обʼєктів і моделей, які будуть автоматично конвертовані в JSON (зокрема ORM тощо). Спробуйте використати свої улюблені - велика ймовірність, що вони вже підтримуються.
Оскільки це помилка Python, ви не `return` її, а `raise` її.
Це також означає, що якщо ви перебуваєте всередині допоміжної функції, яку викликаєте всередині своєї *функції операції шляху*, і там згенеруєте `HTTPException` всередині цієї допоміжної функції, то решта коду в *функції операції шляху* не буде виконана. Запит одразу завершиться, і HTTP-помилка з `HTTPException` буде надіслана клієнту.
Це також означає, що якщо ви перебваєте всередині допоміжної функції, яку викликаєте всередині своєї *функції операції шляху*, і там згенеруєте `HTTPException` всередині цієї допоміжної функції, то решта коду в *функції операції шляху* не буде виконана. Запит одразу завершиться, і HTTP-помилка з `HTTPException` буде надіслана клієнту.
Перевага генерації виключення замість повернення значення стане більш очевидною в розділі про залежності та безпеку.
@ -54,7 +54,7 @@ $ <font color="#4E9A06">fastapi</font> dev
**ДУЖЕ радимо** написати або скопіювати код, відредагувати його та запустити локально.
Використання його у своєму редакторі – це те, що дійсно показує вам переваги FastAPI, бачите, як мало коду вам потрібно написати, всі перевірки типів, автозаповнення тощо.
Використання його у своєму редакторі - це те, що дійсно показує вам переваги FastAPI, бачите, як мало коду вам потрібно написати, всі перевірки типів, автозаповнення тощо.
FastAPI має [офіційне розширення для VS Code](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) (та Cursor), яке надає багато можливостей, включно з переглядачем операцій шляху, пошуком операцій шляху, навігацією CodeLens у тестах (перехід до визначення з тестів), а також розгортанням і журналами FastAPI Cloud — усе безпосередньо з вашого редактора.
FastAPI має [офіційне розширення для VS Code](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) (та Cursor), яке надає багато можливостей, включно з переглядачем операцій шляху, пошуком операцій шляху, навігацією CodeLens у тестах (перехід до визначення з тестів), а також розгортанням і журналами FastAPI Cloud - усе безпосередньо з вашого редактора.
| `summary` | `str` | Короткий підсумок API. <small>Доступно з OpenAPI 3.1.0, FastAPI 0.99.0.</small> |
| `description` | `str` | Короткий опис API. Може використовувати Markdown. |
| `version` | `string` | Версія API. Це версія вашого додатка, а не OpenAPI. Наприклад, `2.5.0`. |
| `version` | `str` | Версія API. Це версія вашого додатка, а не OpenAPI. Наприклад, `2.5.0`. |
| `terms_of_service` | `str` | URL до умов використання API. Якщо вказано, має бути у форматі URL. |
| `contact` | `dict` | Інформація для контакту з опублікованим API. Може містити кілька полів. <details><summary><code>contact</code> поля</summary><table><thead><tr><th>Параметр</th><th>Тип</th><th>Опис</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>Ідентифікаційне ім'я контактної особи або організації.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>URL, що вказує на контактну інформацію. <strong>МАЄ</strong> бути у форматі URL.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>Адреса електронної пошти контактної особи або організації. <strong>МАЄ</strong> бути у форматі адреси електронної пошти.</td></tr></tbody></table></details> |
| `license_info` | `dict` | Інформація про ліцензію для опублікованого API. Може містити кілька полів. <details><summary><code>license_info</code> поля</summary><table><thead><tr><th>Параметр</th><th>Тип</th><th>Опис</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>ОБОВ'ЯЗКОВО</strong> (якщо встановлено <code>license_info</code>). Назва ліцензії для API.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>Ліцензійний вираз за [SPDX](https://spdx.org/licenses/) для API. Поле <code>identifier</code> взаємовиключне з полем <code>url</code>. <small>Доступно з OpenAPI 3.1.0, FastAPI 0.99.0.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>URL до ліцензії, яка використовується для API. <strong>МАЄ</strong> бути у форматі URL.</td></tr></tbody></table></details> |
Ви можете визначити (HTTP) `status_code`, який буде використано у відповіді вашої «операції шляху».
Можна передати безпосередньо цілий код, наприклад `404`.
Ви можете передати безпосередньо код `int`, наприклад `404`.
Якщо ви не пам'ятаєте призначення числових кодів, скористайтеся скороченими константами в `status`:
@ -24,7 +24,7 @@
Ви також можете використати `from starlette import status`.
FastAPI надає той самий `starlette.status` як `fastapi.status` для вашої зручності як розробника. Але він походить безпосередньо зі Starlette.
**FastAPI** надає той самий `starlette.status` як `fastapi.status` для вашої зручності як розробника. Але він походить безпосередньо зі Starlette.
///
@ -40,11 +40,11 @@ FastAPI надає той самий `starlette.status` як `fastapi.status` д
### Мітки з переліками { #tags-with-enums }
У великому застосунку ви можете накопичити багато міток і захочете переконатися, що завжди використовуєте ту саму мітку для пов'язаних «операцій шляху».
У великому застосунку ви можете накопичити **багато міток** і захочете переконатися, що завжди використовуєте **ту саму мітку** для пов'язаних «операцій шляху».
У таких випадках має сенс зберігати мітки в `Enum`.
FastAPI підтримує це так само, як і зі звичайними строками:
**FastAPI** підтримує це так само, як і зі звичайними строками:
@ -56,7 +56,7 @@ FastAPI підтримує це так само, як і зі звичайним
## Опис зі строки документації { #description-from-docstring }
Оскільки описи зазвичай довгі та займають кілька рядків, ви можете оголосити опис «операції шляху» у <dfntitle="багаторядкова строка як перший вираз усередині функції (не прив'язаний до жодної змінної), використовується для документації">строці документації</dfn> функції, і FastAPI прочитає його звідти.
Оскільки описи зазвичай довгі та займають кілька рядків, ви можете оголосити опис «операції шляху» у <dfntitle="багаторядкова строка як перший вираз усередині функції (не прив'язаний до жодної змінної), використовується для документації">строці документації</dfn> функції, і **FastAPI** прочитає його звідти.
Ви можете писати [Markdown](https://en.wikipedia.org/wiki/Markdown) у строці документації, його буде інтерпретовано та показано коректно (з урахуванням відступів у строці документації).
@ -82,7 +82,7 @@ FastAPI підтримує це так само, як і зі звичайним
OpenAPI визначає, що кожна «операція шляху» потребує опису відповіді.
Тому, якщо ви його не надасте, FastAPI автоматично згенерує «Successful response».
Тому, якщо ви його не надасте, **FastAPI** автоматично згенерує «Successful response».
///
@ -98,7 +98,7 @@ OpenAPI визначає, що кожна «операція шляху» пот
Query параметр`q` має тип `str | None`, що означає, що він має тип `str`, але також може бути `None`, і справді, значення за замовчуванням —`None`, тож FastAPI знатиме, що він не є обов'язковим.
Параметр запиту`q` має тип `str | None`, що означає, що він має тип `str`, але також може бути `None`, і справді, значення за замовчуванням -`None`, тож FastAPI знатиме, що він не є обов'язковим.
/// note | Примітка
@ -18,7 +18,7 @@ FastAPI знатиме, що значення `q` не є обов’язков
## Додаткова валідація { #additional-validation }
Ми хочемо, щоб навіть якщо `q` є необов’язковим, коли його передають, його довжина не перевищувала 50 символів.
Ми забезпечимо, що навіть якщо `q` є необов’язковим, коли його передають, **його довжина не перевищувала 50 символів**.
### Імпорт `Query` та `Annotated` { #import-query-and-annotated }
@ -45,7 +45,7 @@ FastAPI додав підтримку `Annotated` (і почав рекомен
Зараз саме час використати його разом із FastAPI. 🚀
Раніше ми мали таку анотацію типу:
Ми мали таку анотацію типу:
```Python
q: str | None = None
@ -57,31 +57,31 @@ q: str | None = None
q: Annotated[str | None] = None
```
Обидві ці версії означають одне й те саме: `q`— це параметр, який може бути `str` або `None`, і за замовчуванням має значення `None`.
Обидві ці версії означають одне й те саме: `q`- це параметр, який може бути `str` або `None`, і за замовчуванням має значення `None`.
А тепер переходимо до цікавого! 🎉
## Додавання `Query` до `Annotated` у параметр `q` { #add-query-to-annotated-in-the-q-parameter }
Тепер, коли у нас є `Annotated`, де ми можемо додавати додаткову інформацію (у цьому випадку — додаткову валідацію), додамо `Query` всередину `Annotated` і встановимо параметр `max_length` у `50`:
Тепер, коли у нас є `Annotated`, де ми можемо додавати додаткову інформацію (у цьому випадку - додаткову валідацію), додамо `Query` всередину `Annotated` і встановимо параметр `max_length` у `50`:
Зверніть увагу, що значення за замовчуванням усе ще `None`, тому параметр залишається необов'язковим.
Але тепер, додавши `Query(max_length=50)` всередину `Annotated`, ми повідомляємо FastAPI, що хочемо додаткову валідацію для цього значення: ми хочемо, щоб воно мало максимум 50 символів. 😎
Але тепер, додавши `Query(max_length=50)` всередину `Annotated`, ми повідомляємо FastAPI, що хочемо **додаткову валідацію** для цього значення: ми хочемо, щоб воно мало максимум 50 символів. 😎
/// tip | Порада
Тут ми використовуємо `Query()`, оскільки це query параметр. Далі ми розглянемо інші варіанти, як-от `Path()`, `Body()`, `Header()` та `Cookie()`, які приймають ті самі аргументи, що й `Query()`.
Тут ми використовуємо `Query()`, оскільки це **параметр запиту**. Далі ми розглянемо інші варіанти, як-от `Path()`, `Body()`, `Header()` та `Cookie()`, які приймають ті самі аргументи, що й `Query()`.
///
Тепер FastAPI:
* Перевірить дані, щоб переконатися, що їхня максимальна довжина — 50 символів
* Покажe чітку помилку клієнту, якщо дані недійсні
* Задокументує параметр в OpenAPI-схемі операції шляху (що відобразиться в автоматично згенерованій документації)
* **Перевірить** дані, щоб переконатися, що їхня максимальна довжина - 50 символів
* Покажe **чітку помилку** клієнту, якщо дані недійсні
* **Задокументує** параметр в *операції шляху* схеми OpenAPI (що відобразиться в **автоматичному інтерфейсі документації**)
## Альтернативний (застарілий) метод: `Query` як значення за замовчуванням { #alternative-old-query-as-the-default-value }
@ -93,7 +93,7 @@ q: Annotated[str | None] = None
///
Раніше ми писали `Query()` як значення за замовчуванням для параметра функції, встановлюючи `max_length` у 50:
Раніше ми писали `Query()` як значення за замовчуванням для параметра функції, встановлюючи параметр `max_length` у 50:
### Переваги використання `Annotated` { #advantages-of-annotated }
Використання `Annotated` є рекомендованим замість задання значення за замовчуванням у параметрах функції, оскільки воно краще з кількох причин. 🤓
**Використання `Annotated` є рекомендованим** замість задання значення за замовчуванням у параметрах функції, оскільки воно **краще** з кількох причин. 🤓
Значення за замовчуванням параметра функції є фактичним значенням за замовчуванням, що є більш інтуїтивним у Python загалом. 😌
**Значення за замовчуванням****параметра функції** є **фактичним значенням за замовчуванням**, що є більш інтуїтивним у Python загалом. 😌
Ви можете викликати ту саму функцію в інших місцях без FastAPI, і вона працюватиме очікувано. Якщо параметр є обов’язковим (без значення за замовчуванням), ваш редактор повідомить про помилку, а Python також видасть помилку, якщо ви виконаєте функцію без передавання цього параметра.
Ви можете **викликати** ту саму функцію в **інших місцях** без FastAPI, і вона **працюватиме очікувано**. Якщо параметр є **обов’язковим** (без значення за замовчуванням), ваш **редактор** повідомить про помилку, а **Python** також видасть помилку, якщо ви виконаєте функцію без передавання обов’язкового параметра.
Якщо ви не використовуєте `Annotated`, а використовуєте (старий) стиль значень за замовчуванням, то при виклику цієї функції без FastAPI в інших місцях потрібно пам’ятати передати їй аргументи, щоб вона працювала коректно, інакше значення будуть відрізнятися від очікуваних (наприклад, ви отримаєте `QueryInfo` або щось подібне замість `str`). І ваш редактор не повідомить про помилку, і Python не скаржитиметься під час запуску цієї функції — лише коли операції всередині завершаться помилкою.
Якщо ви не використовуєте `Annotated`, а використовуєте **(старий) стиль значень за замовчуванням**, то при виклику цієї функції без FastAPI в **інших місцях** потрібно **пам’ятати** передати їй аргументи, щоб вона працювала коректно, інакше значення будуть відрізнятися від очікуваних (наприклад, ви отримаєте `QueryInfo` або щось подібне замість `str`). І ваш редактор не повідомить про помилку, і Python не скаржитиметься під час запуску цієї функції - лише коли операції всередині завершаться помилкою.
Оскільки `Annotated` може містити кілька анотацій метаданих, тепер ви навіть можете використовувати ту саму функцію з іншими інструментами, такими як [Typer](https://typer.tiangolo.com/). 🚀
Ви можете визначити <dfntitle="Регулярний вираз, regex або regexp — це послідовність символів, яка визначає шаблон для пошуку в рядках.">регулярний вираз</dfn>`pattern`, якому має відповідати параметр:
Ви можете визначити <dfntitle="Регулярний вираз, regex або regexp - це послідовність символів, яка визначає шаблон для пошуку в строках.">регулярний вираз</dfn>`pattern`, якому має відповідати параметр:
* `fixedquery`: точно відповідає значенню `fixedquery`.
* `$`: закінчується тут, після `fixedquery` немає жодних символів.
Якщо ви почуваєтеся розгублено щодо **«regular expression»**, не хвилюйтеся. Це складна тема для багатьох людей. Ви все одно можете робити багато речей без використання регулярних виразів.
Якщо ви почуваєтеся розгублено щодо всіх цих ідей **«регулярного виразу»**, не хвилюйтеся. Це складна тема для багатьох людей. Ви все одно можете робити багато речей без потреби в регулярних виразах.
Тепер ви знаєте, що коли вони знадобляться, їх можна застосовувати у **FastAPI**.
Наявність значення за замовчуванням будь-якого типу, включаючи `None`, робить параметр необов’язковим (not required).
Наявність значення за замовчуванням будь-якого типу, включаючи `None`, робить параметр необов’язковим (не обов’язковим).
///
## Обов’язкові параметри { #required-parameters }
Якщо нам не потрібно оголошувати додаткові валідації або метадані, ми можемо зробити query параметр `q` обов’язковим, просто не вказуючи значення за замовчуванням, наприклад:
Якщо нам не потрібно оголошувати додаткові валідації або метадані, ми можемо зробити параметр запиту`q` обов’язковим, просто не вказуючи значення за замовчуванням, наприклад:
## Список query параметрів / кілька значень { #query-parameter-list-multiple-values }
## Список параметрів запиту / кілька значень { #query-parameter-list-multiple-values }
Коли ви явно визначаєте query параметр за допомогою `Query`, ви також можете оголосити, що він має приймати список значень, або, іншими словами, кілька значень.
Коли ви явно визначаєте параметр запиту за допомогою `Query`, ви також можете оголосити, що він має приймати список значень, або, іншими словами, кілька значень.
Наприклад, щоб оголосити query параметр `q`, який може з’являтися в URL кілька разів, можна написати:
Наприклад, щоб оголосити параметр запиту`q`, який може з’являтися в URL кілька разів, можна написати:
Щоб оголосити query параметр з типом `list`, як у наведеному вище прикладі, потрібно явно використовувати `Query`, інакше він буде інтерпретований як тіло запиту.
Щоб оголосити параметр запиту з типом `list`, як у наведеному вище прикладі, потрібно явно використовувати `Query`, інакше він буде інтерпретований як тіло запиту.
## Виняток параметрів з OpenAPI { #exclude-parameters-from-openapi }
Щоб виключити query параметр зі згенерованої схеми OpenAPI (і, таким чином, з автоматичних систем документації), встановіть параметр `include_in_schema` для `Query` в `False`:
Щоб виключити параметр запиту зі згенерованої схеми OpenAPI (і, таким чином, з автоматичних систем документації), встановіть параметр `include_in_schema` для `Query` в `False`:
Можуть бути випадки, коли вам потрібно провести кастомну валідацію, яку не можна реалізувати за допомогою параметрів, показаних вище.
Можуть бути випадки, коли вам потрібно провести **кастомну валідацію**, яку не можна реалізувати за допомогою параметрів, показаних вище.
У таких випадках ви можете використати кастомну функцію-валідатор, яка буде застосована після звичайної валідації (наприклад, після перевірки, що значення є типом `str`).
У таких випадках ви можете використати **кастомну функцію-валідатор**, яка буде застосована після звичайної валідації (наприклад, після перевірки, що значення є типом `str`).
Це можна досягти за допомогою [Pydantic's `AfterValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) всередині `Annotated`.
Це можна досягти за допомогою [Pydantic's `AfterValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) всередині `Annotated`.
/// tip | Порада
@ -377,7 +378,7 @@ Pydantic також має [`BeforeValidator`](https://docs.pydantic.dev/latest/
///
Наприклад, цей кастомний валідатор перевіряє, чи починається ID елемента з `isbn-` для номера книги <abbrtitle="International Standard Book Number - Міжнародний стандартний номер книги">ISBN</abbr> або з `imdb-` для ID URL фільму на <abbrtitle="Internet Movie Database - Інтернетна база даних фільмів: вебсайт з інформацією про фільми">IMDB</abbr>:
Наприклад, цей кастомний валідатор перевіряє, чи починається ID предмета з `isbn-` для номера книги <abbrtitle="International Standard Book Number - Міжнародний стандартний номер книги">ISBN</abbr> або з `imdb-` для ID URL фільму на <abbrtitle="Internet Movie Database - Інтернетна база даних фільмів: вебсайт з інформацією про фільми">IMDB</abbr>:
@ -389,39 +390,39 @@ Pydantic також має [`BeforeValidator`](https://docs.pydantic.dev/latest/
/// tip | Порада
Якщо вам потрібно виконати будь-яку валідацію, яка вимагає взаємодії з будь-яким зовнішнім компонентом, таким як база даних чи інший API, замість цього слід використовувати FastAPI Dependencies — ви дізнаєтесь про них пізніше.
Якщо вам потрібно виконати будь-яку валідацію, яка вимагає взаємодії з будь-яким **зовнішнім компонентом**, таким як база даних чи інший API, замість цього слід використовувати **FastAPI Dependencies** - ви дізнаєтесь про них пізніше.
Ці кастомні валідатори використовуються для речей, які можна перевірити лише з тими самими даними, що надані в запиті.
Ці кастомні валідатори використовуються для речей, які можна перевірити **лише** з **тими самими даними**, що надані в запиті.
///
### Зрозумійте цей код { #understand-that-code }
Головний момент — це використання `AfterValidator` з функцією всередині `Annotated`. Можете пропустити цю частину, якщо хочете. 🤸
Головний момент - це використання **`AfterValidator` з функцією всередині `Annotated`**. Можете пропустити цю частину, якщо хочете. 🤸
---
Але якщо вам цікаво розібратися в цьому конкретному прикладі коду і вам ще не набридло, ось кілька додаткових деталей.
#### Рядок із `value.startswith()` { #string-with-value-startswith }
#### Строка з `value.startswith()` { #string-with-value-startswith }
Звернули увагу? Рядок із `value.startswith()` може приймати кортеж, і тоді він перевірятиме кожне значення в кортежі:
Звернули увагу? Строка з `value.startswith()` може приймати кортеж, і тоді він перевірятиме кожне значення в кортежі:
За допомогою `data.items()` ми отримуємо <dfntitle="Щось, що ми можемо ітерувати циклом for, як-от список, множина тощо.">ітерабельний об'єкт</dfn> із кортежами, що містять ключ і значення для кожного елемента словника.
За допомогою `data.items()` ми отримуємо <dfntitle="Щось, що ми можемо ітерувати циклом for, як-от список, множина тощо.">ітерабельний об'єкт</dfn> із кортежами, що містять ключ і значення для кожного предмета словника.
Ми перетворюємо цей ітерабельний об'єкт у звичайний `list` за допомогою `list(data.items())`.
Потім, використовуючи `random.choice()`, ми можемо отримати випадкове значення зі списку, тобто отримуємо кортеж із `(id, name)`. Це може бути щось на зразок `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
Потім, використовуючи `random.choice()`, ми можемо отримати **випадкове значення** зі списку, тобто отримуємо кортеж із `(id, name)`. Це може бути щось на зразок `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
Далі ми присвоюємо ці два значення кортежу змінним `id` і `name`.
Далі ми **присвоюємо ці два значення** кортежу змінним `id` і `name`.
Тож, якщо користувач не вказав ID елемента, він все одно отримає випадкову рекомендацію.
Тож, якщо користувач не вказав ID предмета, він все одно отримає випадкову рекомендацію.
...ми робимо все це в одному простому рядку. 🤯 Хіба ви не любите Python? 🐍
...ми робимо все це в **одному простому рядку**. 🤯 Хіба ви не любите Python? 🐍
Також зверніть увагу, що **FastAPI** достатньо розумний, щоб визначити, що параметр шляху `item_id` є параметром шляху, а `q`— ні, отже, це параметр query.
Також зверніть увагу, що **FastAPI** достатньо розумний, щоб визначити, що параметр шляху `item_id` є параметром шляху, а `q`- ні, отже, це параметр запиту.
///
## Перетворення типу параметра query { #query-parameter-type-conversion }
## Перетворення типу параметра запиту { #query-parameter-type-conversion }
Ви також можете оголошувати параметри типу `bool`, і вони будуть автоматично конвертовані:
або будь-який інший варіант написання (великі літери, перша літера велика тощо), ваша функція побачить параметр `short` зі значенням `True` типу `bool`. В іншому випадку —`False`.
або будь-який інший варіант написання (великі літери, перша літера велика тощо), ваша функція побачить параметр `short` зі значенням `True` типу `bool`. В іншому випадку -`False`.
## Кілька path і query параметрів { #multiple-path-and-query-parameters }
## Кілька параметрів шляху та запиту { #multiple-path-and-query-parameters }
Ви можете одночасно оголошувати кілька параметрів шляху та параметрів query, **FastAPI** знає, який з них який.
Ви можете одночасно оголошувати кілька параметрів шляху та параметрів запиту, **FastAPI** знає, який з них який.
І вам не потрібно оголошувати їх у якомусь конкретному порядку.
Коли ви оголошуєте значення за замовчуванням для не-path-параметрів (поки що ми бачили лише параметри query), тоді вони не є обов’язковими.
Коли ви оголошуєте значення за замовчуванням для параметрів, що не є параметрами шляху (поки що ми бачили лише параметри запиту), тоді вони не є обов’язковими.
Якщо ви не хочете задавати конкретне значення, а просто зробити параметр необов’язковим, задайте `None` як значення за замовчуванням.
Але якщо ви хочете зробити параметр query обов’язковим, просто не вказуйте для нього значення за замовчуванням:
Але якщо ви хочете зробити параметр запиту обов’язковим, просто не вказуйте для нього значення за замовчуванням:
Це необхідно, оскільки завантажені файли передаються у вигляді «form data».
Це необхідно, оскільки завантажені файли передаються як «дані форми».
///
@ -30,7 +30,7 @@ $ pip install python-multipart
/// note | Примітка
`File`— це клас, який безпосередньо успадковує `Form`.
`File`- це клас, який безпосередньо успадковує `Form`.
Але пам’ятайте, що коли ви імпортуєте `Query`, `Path`, `File` та інші з `fastapi`, це насправді функції, які повертають спеціальні класи.
@ -42,7 +42,7 @@ $ pip install python-multipart
///
Файли будуть завантажені у вигляді «form data».
Файли будуть завантажені як «дані форми».
Якщо ви оголосите тип параметра *функції операції шляху* як `bytes`, **FastAPI** прочитає файл за вас, і ви отримаєте його вміст у вигляді `bytes`.
@ -70,8 +70,8 @@ $ pip install python-multipart
`UploadFile` має такі атрибути:
* `filename`: Рядок`str` з оригінальною назвою файлу, який був завантажений (наприклад, `myimage.jpg`).
* `content_type`: Рядок`str` з типом вмісту (MIME type / media type) (наприклад, `image/jpeg`).
* `filename`: Строка`str` з оригінальною назвою файлу, який був завантажений (наприклад, `myimage.jpg`).
* `content_type`: Строка`str` з типом вмісту (MIME type / media type) (наприклад, `image/jpeg`).
* `file`: [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) ([file-like](https://docs.python.org/3/glossary.html#term-file-like-object) об'єкт). Це фактичний файловий об'єкт Python, який ви можете передавати безпосередньо іншим функціям або бібліотекам, що очікують «file-like» об'єкт.
`UploadFile` має такі асинхронні `async` методи. Вони всі викликають відповідні методи файлу під капотом (використовуючи внутрішній `SpooledTemporaryFile`).
@ -109,7 +109,7 @@ contents = myfile.file.read()
///
## Що таке «Form Data» { #what-is-form-data }
## Що таке «дані форми» { #what-is-form-data }
Спосіб, у який HTML-форми (`<form></form>`) надсилають дані на сервер, зазвичай використовує «спеціальне» кодування для цих даних, відмінне від JSON.
@ -121,7 +121,7 @@ contents = myfile.file.read()
Але якщо форма містить файли, вона кодується як `multipart/form-data`. Якщо ви використовуєте `File`, **FastAPI** знатиме, що потрібно отримати файли з правильної частини тіла.
Якщо ви хочете дізнатися більше про ці типи кодування та формові поля, ознайомтеся з [<abbr title="Mozilla Developer Network - Мережа Розробників Mozilla">MDN</abbr> web docs для `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).
Якщо ви хочете дізнатися більше про ці типи кодування та поля форми, ознайомтеся з [<abbr title="Mozilla Developer Network - Мережа Розробників Mozilla">MDN</abbr> web docs для `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).
///
@ -149,7 +149,7 @@ contents = myfile.file.read()
Можна завантажувати кілька файлів одночасно.
Вони будуть пов’язані з одним і тим самим «form field», який передається у вигляді «form data».
Вони будуть пов’язані з одним і тим самим «полем форми», яке передається як «дані форми».
Щоб це реалізувати, потрібно оголосити список `bytes` або `UploadFile`:
@ -173,4 +173,4 @@ contents = myfile.file.read()
## Підсумок { #recap }
Використовуйте `File`, `bytes` та `UploadFile`, щоб оголошувати файли для завантаження в запиті, надіслані у вигляді form data.
Використовуйте `File`, `bytes` та `UploadFile`, щоб оголошувати файли для завантаження в запиті, надіслані як дані форми.
Так само, як ви можете вказати модель відповіді, ви також можете оголосити HTTP код статусу, що використовується для відповіді, за допомогою параметра `status_code` в будь-якій з *операцій шляху*:
А **frontend** - на іншому домені або в іншому шляху того ж домену (або у мобільному застосунку).
І ви хочете, щоб frontend міг автентифікуватися в backend, використовуючи ім'я користувача та пароль.
І ви хочете, щоб frontend міг автентифікуватися в backend, використовуючи **ім'я користувача** та **пароль**.
Ми можемо використати **OAuth2**, щоб збудувати це з **FastAPI**.
@ -40,7 +40,7 @@ $ pip install python-multipart
///
Запустіть приклад:
Запустіть приклад за допомогою:
<divclass="termy">
@ -60,7 +60,7 @@ $ fastapi dev
<imgsrc="/img/tutorial/security/image01.png">
/// tip | Кнопка Authorize!
/// tip | Кнопка «Authorize»!
У вас уже є нова блискуча кнопка «Authorize».
@ -78,7 +78,7 @@ $ fastapi dev
///
Звісно, це не frontend для кінцевих користувачів, але це чудовий інструмент для інтерактивної документації всього вашого API.
Звісно, це не frontend для кінцевих користувачів, але це чудовий автоматичний інструмент для інтерактивного документування всього вашого API.
Ним може користуватися команда frontend (якою можете бути і ви самі).
@ -86,11 +86,11 @@ $ fastapi dev
І ним також можете користуватися ви самі, щоб налагоджувати, перевіряти та тестувати той самий застосунок.
## Потік паролю { #the-password-flow }
## Потік `password` { #the-password-flow }
Тепер повернімося трохи назад і розберімося, що це все таке.
`password` «flow» - це один зі способів («flows»), визначених в OAuth2, для обробки безпеки та автентифікації.
`password` «потік» - це один зі способів («потоків»), визначених в OAuth2, для обробки безпеки та автентифікації.
OAuth2 був спроєктований так, щоб backend або API могли бути незалежними від сервера, який автентифікує користувача.
@ -100,7 +100,7 @@ OAuth2 був спроєктований так, щоб backend або API мо
- Користувач вводить `username` і `password` у frontend і натискає `Enter`.
- Frontend (у браузері користувача) надсилає ці `username` і `password` на специфічну URL-адресу нашого API (оголошену як `tokenUrl="token"`).
- API перевіряє ці `username` і `password` та повертає «токен» (ми ще нічого з цього не реалізували).
- API перевіряє ці `username` і `password` та відповідає «токеном» (ми ще нічого з цього не реалізували).
- «Токен» - це просто строка з деяким вмістом, який ми можемо пізніше використати, щоб перевірити цього користувача.
- Зазвичай токен налаштований на завершення строку дії через певний час.
- Тож користувачу доведеться знову увійти пізніше.
@ -116,11 +116,11 @@ OAuth2 був спроєктований так, щоб backend або API мо
**FastAPI** надає кілька інструментів на різних рівнях абстракції, щоб реалізувати ці функції безпеки.
У цьому прикладі ми використаємо **OAuth2** з потоком **Password**, використовуючи токен **Bearer**. Це робиться за допомогою класу `OAuth2PasswordBearer`.
У цьому прикладі ми використаємо **OAuth2** з потоком **Password**, використовуючи **токен носія**. Це робиться за допомогою класу `OAuth2PasswordBearer`.
/// note | Примітка
«Bearer»-токен - не єдиний варіант.
«Токен носія» - не єдиний варіант.
Але це найкращий для нашого сценарію.
@ -138,7 +138,7 @@ OAuth2 був спроєктований так, щоб backend або API мо
Тут `tokenUrl="token"` відноситься до відносної URL-адреси `token`, яку ми ще не створили. Оскільки це відносна URL-адреса, вона еквівалентна `./token`.
Тому, якщо ваш API розміщений на `https://example.com/`, це буде `https://example.com/token`. А якщо на `https://example.com/api/v1/`, тоді це буде `https://example.com/api/v1/token`.
Оскільки ми використовуємо відносну URL-адресу, якщо ваш API розміщений на `https://example.com/`, це буде `https://example.com/token`. А якщо ваш API розміщений на `https://example.com/api/v1/`, тоді це буде `https://example.com/api/v1/token`.
Використання відносної URL-адреси важливе, щоб ваша програма продовжувала працювати навіть у просунутому сценарії, як-от [За представником](../../advanced/behind-a-proxy.md).
Вона шукатиме в запиті заголовок `Authorization`, перевірить, чи його значення - це `Bearer ` плюс деякий токен, і поверне токен як `str`.
Якщо заголовка `Authorization` немає або значення не містить токена `Bearer `, вона одразу відповість помилкою зі статус-кодом 401 (`UNAUTHORIZED`).
Якщо заголовка `Authorization` немає або значення не містить токена `Bearer `, вона одразу відповість помилкою з кодом статусу 401 (`UNAUTHORIZED`).
Вам навіть не потрібно перевіряти, чи існує токен, щоб повернути помилку. Ви можете бути певні: якщо ваша функція виконується, у параметрі токена буде `str`.
## Створити залежність `get_current_user` { #create-a-get-current-user-dependency }
@ -24,19 +24,19 @@
`get_current_user` матиме залежність із тим самим `oauth2_scheme`, який ми створили раніше.
Так само, як ми робили раніше безпосередньо в операції шляху, наша нова залежність `get_current_user` отримає `token` як `str` від підзалежності `oauth2_scheme`:
Так само, як ми робили раніше безпосередньо в *операції шляху*, наша нова залежність `get_current_user` отримає `token` як `str` від підзалежності `oauth2_scheme`:
Тепер ви можете отримувати поточного користувача безпосередньо у функціях операцій шляху та працювати з механізмами безпеки на рівні **впровадження залежностей**, використовуючи `Depends`.
Тепер ви можете отримувати поточного користувача безпосередньо у *функціях операцій шляху* та працювати з механізмами безпеки на рівні **впровадження залежностей**, використовуючи `Depends`.
І ви можете використовувати будь-яку модель або дані для вимог безпеки (у цьому випадку Pydantic-модель `User`).
Але ви не обмежені використанням якоїсь конкретної модели даних, класу чи типу.
Але ви не обмежені використанням якоїсь конкретної моделі даних, класу чи типу.
Хочете мати id та email і не мати жодного username у вашій моделі? Без проблем. Ви можете використовувати ті самі інструменти.
Хочете мати `id` та `email` і не мати жодного `username` у вашій моделі? Без проблем. Ви можете використовувати ті самі інструменти.
Хочете мати просто `str`? Або лише `dict`? Або безпосередньо екземпляр класу моделі бази даних? Усе працює так само.
@ -78,7 +78,7 @@
## Розмір коду { #code-size }
Цей приклад може здаватися багатослівним. Майте на увазі, що ми змішуємо безпеку, моделі даних, утилітні функції та операції шляху в одному файлі.
Цей приклад може здаватися багатослівним. Майте на увазі, що ми змішуємо безпеку, моделі даних, утилітні функції та *операції шляху* в одному файлі.
Але ось ключовий момент.
@ -86,20 +86,20 @@
І ви можете зробити це настільки складним, наскільки потрібно. І все одно мати це написаним лише один раз, в одному місці. З усією гнучкістю.
Зате ви можете мати тисячі кінцевих точок (операцій шляху), що використовують одну й ту саму систему безпеки.
Зате ви можете мати тисячі кінцевих точок (*операцій шляху*), що використовують одну й ту саму систему безпеки.
І всі вони (або будь-яка їхня частина, яку ви захочете) можуть скористатися повторним використанням цих залежностей або будь-яких інших, які ви створите.
І всі ці тисячі операцій шляху можуть бути всього у 3 рядки:
І всі ці тисячі *операцій шляху* можуть бути всього у 3 рядки:
# SQL (реляційні) бази даних { #sql-relational-databases }
**FastAPI** не вимагає від вас використовувати SQL (реляційну) базу даних. Але ви можете скористатися будь-якою базою даних, яку забажаєте.
**FastAPI** не вимагає від вас використовувати SQL (реляційну) базу даних. Але ви можете скористатися **будь-якою базою даних**, яку забажаєте.
Тут ми розглянемо приклад з [SQLModel](https://sqlmodel.tiangolo.com/).
@ -8,7 +8,7 @@
/// tip | Порада
Ви можете використовувати будь-яку іншу бібліотеку для SQL або NoSQL баз (інколи їх називають <abbrtitle="Object Relational Mapper - Об'єктно-реляційний відображувач: складний термін для бібліотеки, де деякі класи представляють таблиці SQL, а екземпляри представляють рядки в цих таблицях">"ORMs"</abbr>), FastAPI нічого не нав’язує. 😎
Ви можете використовувати будь-яку іншу бібліотеку для SQL або NoSQL баз (інколи їх називають <abbrtitle="Object Relational Mapper - Об'єктно-реляційний відображувач: складний термін для бібліотеки, де деякі класи представляють таблиці SQL, а екземпляри представляють рядки в цих таблицях">«ORMs»</abbr>), FastAPI нічого не нав’язує. 😎
///
@ -65,7 +65,7 @@ $ pip install sqlmodel
* `Field(primary_key=True)` каже SQLModel, що `id` - це **первинний ключ** у SQL базі даних (більше про первинні ключі в SQL див. у документації SQLModel).
Примітка: Ми використовуємо `int | None` для поля первинного ключа, щоб у Python-коді можна було створити об’єкт без `id` (`id=None`), припускаючи, що база даних згенерує його під час збереження. SQLModel розуміє, що `id` надасть база даних, і визначає стовпець як ненульовий `INTEGER` у схемі бази даних. Докладніше див. [документацію SQLModel про первинні ключі](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id).
**Примітка:** Ми використовуємо `int | None` для поля первинного ключа, щоб у Python-коді можна було створити об’єкт без `id` (`id=None`), припускаючи, що база даних згенерує його під час збереження. SQLModel розуміє, що `id` надасть база даних, і визначає стовпець як ненульовий `INTEGER` у схемі бази даних. Докладніше див. [документацію SQLModel про первинні ключі](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id).
* `Field(index=True)` каже SQLModel створити **SQL-індекс** для цього стовпця, що дозволить швидше виконувати пошук у базі даних під час читання даних, відфільтрованих за цим стовпцем.
«Під'єднання» означає додавання повноцінного «незалежного» застосунку за певним шляхом, який потім обробляє всі під шляхи.
«Монтування» означає додавання повноцінного «незалежного» застосунку за певним шляхом, який потім відповідає за обробку всіх підшляхів.
Це відрізняється від використання `APIRouter`, оскільки під'єднаний застосунок є повністю незалежним. OpenAPI та документація вашого основного застосунку не будуть знати нічого про ваш під'єднаний застосунок тощо.
Це відрізняється від використання `APIRouter`, оскільки змонтований застосунок є повністю незалежним. OpenAPI та документація вашого основного застосунку не включатимуть нічого зі змонтованого застосунку тощо.
Ви можете дізнатися більше про це в [Посібнику для просунутих користувачів](../advanced/index.md).
Ви можете дізнатися більше про це в [Просунутому посібнику користувача](../advanced/index.md).
## Деталі { #details }
Перше `"/static"`вказує на під шлях, за яким буде «під'єднано» цей новий «підзастосунок». Тому будь-який шлях, який починається з `"/static"`, буде оброблятися ним.
Перше `"/static"`стосується підшляху, на якому буде «змонтовано» цей «підзастосунок». Тому будь-який шлях, який починається з `"/static"`, буде оброблятися ним.
`directory="static"` визначає назву каталогу, що містить ваші статичні файли.
`name="static"`це ім'я, яке можна використовувати всередині **FastAPI**.
`name="static"`надає йому ім'я, яке можна використовувати всередині **FastAPI**.
Усі ці параметри можуть бути іншими за "`static`", налаштуйте їх відповідно до потреб і особливостей вашого застосунку.
## Додаткова інформація { #more-info }
Детальніше про налаштування та можливості можна дізнатися в [документації Starlette про статичні файли](https://www.starlette.dev/staticfiles/).
Для отримання додаткової інформації та параметрів перевірте [документацію Starlette про Static Files](https://www.starlette.dev/staticfiles/).
Якщо ви хочете викликати `async`-функції у ваших тестах, окрім відправлення запитів до вашого застосунку FastAPI (наприклад, асинхронні функції роботи з базою даних), перегляньте [Async Tests](../advanced/async-tests.md) у розширеному керівництві.
Якщо ви хочете викликати `async`-функції у ваших тестах, окрім відправлення запитів до вашого застосунку FastAPI (наприклад, асинхронні функції роботи з базою даних), перегляньте [Асинхронні тести](../advanced/async-tests.md) у просунутому навчальному посібнику.
Коли вам потрібно передати клієнту інформацію в запиті, але ви не знаєте, як це зробити, ви можете пошукати (Google), як це зробити в `httpx`, або навіть як це зробити з `requests`, оскільки дизайн HTTPX базується на дизайні Requests.
Коли вам потрібно, щоб клієнт передав інформацію в запиті, але ви не знаєте, як це зробити, ви можете пошукати (Google), як це зробити в `httpx`, або навіть як це зробити з `requests`, оскільки дизайн HTTPX базується на дизайні Requests.
Далі ви просто повторюєте ці ж дії у ваших тестах.
Наприклад:
* Щоб передати *path* або *query* параметр, додайте його безпосередньо до URL.
* Щоб передати параметр *шляху* або *запиту*, додайте його безпосередньо до URL.
* Щоб передати тіло JSON, передайте Python-об'єкт (наприклад, `dict`) у параметр `json`.
* Якщо потрібно надіслати *Form Data* замість JSON, використовуйте параметр `data`.
* Щоб передати заголовки *headers*, використовуйте `dict` у параметрі `headers`.
* Для *cookies* використовуйте `dict` у параметрі `cookies`.
* Якщо потрібно надіслати *дані форми* замість JSON, використовуйте параметр `data`.
* Щоб передати *заголовки*, використовуйте `dict` у параметрі `headers`.
* Для *кукі* використовуйте `dict` у параметрі `cookies`.
Докладніше про передачу даних у бекенд (за допомогою `httpx` або `TestClient`) можна знайти в [документації HTTPX](https://www.python-httpx.org).
@ -148,7 +148,7 @@ $ pip install httpx
Зверніть увагу, що `TestClient` отримує дані, які можна конвертувати в JSON, а не Pydantic-моделі.
Якщо у вас є Pydantic-модель у тесті, і ви хочете передати її дані в застосунок під час тестування, ви можете використати `jsonable_encoder`, описаний у розділі [JSON Compatible Encoder](encoder.md).
Якщо у вас є Pydantic-модель у тесті, і ви хочете передати її дані в застосунок під час тестування, ви можете використати `jsonable_encoder`, описаний у розділі [JSON-сумісний кодувальник](encoder.md).
Коли ви працюєте над проєктами Python, вам, імовірно, слід використовувати віртуальне середовище (або схожий механізм), щоб ізолювати пакети, які ви встановлюєте для кожного проєкту.
Коли ви працюєте над проєктами Python, вам, імовірно, слід використовувати **віртуальне середовище** (або схожий механізм), щоб ізолювати пакети, які ви встановлюєте для кожного проєкту.
/// note | Примітка
@ -10,19 +10,19 @@
/// tip | Порада
Віртуальне середовище відрізняється від змінної оточення.
**Віртуальне середовище** відрізняється від **змінної оточення**.
Змінна оточення - це змінна в системі, яку можуть використовувати програми.
**Змінна оточення** - це змінна в системі, яку можуть використовувати програми.
Віртуальне середовище - це каталог із файлами в ньому.
**Віртуальне середовище** - це каталог із файлами в ньому.
///
/// note | Примітка
На цій сторінці ви дізнаєтеся, як використовувати віртуальні середовища і як вони працюють.
На цій сторінці ви дізнаєтеся, як використовувати **віртуальні середовища** і як вони працюють.
Якщо ви готові прийняти інструмент, що керує всім за вас (включно з установленням Python), спробуйте [uv](https://github.com/astral-sh/uv).
Якщо ви готові прийняти **інструмент, що керує всім** за вас (включно з установленням Python), спробуйте [uv](https://github.com/astral-sh/uv).
Коли ви починаєте працювати над проєктом Python уперше, створіть віртуальне середовище у вашому проєкті**<dfntitle="є інші варіанти, це проста настанова">у вашому проєкті</dfn>**.
Коли ви починаєте працювати над проєктом Python **уперше**, створіть віртуальне середовище **<dfntitle="є інші варіанти, це проста настанова">у вашому проєкті</dfn>**.
/// tip | Порада
Це потрібно робити лише один раз на проєкт, не щоразу, коли ви працюєте.
Це потрібно робити лише **один раз на проєкт**, не щоразу, коли ви працюєте.
///
@ -120,7 +120,7 @@ $ uv venv
/// tip | Порада
Робіть це щоразу, коли ви починаєте нову сесію термінала для роботи над проєктом.
Робіть це **щоразу**, коли ви починаєте **нову сесію термінала** для роботи над проєктом.
Кожного разу, коли ви встановлюєте новий пакет у це середовище, активуйте середовище знову.
Кожного разу, коли ви встановлюєте **новий пакет** у це середовище, **активуйте** середовище знову.
Це гарантує, що якщо ви використовуєте програму термінала (<abbrtitle="command line interface - інтерфейс командного рядка">CLI</abbr>), встановлену цим пакетом, ви використовуєте саме ту з вашого віртуального середовища, а не будь-яку іншу, яка може бути встановлена глобально, імовірно з іншою версією, ніж вам потрібно.
Це гарантує, що якщо ви використовуєте **програму термінала (<abbr title="command line interface - інтерфейс командного рядка">CLI</abbr>)**, встановлену цим пакетом, ви використовуєте саме ту з вашого віртуального середовища, а не будь-яку іншу, яка може бути встановлена глобально, імовірно з іншою версією, ніж вам потрібно.
Це необов'язково, але це гарний спосіб перевірити, що все працює як очікується і ви використовуєте саме те віртуальне середовище, яке планували.
Це **необов'язково**, але це гарний спосіб **перевірити**, що все працює як очікується і ви використовуєте саме те віртуальне середовище, яке планували.
Коли ви завершили роботу над проєктом, ви можете деактивувати віртуальне середовище.
Коли ви завершили роботу над проєктом, ви можете **деактивувати** віртуальне середовище.
<divclass="termy">
@ -443,6 +443,8 @@ $ deactivate
Тепер ви готові почати працювати над вашим проєктом.
/// tip | Порада
Хочете зрозуміти, що це все було вище?
@ -455,33 +457,33 @@ $ deactivate
Щоб працювати з FastAPI, вам потрібно встановити [Python](https://www.python.org/).
Після цього вам потрібно буде встановити FastAPI та інші пакети, які ви хочете використовувати.
Після цього вам потрібно буде **встановити** FastAPI та інші **пакети**, які ви хочете використовувати.
Для встановлення пакетів зазвичай використовують команду `pip`, що постачається з Python (або схожі альтернативи).
Однак, якщо ви просто користуватиметеся `pip` напряму, пакети встановлюватимуться у ваше глобальне середовище Python (глобальну інсталяцію Python).
Однак, якщо ви просто користуватиметеся `pip` напряму, пакети встановлюватимуться у ваше **глобальне середовище Python** (глобальну інсталяцію Python).
### Проблема { #the-problem }
То в чому ж проблема встановлення пакетів у глобальне середовище Python?
З часом ви, вірогідно, писатимете багато різних програм, які залежать від різних пакетів. І деякі з цих ваших проєктів залежатимуть від різних версій одного й того ж пакета. 😱
З часом ви, вірогідно, писатимете багато різних програм, які залежать від **різних пакетів**. І деякі з цих ваших проєктів залежатимуть від **різних версій** одного й того ж пакета. 😱
Наприклад, ви можете створити проєкт із назвою `philosophers-stone`, ця програма залежить від іншого пакета з назвою `harry`, використовуючи версію `1`. Тож вам потрібно встановити `harry`.
Наприклад, ви можете створити проєкт із назвою `philosophers-stone`, ця програма залежить від іншого пакета з назвою **`harry`, використовуючи версію `1`**. Тож вам потрібно встановити `harry`.
Потім, трохи згодом, ви створюєте інший проєкт із назвою `prisoner-of-azkaban`, і цей проєкт також залежить від `harry`, але йому потрібна версія `harry``3`.
Потім, трохи згодом, ви створюєте інший проєкт із назвою `prisoner-of-azkaban`, і цей проєкт також залежить від `harry`, але йому потрібна **версія `harry` `3`**.
Але тепер проблема в тому, що якщо ви встановлюєте пакети глобально (у глобальне середовище), а не у локальне віртуальне середовище, вам доведеться вибирати, яку версію `harry` встановити.
Але тепер проблема в тому, що якщо ви встановлюєте пакети глобально (у глобальне середовище), а не у локальне **віртуальне середовище**, вам доведеться вибирати, яку версію `harry` встановити.
Якщо ви хочете запустити `philosophers-stone`, вам спочатку потрібно встановити `harry` версії `1`, наприклад, так:
@ -517,7 +519,7 @@ $ pip install "harry==3"
У підсумку у вас буде встановлено `harry` версії `3` у глобальному середовищі Python.
А якщо ви знову спробуєте запустити `philosophers-stone`, є шанс, що він не працюватиме, тому що йому потрібен `harry` версії `1`.
А якщо ви знову спробуєте запустити `philosophers-stone`, є шанс, що він **не працюватиме**, тому що йому потрібен `harry` версії `1`.
```mermaid
flowchart LR
@ -536,13 +538,13 @@ flowchart LR
/// tip | Порада
У пакетах Python дуже поширена практика намагатися якнайкраще уникати несумісних змін у нових версіях, але краще підстрахуватися та встановлювати новіші версії свідомо і тоді, коли ви можете запустити тести, щоб перевірити, що все працює коректно.
У пакетах Python дуже поширена практика намагатися якнайкраще **уникати несумісних змін** у **нових версіях**, але краще підстрахуватися та встановлювати новіші версії свідомо і тоді, коли ви можете запустити тести, щоб перевірити, що все працює коректно.
///
Тепер уявіть те саме з багатьма іншими пакетами, від яких залежать усі ваші проєкти. Це дуже складно керувати. І ви, імовірно, запускатимете деякі проєкти з деякими несумісними версіями пакетів і не розумітимете, чому щось не працює.
Тепер уявіть те саме з **багатьма** іншими **пакетами**, від яких залежать усі ваші **проєкти**. Це дуже складно керувати. І ви, імовірно, запускатимете деякі проєкти з деякими **несумісними версіями** пакетів і не розумітимете, чому щось не працює.
Також, залежно від вашої операційної системи (напр., Linux, Windows, macOS), у ній може бути вже встановлений Python. І в такому разі, імовірно, уже будуть попередньо встановлені деякі пакети з певними версіями, потрібними вашій системі. Якщо ви встановлюєте пакети в глобальне середовище Python, ви можете зламати деякі програми, що постачаються з вашою операційною системою.
Також, залежно від вашої операційної системи (напр., Linux, Windows, macOS), у ній може бути вже встановлений Python. І в такому разі, імовірно, уже будуть попередньо встановлені деякі пакети з певними версіями, **потрібними вашій системі**. Якщо ви встановлюєте пакети в глобальне середовище Python, ви можете **зламати** деякі програми, що постачаються з вашою операційною системою.
## Де встановлюються пакети { #where-are-packages-installed }
Це завантажить стиснений файл з кодом FastAPI, зазвичай із [PyPI](https://pypi.org/project/fastapi/).
Також будуть завантажені файли для інших пакетів, від яких залежить FastAPI.
Також будуть **завантажені** файли для інших пакетів, від яких залежить FastAPI.
Потім усе це буде розпаковано та покладено в каталог на вашому комп'ютері.
Потім усе це буде **розпаковано** та покладено в каталог на вашому комп'ютері.
Типово ці завантажені та розпаковані файли будуть покладені в каталог, що постачається з вашою інсталяцією Python, це глобальне середовище.
Типово ці завантажені та розпаковані файли будуть покладені в каталог, що постачається з вашою інсталяцією Python, це **глобальне середовище**.
## Що таке віртуальні середовища { #what-are-virtual-environments }
Рішенням проблеми з наявністю всіх пакетів у глобальному середовищі є використання віртуального середовища для кожного проєкту, над яким ви працюєте.
Рішенням проблеми з наявністю всіх пакетів у глобальному середовищі є використання **віртуального середовища для кожного проєкту**, над яким ви працюєте.
Віртуальне середовище - це каталог, дуже схожий на глобальний, у якому ви можете встановлювати пакети для конкретного проєкту.
Віртуальне середовище - це **каталог**, дуже схожий на глобальний, у якому ви можете встановлювати пакети для конкретного проєкту.
Таким чином кожен проєкт матиме власне віртуальне середовище (каталог `.venv`) із власними пакетами.
Важлива деталь: шлях до віртуального середовища буде додано на початок змінної `PATH`. Система знайде його раніше за будь-який інший доступний Python. Таким чином, коли ви запускаєте `python`, використовується саме Python із віртуального середовища, а не будь-який інший `python` (наприклад, з глобального середовища).
Важлива деталь: шлях до віртуального середовища буде додано на **початок** змінної `PATH`. Система знайде його **раніше** за будь-який інший доступний Python. Таким чином, коли ви запускаєте `python`, використовується саме Python **із віртуального середовища**, а не будь-який інший `python` (наприклад, з глобального середовища).
Активація віртуального середовища також змінює ще кілька речей, але це одна з найважливіших.
Це означає, що програма `python`, яка буде використана, знаходиться у віртуальному середовищі.
Це означає, що програма `python`, яка буде використана, знаходиться **у віртуальному середовищі**.
На Linux і macOS використовують `which`, а в Windows PowerShell - `Get-Command`.
Принцип роботи цієї команди в тому, що вона перевіряє змінну оточення `PATH`, проходячи по кожному шляху по порядку, шукаючи програму з назвою `python`. Щойно вона її знайде, вона покаже вам шлях до цієї програми.
Принцип роботи цієї команди в тому, що вона перевіряє змінну оточення `PATH`, проходячи по **кожному шляху по порядку**, шукаючи програму з назвою `python`. Щойно вона її знайде, вона **покаже вам шлях** до цієї програми.
Найважливіше, що коли ви викликаєте `python`, це рівно той «`python`», який буде виконаний.
Наприклад, ви працюєте над проєктом `philosophers-stone`, активували його віртуальне середовище, встановили пакети та працюєте з цим середовищем.
Наприклад, ви працюєте над проєктом `philosophers-stone`, **активували його віртуальне середовище**, встановили пакети та працюєте з цим середовищем.
А потім ви хочете працювати над іншим проєктом `prisoner-of-azkaban`.
А потім ви хочете працювати над **іншим проєктом**`prisoner-of-azkaban`.
Ви переходите до цього проєкту:
@ -840,23 +842,23 @@ I solemnly swear 🐺
## Альтернативи { #alternatives }
Це простий посібник, щоб ви швидко стартували та зрозуміли, як усе працює «під капотом».
Це простий посібник, щоб ви швидко стартували та зрозуміли, як усе працює **«під капотом»**.
Існує багато альтернатив керування віртуальними середовищами, залежностями пакетів (вимогами), проєктами.
Існує багато **альтернатив** керування віртуальними середовищами, залежностями пакетів (вимогами), проєктами.
Коли будете готові й захочете використовувати інструмент для керування всім проєктом, залежностями пакетів, віртуальними середовищами тощо, я раджу спробувати [uv](https://github.com/astral-sh/uv).
Коли будете готові й захочете використовувати інструмент для **керування всім проєктом**, залежностями пакетів, віртуальними середовищами тощо, я раджу спробувати [uv](https://github.com/astral-sh/uv).
`uv` уміє багато чого, зокрема:
* Встановлювати Python для вас, включно з різними версіями
* Керувати віртуальним середовищем ваших проєктів
* Встановлювати пакети
* Керувати залежностями пакетів і версіями у вашому проєкті
* Гарантувати, що у вас є точний набір пакетів і версій для встановлення, включно з їхніми залежностями, щоб ви були певні, що зможете запустити ваш проєкт у продакшені точно так само, як і на вашому комп'ютері під час розробки - це називається блокуванням
* **Встановлювати Python** для вас, включно з різними версіями
* Керувати **залежностями і версіями** пакетів у вашому проєкті
* Гарантувати, що у вас є **точний** набір пакетів і версій для встановлення, включно з їхніми залежностями, щоб ви були певні, що зможете запустити ваш проєкт у продакшені точно так само, як і на вашому комп'ютері під час розробки - це називається **блокуванням**
* І багато іншого
## Висновок { #conclusion }
Якщо ви все це прочитали й зрозуміли, тепер ви знаєте значно більше про віртуальні середовища, ніж багато розробників. 🤓
Якщо ви все це прочитали й зрозуміли, тепер **ви знаєте значно більше** про віртуальні середовища, ніж багато розробників. 🤓
Знання цих деталей, найімовірніше, стане в пригоді в майбутньому, коли ви налагоджуватимете щось, що виглядає складним, але ви знатимете, як усе працює «під капотом». 😎
Знання цих деталей, найімовірніше, стане в пригоді в майбутньому, коли ви налагоджуватимете щось, що виглядає складним, але ви знатимете, **як усе працює «під капотом»**. 😎