@ -243,5 +243,5 @@ new_dict = {**old_dict, "new key": "new value"}
Щоб побачити, що саме можна включати у відповіді, ознайомтеся з цими розділами специфікації OpenAPI:
Щоб побачити, що саме можна включати у відповіді, ознайомтеся з цими розділами специфікації OpenAPI:
- <ahref="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object"class="external-link"target="_blank">Об'єкт відповідей OpenAPI</a>, він включає `Response Object`.
- [Об'єкт відповідей OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object), він включає `Response Object`.
- <ahref="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object"class="external-link"target="_blank">Об'єкт відповіді OpenAPI</a>, ви можете включити будь-що з цього безпосередньо в кожну відповідь у параметрі `responses`. Зокрема `description`, `headers`, `content` (усередині нього ви оголошуєте різні типи медіа та Схеми JSON) і `links`.
- [Об'єкт відповіді OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object), ви можете включити будь-що з цього безпосередньо в кожну відповідь у параметрі `responses`. Зокрема `description`, `headers`, `content` (усередині нього ви оголошуєте різні типи медіа та Схеми JSON) і `links`.
Якщо ви повертаєте додаткові коди статусу та відповіді безпосередньо, вони не будуть включені до схеми OpenAPI (документації API), адже FastAPI не має способу заздалегідь знати, що саме ви повернете.
Якщо ви повертаєте додаткові коди статусу та відповіді безпосередньо, вони не будуть включені до схеми OpenAPI (документації API), адже FastAPI не має способу заздалегідь знати, що саме ви повернете.
Але ви можете задокументувати це у своєму коді, використовуючи: [Додаткові відповіді](additional-responses.md){.internal-link target=_blank}.
Але ви можете задокументувати це у своєму коді, використовуючи: [Додаткові відповіді](additional-responses.md).
Так сесія звільнить з'єднання з базою даних, і його зможуть використовувати інші запити.
Так сесія звільнить з'єднання з базою даних, і його зможуть використовувати інші запити.
Якщо у вас інший сценарій, де потрібно раннє завершення залежності з `yield`, створіть, будь ласка, <ahref="https://github.com/fastapi/fastapi/discussions/new?category=questions"class="external-link"target="_blank">питання в обговореннях GitHub</a> із вашим конкретним випадком і поясненням, чому вам корисне раннє закриття для залежностей з `yield`.
Якщо у вас інший сценарій, де потрібно раннє завершення залежності з `yield`, створіть, будь ласка, [питання в обговореннях GitHub](https://github.com/fastapi/fastapi/discussions/new?category=questions) із вашим конкретним випадком і поясненням, чому вам корисне раннє закриття для залежностей з `yield`.
Якщо будуть переконливі приклади для раннього закриття в залежностях з `yield`, я розгляну додавання нового способу увімкнути раннє закриття.
Якщо будуть переконливі приклади для раннього закриття в залежностях з `yield`, я розгляну додавання нового способу увімкнути раннє закриття.
@ -144,7 +144,7 @@ checker(q="somequery")
### Фонові задачі та залежності з `yield`, технічні деталі { #background-tasks-and-dependencies-with-yield-technical-details }
### Фонові задачі та залежності з `yield`, технічні деталі { #background-tasks-and-dependencies-with-yield-technical-details }
До **FastAPI** 0.106.0 піднімати винятки після `yield` було неможливо: завершальний код у залежностях з `yield` виконувався після надсилання відповіді, тож [обробники винятків](../tutorial/handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} уже відпрацювали б.
До **FastAPI** 0.106.0 піднімати винятки після `yield` було неможливо: завершальний код у залежностях з `yield` виконувався після надсилання відповіді, тож [обробники винятків](../tutorial/handling-errors.md#install-custom-exception-handlers) уже відпрацювали б.
Так було спроєктовано головно для того, щоб дозволити використовувати ті самі об'єкти, «віддані» залежностями через `yield`, усередині фонових задач, оскільки завершальний код виконувався після завершення фонових задач.
Так було спроєктовано головно для того, щоб дозволити використовувати ті самі об'єкти, «віддані» залежностями через `yield`, усередині фонових задач, оскільки завершальний код виконувався після завершення фонових задач.
@ -160,4 +160,4 @@ checker(q="somequery")
Якщо ви раніше покладалися на цю поведінку, тепер слід створювати ресурси для фонових задач усередині самої фонової задачі та використовувати всередині лише дані, що не залежать від ресурсів залежностей із `yield`.
Якщо ви раніше покладалися на цю поведінку, тепер слід створювати ресурси для фонових задач усередині самої фонової задачі та використовувати всередині лише дані, що не залежать від ресурсів залежностей із `yield`.
Наприклад, замість використання тієї самої сесії бази даних ви створюватимете нову сесію в самій фоновій задачі та отримуватимете об'єкти з бази даних, використовуючи цю нову сесію. І далі, замість передавання об'єкта з бази даних як параметра у функцію фонової задачі, ви передасте ідентифікатор цього об'єкта, а потім отримаєте об'єкт знову всередині функції фонової задачі.
Наприклад, замість використання тієї самої сесії бази даних ви створюватимете нову сесію в самій фоновій задачі та отримуватимете об'єкти з бази даних, використовуючи Цю нову сесію. І далі, замість передавання об'єкта з бази даних як параметра у функцію фонової задачі, ви передасте ідентифікатор цього об'єкта, а потім отримаєте об'єкт знову всередині функції фонової задачі.
Майте на увазі, що сервер (Uvicorn) не використовуватиме `root_path` ні для чого, окрім передачі його застосунку.
Майте на увазі, що сервер (Uvicorn) не використовуватиме `root_path` ні для чого, окрім передачі його застосунку.
Але якщо ви перейдете у вашому браузері на <ahref="http://127.0.0.1:8000/app"class="external-link"target="_blank">http://127.0.0.1:8000/app</a>, ви побачите звичайну відповідь:
Але якщо ви перейдете у вашому браузері на [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app), ви побачите звичайну відповідь:
```JSON
```JSON
{
{
@ -251,9 +251,9 @@ Uvicorn очікуватиме, що представник буде зверт
## Локальне тестування з Traefik { #testing-locally-with-traefik }
## Локальне тестування з Traefik { #testing-locally-with-traefik }
Ви можете легко провести експеримент локально з вилученим префіксом шляху, використовуючи <ahref="https://docs.traefik.io/"class="external-link"target="_blank">Traefik</a>.
Ви можете легко провести експеримент локально з вилученим префіксом шляху, використовуючи [Traefik](https://docs.traefik.io/).
<ahref="https://github.com/containous/traefik/releases"class="external-link"target="_blank">Завантажте Traefik</a>, це один бінарний файл, ви можете розпакувати архів і запустити його безпосередньо з термінала.
[Завантажте Traefik](https://github.com/containous/traefik/releases), це один бінарний файл, ви можете розпакувати архів і запустити його безпосередньо з термінала.
Потім створіть файл `traefik.toml` з таким вмістом:
Потім створіть файл `traefik.toml` з таким вмістом:
Тепер, якщо ви перейдете за URL із портом Uvicorn: <ahref="http://127.0.0.1:8000/app"class="external-link"target="_blank">http://127.0.0.1:8000/app</a>, ви побачите звичайну відповідь:
Тепер, якщо ви перейдете за URL із портом Uvicorn: [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app), ви побачите звичайну відповідь:
А тепер відкрийте URL із портом Traefik, включно з префіксом шляху: <ahref="http://127.0.0.1:9999/api/v1/app"class="external-link"target="_blank">http://127.0.0.1:9999/api/v1/app</a>.
А тепер відкрийте URL із портом Traefik, включно з префіксом шляху: [http://127.0.0.1:9999/api/v1/app](http://127.0.0.1:9999/api/v1/app).
«Офіційний» спосіб доступу до застосунку - через представника з префіксом шляху, який ми визначили. Тож, як і очікується, якщо ви спробуєте інтерфейс документації, який обслуговує безпосередньо Uvicorn без префікса шляху в URL, це не запрацює, оскільки він очікує доступу через представника.
«Офіційний» спосіб доступу до застосунку - через представника з префіксом шляху, який ми визначили. Тож, як і очікується, якщо ви спробуєте інтерфейс документації, який обслуговує безпосередньо Uvicorn без префікса шляху в URL, це не запрацює, оскільки він очікує доступу через представника.
Ви можете перевірити це на <ahref="http://127.0.0.1:8000/docs"class="external-link"target="_blank">http://127.0.0.1:8000/docs</a>:
Ви можете перевірити це на [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs):
Але якщо ми звернемося до інтерфейсу документації за «офіційним» URL, використовуючи представника з портом `9999`, за адресою `/api/v1/docs`, усе працює коректно! 🎉
Але якщо ми звернемося до інтерфейсу документації за «офіційним» URL, використовуючи представника з портом `9999`, за адресою `/api/v1/docs`, усе працює коректно! 🎉
Ви можете перевірити це на <ahref="http://127.0.0.1:9999/api/v1/docs"class="external-link"target="_blank">http://127.0.0.1:9999/api/v1/docs</a>:
Ви можете перевірити це на [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs):
В інтерфейсі документації за адресою <ahref="http://127.0.0.1:9999/api/v1/docs"class="external-link"target="_blank">http://127.0.0.1:9999/api/v1/docs</a> це виглядатиме так:
В інтерфейсі документації за адресою [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs) це виглядатиме так:
Якщо вам потрібно змонтувати підзастосунок (як описано в [Підзастосунки - монтування](sub-applications.md){.internal-link target=_blank}), одночасно використовуючи представника з `root_path`, ви можете робити це звичайним чином, як і очікуєте.
Якщо вам потрібно змонтувати підзастосунок (як описано в [Підзастосунки - монтування](sub-applications.md)), одночасно використовуючи представника з `root_path`, ви можете робити це звичайним чином, як і очікуєте.
FastAPI внутрішньо розумно використовуватиме `root_path`, тож усе просто працюватиме. ✨
FastAPI внутрішньо розумно використовуватиме `root_path`, тож усе просто працюватиме. ✨
# Користувацька відповідь - HTML, стрім, файл, інше { #custom-response-html-stream-file-others }
# Користувацька відповідь - HTML, стрім, файл, інше { #custom-response-html-stream-file-others }
Типово **FastAPI** повертатиме відповіді, використовуючи `JSONResponse`.
Типово **FastAPI** повертатиме JSON-відповіді.
Ви можете переписати це, повернувши безпосередньо `Response`, як показано в [Повернути відповідь безпосередньо](response-directly.md){.internal-link target=_blank}.
Ви можете переписати це, повернувши `Response` безпосередньо, як показано в [Повернути відповідь безпосередньо](response-directly.md).
Але якщо ви повертаєте `Response` безпосередньо (або будь-який його підклас, як-от `JSONResponse`), дані не будуть автоматично конвертовані (навіть якщо ви оголосите `response_model`), і документація не буде автоматично згенерована (наприклад, із включенням конкретного «медіа-типу» в HTTP-заголовку `Content-Type` як частини згенерованого OpenAPI).
Але якщо ви повертаєте `Response` безпосередньо (або будь-який його підклас, як-от `JSONResponse`), дані не будуть автоматично конвертовані (навіть якщо ви оголосите `response_model`), і документація не буде автоматично згенерована (наприклад, з включенням конкретного «медіа-типу» в HTTP-заголовку `Content-Type` як частини згенерованого OpenAPI).
Ви також можете оголосити `Response`, який слід використовувати (наприклад, будь-який підклас `Response`), у декораторі операції шляху через параметр `response_class`.
Ви також можете оголосити `Response`, який слід використовувати (наприклад, будь-який підклас `Response`), у декораторі операції шляху через параметр `response_class`.
Вміст, який ви повертаєте з вашої функції операції шляху, буде поміщений усередину цього `Response`.
Вміст, який ви повертаєте з вашої функції операції шляху, буде поміщений усередину цього `Response`.
І якщо цей `Response` має JSON медіа-тип (`application/json`), як у випадку з `JSONResponse` та `UJSONResponse`, дані, що повертаються, будуть автоматично перетворені (і відфільтровані) з урахуванням будь-якого Pydantic `response_model`, який ви оголосили в декораторі операції шляху.
/// note | Примітка
/// note | Примітка
Якщо ви використовуєте клас відповіді без медіа-типу, FastAPI очікуватиме, що у вашої відповіді не буде вмісту, тож формат відповіді не буде задокументовано в згенерованих OpenAPI-документах.
Якщо ви використовуєте клас відповіді без медіа-типу, FastAPI очікуватиме, що у вашої відповіді не буде вмісту, тож формат відповіді не буде задокументовано в згенерованій документації OpenAPI.
Наприклад, якщо ви максимально оптимізуєте продуктивність, можете встановити та використовувати <ahref="https://github.com/ijl/orjson"class="external-link"target="_blank">`orjson`</a> і встановити відповідь як `ORJSONResponse`.
Імпортуйте потрібний клас `Response` (підклас) і оголосіть його в декораторі операції шляху.
Для великих відповідей повернення `Response` безпосередньо значно швидше, ніж повернення словника.
Це тому, що за замовчуванням FastAPI перевірятиме кожен елемент усередині та переконуватиметься, що його можна серіалізувати як JSON, використовуючи той самий [Сумісний кодувальник JSON](../tutorial/encoder.md){.internal-link target=_blank}, описаний у навчальному посібнику. Саме це дозволяє повертати довільні об'єкти, наприклад моделі бази даних.
Але якщо ви впевнені, що вміст, який повертається, серіалізується в JSON, ви можете передати його безпосередньо класу відповіді та уникнути додаткових витрат FastAPI на пропускання вашого вмісту через `jsonable_encoder` перед передаванням його класу відповіді.
Якщо ви оголосите [Модель відповіді](../tutorial/response-model.md), FastAPI використає її, щоб серіалізувати дані в JSON за допомогою Pydantic.
Параметр `response_class` також визначатиме «медіа-тип» відповіді.
У цьому випадку HTTP-заголовок `Content-Type` буде встановлено в `application/json`.
Якщо ви не оголосите модель відповіді, FastAPI використає `jsonable_encoder`, пояснений у [Сумісний кодувальник JSON](../tutorial/encoder.md), і помістить результат у `JSONResponse`.
І це буде задокументовано відповідно в OpenAPI.
Якщо ви оголосите `response_class` з JSON медіа-типом (`application/json`), як у випадку з `JSONResponse`, дані, що повертаються, будуть автоматично перетворені (і відфільтровані) згідно з будь-якою Pydantic `response_model`, яку ви оголосили в декораторі операції шляху. Але дані не будуть серіалізовані в JSON-байти за допомогою Pydantic, натомість вони будуть перетворені з `jsonable_encoder`, а потім передані класу `JSONResponse`, який і серіалізує їх у байти, використовуючи стандартну JSON-бібліотеку в Python.
///
### Продуктивність JSON { #json-performance }
/// tip | Порада
Коротко: якщо вам потрібна максимальна продуктивність, використовуйте [Модель відповіді](../tutorial/response-model.md) і не оголошуйте `response_class` у декораторі операції шляху.
`ORJSONResponse` доступний лише у FastAPI, не в Starlette.
Як показано в [Повернути відповідь безпосередньо](response-directly.md){.internal-link target=_blank}, ви також можете переписати відповідь безпосередньо у вашій операції шляху, просто повернувши її.
Як показано в [Повернути відповідь безпосередньо](response-directly.md), ви також можете переписати відповідь безпосередньо у вашій операції шляху, просто повернувши її.
Той самий приклад вище, що повертає `HTMLResponse`, може виглядати так:
Той самий приклад вище, що повертає `HTMLResponse`, може виглядати так:
@ -134,7 +118,7 @@
- `headers` - `dict` строк.
- `headers` - `dict` строк.
- `media_type` - `str`, що задає медіа-тип, напр. `"text/html"`.
- `media_type` - `str`, що задає медіа-тип, напр. `"text/html"`.
FastAPI (насправді Starlette) автоматично додасть заголовок Content-Length. Також буде додано заголовок Content-Type, на основі `media_type` з додаванням набору символів для текстових типів.
FastAPI (насправді Starlette) автоматично додасть заголовок Content-Length. Також буде додано заголовок Content-Type на основі `media_type` з додаванням набору символів для текстових типів.
@ -154,37 +138,11 @@ FastAPI (насправді Starlette) автоматично додасть з
Це типова відповідь, яку використовує **FastAPI**, як зазначено вище.
Це типова відповідь, яку використовує **FastAPI**, як зазначено вище.
### `ORJSONResponse` { #orjsonresponse }
/// note | Технічні деталі
Швидка альтернативна JSON-відповідь з використанням <ahref="https://github.com/ijl/orjson"class="external-link"target="_blank">`orjson`</a>, як описано вище.
/// info | Інформація
Потрібно встановити `orjson`, наприклад `pip install orjson`.
///
### `UJSONResponse` { #ujsonresponse }
Альтернативна JSON-відповідь з використанням <ahref="https://github.com/ultrajson/ultrajson"class="external-link"target="_blank">`ujson`</a>.
/// info | Інформація
Потрібно встановити `ujson`, наприклад `pip install ujson`.
///
/// warning | Попередження
`ujson` менш обережний, ніж вбудована реалізація Python, у поводженні з деякими крайніми випадками.
Але якщо ви оголосите модель відповіді або тип, його буде використано безпосередньо для серіалізації даних у JSON, і відповідь з коректним медіа-типом для JSON буде повернута безпосередньо, без використання класу `JSONResponse`.
Ймовірно, `ORJSONResponse` може бути швидшою альтернативою.
Це ідеальний спосіб отримати найкращу продуктивність.
///
///
@ -200,6 +158,7 @@ FastAPI (насправді Starlette) автоматично додасть з
Або ви можете використати його в параметрі `response_class`:
Або ви можете використати його в параметрі `response_class`:
#### Використання `StreamingResponse` з об'єктами типу file-like { #using-streamingresponse-with-file-like-objects }
Якщо у вас є <ahref="https://docs.python.org/3/glossary.html#term-file-like-object"class="external-link"target="_blank">file-like</a> об'єкт (наприклад, об'єкт, що повертається `open()`), ви можете створити генераторну функцію для ітерації по цьому file-like об'єкту.
Завдання `async` може бути скасовано лише тоді, коли воно досягає `await`. Якщо немає `await`, генератор (функція з `yield`) не може бути коректно скасований і може продовжувати працювати навіть після запиту на скасування.
1. Це генераторна функція. Вона є «генераторною функцією», бо містить оператори `yield` усередині.
Оскільки цьому невеликому прикладу не потрібні жодні оператори `await`, ми додаємо `await anyio.sleep(0)`, щоб надати циклу подій шанс обробити скасування.
2. Використовуючи блок `with`, ми гарантуємо, що file-like об'єкт буде закрито після завершення роботи генераторної функції. Тобто після того, як вона завершить надсилання відповіді.
3. Цей `yield from` вказує функції ітеруватися по об'єкту з назвою `file_like`. А потім, для кожної ітерованої частини, повертати цю частину, ніби вона надходить з цієї генераторної функції (`iterfile`).
Тож це генераторна функція, яка всередині передає роботу «генерації» чомусь іншому.
Це ще важливіше для великих або нескінченних потоків.
Роблячи це таким чином, ми можемо помістити її в блок `with` і таким чином гарантувати, що file-like об'єкт буде закрито після завершення.
///
/// tip | Порада
/// tip | Порада
Зверніть увагу, що тут ми використовуємо стандартний `open()`, який не підтримує `async` та `await`, тому ми оголошуємо операцію шляху звичайною `def`.
Замість того щоб повертати `StreamingResponse` безпосередньо, імовірно, краще дотримуватися стилю в [Потокова передача даних](./stream-data.md), це значно зручніше та обробляє скасування «за лаштунками» для вас.
Якщо ви транслюєте JSON Lines, дотримуйтесь навчального посібника [Потоки JSON Lines](../tutorial/stream-json-lines.md).
///
///
@ -267,7 +220,7 @@ FastAPI (насправді Starlette) автоматично додасть з
Ви можете створити власний клас відповіді, успадкувавши його від `Response`, і використовувати його.
Ви можете створити власний клас відповіді, успадкувавши його від `Response`, і використовувати його.
Наприклад, скажімо, ви хочете використовувати <ahref="https://github.com/ijl/orjson"class="external-link"target="_blank">`orjson`</a>, але з деякими користувацькими налаштуваннями, які не використовуються у вбудованому класі `ORJSONResponse`.
Наприклад, скажімо, ви хочете використовувати [`orjson`](https://github.com/ijl/orjson) з деякими налаштуваннями.
Припустімо, ви хочете, щоб повертався відформатований із відступами JSON, тож ви хочете використати опцію orjson `orjson.OPT_INDENT_2`.
Припустімо, ви хочете, щоб повертався відформатований із відступами JSON, тож ви хочете використати опцію orjson `orjson.OPT_INDENT_2`.
@ -291,13 +244,21 @@ FastAPI (насправді Starlette) автоматично додасть з
Звісно, ви, ймовірно, знайдете значно кращі способи скористатися цим, ніж просто форматування JSON. 😉
Звісно, ви, ймовірно, знайдете значно кращі способи скористатися цим, ніж просто форматування JSON. 😉
### `orjson` або Модель відповіді { #orjson-or-response-model }
Якщо ви шукаєте продуктивність, імовірно, краще використати [Модель відповіді](../tutorial/response-model.md), ніж відповідь `orjson`.
З моделлю відповіді FastAPI використає Pydantic, щоб серіалізувати дані в JSON без проміжних кроків, як-от перетворення за допомогою `jsonable_encoder`, що відбувалося б в іншому випадку.
І «під капотом» Pydantic використовує ті самі внутрішні механізми Rust, що й `orjson`, для серіалізації в JSON, тож ви вже отримаєте найкращу продуктивність із моделлю відповіді.
## Типова відповідь за замовчуванням { #default-response-class }
## Типова відповідь за замовчуванням { #default-response-class }
Створюючи екземпляр класу **FastAPI** або `APIRouter`, ви можете вказати, який клас відповіді використовувати за замовчуванням.
Створюючи екземпляр класу **FastAPI** або `APIRouter`, ви можете вказати, який клас відповіді використовувати за замовчуванням.
Параметр, що це визначає, - `default_response_class`.
Параметр, що це визначає, - `default_response_class`.
У прикладі нижче **FastAPI** використовуватиме `ORJSONResponse` за замовчуванням в усіх операціях шляху замість `JSONResponse`.
У прикладі нижче **FastAPI** використовуватиме `HTMLResponse` за замовчуванням в усіх операціях шляху, замість JSON.
Ви також можете оголосити медіа-тип і багато інших деталей в OpenAPI, використовуючи `responses`: [Додаткові відповіді в OpenAPI](additional-responses.md){.internal-link target=_blank}.
Ви також можете оголосити медіа-тип і багато інших деталей в OpenAPI, використовуючи `responses`: [Додаткові відповіді в OpenAPI](additional-responses.md).
FastAPI побудовано поверх **Pydantic**, і я показував вам, як використовувати моделі Pydantic для оголошення запитів і відповідей.
FastAPI побудовано поверх **Pydantic**, і я показував вам, як використовувати моделі Pydantic для оголошення запитів і відповідей.
Але FastAPI також підтримує використання <ahref="https://docs.python.org/3/library/dataclasses.html"class="external-link"target="_blank">`dataclasses`</a> таким самим чином:
Але FastAPI також підтримує використання [`dataclasses`](https://docs.python.org/3/library/dataclasses.html) таким самим чином:
Це підтримується завдяки **Pydantic**, адже він має <ahref="https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel"class="external-link"target="_blank">внутрішню підтримку `dataclasses`</a>.
Це підтримується завдяки **Pydantic**, адже він має [внутрішню підтримку `dataclasses`](https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel).
Тож навіть із наведеним вище кодом, який явно не використовує Pydantic, FastAPI використовує Pydantic, щоб перетворити стандартні dataclasses у власний варіант dataclasses Pydantic.
Тож навіть із наведеним вище кодом, який явно не використовує Pydantic, FastAPI використовує Pydantic, щоб перетворити стандартні dataclasses у власний варіант dataclasses Pydantic.
@ -18,7 +18,7 @@ FastAPI побудовано поверх **Pydantic**, і я показував
Це працює так само, як із моделями Pydantic. Насправді під капотом це також досягається за допомогою Pydantic.
Це працює так само, як із моделями Pydantic. Насправді під капотом це також досягається за допомогою Pydantic.
/// info | Інформація
/// info
Майте на увазі, що dataclasses не можуть робити все те, що можуть моделі Pydantic.
Майте на увазі, що dataclasses не можуть робити все те, що можуть моделі Pydantic.
@ -64,7 +64,7 @@ Dataclass буде автоматично перетворено на dataclass
6. Тут ми повертаємо словник, що містить `items`, який є списком dataclass.
6. Тут ми повертаємо словник, що містить `items`, який є списком dataclass.
FastAPI усе ще здатний <dfntitle="перетворення даних у формат, який можна передати">серіалізувати</dfn> дані до JSON.
FastAPI усе ще здатний <dfntitle="перетворення даних у формат, який можна передати">серіалізувати</dfн> дані до JSON.
7. Тут у `response_model` використано анотацію типу список dataclass `Author`.
7. Тут у `response_model` використано анотацію типу список dataclass `Author`.
@ -74,7 +74,7 @@ Dataclass буде автоматично перетворено на dataclass
Як завжди, у FastAPI ви можете поєднувати `def` і `async def` за потреби.
Як завжди, у FastAPI ви можете поєднувати `def` і `async def` за потреби.
Якщо вам потрібне коротке нагадування, коли що використовувати, перегляньте розділ _«Поспішаєте?»_ у документації про [`async` та `await`](../async.md#in-a-hurry){.internal-link target=_blank}.
Якщо вам потрібне коротке нагадування, коли що використовувати, перегляньте розділ _«Поспішаєте?»_ у документації про [`async` та `await`](../async.md#in-a-hurry).
9. Ця *функція операції шляху* не повертає dataclasses (хоча могла б), а список словників із внутрішніми даними.
9. Ця *функція операції шляху* не повертає dataclasses (хоча могла б), а список словників із внутрішніми даними.
@ -88,7 +88,7 @@ Dataclass буде автоматично перетворено на dataclass
Можна поєднувати `dataclasses` з іншими моделями Pydantic, наслідувати їх, включати у власні моделі тощо.
Можна поєднувати `dataclasses` з іншими моделями Pydantic, наслідувати їх, включати у власні моделі тощо.
Щоб дізнатися більше, перегляньте <ahref="https://docs.pydantic.dev/latest/concepts/dataclasses/"class="external-link"target="_blank">документацію Pydantic про dataclasses</a>.
Щоб дізнатися більше, перегляньте [документацію Pydantic про dataclasses](https://docs.pydantic.dev/latest/concepts/dataclasses/).
## Генератори SDK з відкритим кодом { #open-source-sdk-generators }
## Генератори SDK з відкритим кодом { #open-source-sdk-generators }
Універсальним варіантом є <ahref="https://openapi-generator.tech/"class="external-link"target="_blank">OpenAPI Generator</a>, який підтримує **багато мов програмування** та може генерувати SDK з вашої специфікації OpenAPI.
Універсальним варіантом є [OpenAPI Generator](https://openapi-generator.tech/), який підтримує **багато мов програмування** та може генерувати SDK з вашої специфікації OpenAPI.
Для **клієнтів TypeScript**<ahref="https://heyapi.dev/"class="external-link"target="_blank">Hey API</a> — спеціалізоване рішення, що надає оптимізований досвід для екосистеми TypeScript.
Для **клієнтів TypeScript**[Hey API](https://heyapi.dev/) — спеціалізоване рішення, що надає оптимізований досвід для екосистеми TypeScript.
Більше генераторів SDK ви можете знайти на <ahref="https://openapi.tools/#sdk"class="external-link"target="_blank">OpenAPI.Tools</a>.
Більше генераторів SDK ви можете знайти на [OpenAPI.Tools](https://openapi.tools/#sdk).
У цьому розділі представлено рішення від компаній, що спонсорують FastAPI: вони мають **венчурну підтримку** та **корпоративну підтримку**. Ці продукти надають **додаткові можливості** та **інтеграції** поверх високоякісно згенерованих SDK.
У цьому розділі представлено рішення від компаній, що спонсорують FastAPI: вони мають **венчурну підтримку** та **корпоративну підтримку**. Ці продукти надають **додаткові можливості** та **інтеграції** поверх високоякісно згенерованих SDK.
Завдяки ✨ [**спонсорству FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨ ці компанії допомагають підтримувати фреймворк та його **екосистему** здоровими та **сталими**.
Завдяки ✨ [**спонсорству FastAPI**](../help-fastapi.md#sponsor-the-author) ✨ ці компанії допомагають підтримувати фреймворк та його **екосистему** здоровими та **сталими**.
Їхня підтримка також демонструє сильну відданість **спільноті** FastAPI (вам), показуючи, що їм важливо не лише надавати **відмінний сервіс**, а й підтримувати **міцний і процвітаючий фреймворк**, FastAPI. 🙇
Їхня підтримка також демонструє сильну відданість **спільноті** FastAPI (вам), показуючи, що їм важливо не лише надавати **відмінний сервіс**, а й підтримувати **міцний і процвітаючий фреймворк**, FastAPI. 🙇
Деякі з цих рішень також можуть бути з відкритим кодом або мати безкоштовні тарифи, тож ви можете спробувати їх без фінансових зобов'язань. Інші комерційні генератори SDK також доступні й їх можна знайти онлайн. 🤓
Деякі з цих рішень також можуть бути з відкритим кодом або мати безкоштовні тарифи, тож ви можете спробувати їх без фінансових зобов'язань. Інші комерційні генератори SDK також доступні й їх можна знайти онлайн. 🤓
Ви можете дізнатися, як <ahref="https://heyapi.dev/openapi-ts/get-started"class="external-link"target="_blank">встановити `@hey-api/openapi-ts`</a>, і почитати про <ahref="https://heyapi.dev/openapi-ts/output"class="external-link"target="_blank">згенерований результат</a> на їхньому сайті.
Ви можете дізнатися, як [встановити `@hey-api/openapi-ts`](https://heyapi.dev/openapi-ts/get-started), і почитати про [згенерований результат](https://heyapi.dev/openapi-ts/output) на їхньому сайті.
Основний [Навчальний посібник - Посібник користувача](../tutorial/index.md){.internal-link target=_blank} має бути достатнім, щоб провести вас через усі основні можливості **FastAPI**.
Основний [Навчальний посібник - Посібник користувача](../tutorial/index.md) має бути достатнім, щоб провести вас через усі основні можливості **FastAPI**.
У наступних розділах ви побачите інші опції, конфігурації та додаткові можливості.
У наступних розділах ви побачите інші опції, конфігурації та додаткові можливості.
/// tip | Порада
/// tip
Наступні розділи не обов'язково «просунуті».
Наступні розділи **не обов'язково «просунуті»**.
І можливо, що рішення для вашого випадку використання може бути в одному з них.
І можливо, що рішення для вашого випадку використання може бути в одному з них.
@ -16,6 +16,6 @@
## Спершу прочитайте навчальний посібник { #read-the-tutorial-first }
## Спершу прочитайте навчальний посібник { #read-the-tutorial-first }
Ви все ще можете використовувати більшість можливостей **FastAPI**, маючи знання з основного [Навчального посібника - Посібника користувача](../tutorial/index.md){.internal-link target=_blank}.
Ви все ще можете використовувати більшість можливостей **FastAPI**, маючи знання з основного [Навчального посібника - Посібника користувача](../tutorial/index.md).
А в наступних розділах передбачається, що ви вже його прочитали і знайомі з основними ідеями.
А в наступних розділах передбачається, що ви вже його прочитали і знайомі з основними ідеями.
Параметр запиту `callback_url` використовує тип Pydantic <ahref="https://docs.pydantic.dev/latest/api/networks/"class="external-link"target="_blank">Url</a>.
Параметр запиту `callback_url` використовує тип Pydantic [Url](https://docs.pydantic.dev/latest/api/networks/).
Фактичний зворотний виклик - це просто HTTP-запит.
Фактичний зворотний виклик - це просто HTTP-запит.
Реалізуючи зворотний виклик самостійно, ви можете скористатися, наприклад, <ahref="https://www.python-httpx.org"class="external-link"target="_blank">HTTPX</a> або <ahref="https://requests.readthedocs.io/"class="external-link"target="_blank">Requests</a>.
Реалізуючи зворотний виклик самостійно, ви можете скористатися, наприклад, [HTTPX](https://www.python-httpx.org) або [Requests](https://requests.readthedocs.io/).
Є 2 основні відмінності від звичайної операції шляху:
Є 2 основні відмінності від звичайної операції шляху:
- Їй не потрібен реальний код, адже ваш застосунок ніколи не викликатиме цей код. Вона використовується лише для документування зовнішнього API. Тому функція може просто містити `pass`.
- Їй не потрібен реальний код, адже ваш застосунок ніколи не викликатиме цей код. Вона використовується лише для документування зовнішнього API. Тому функція може просто містити `pass`.
- Шлях може містити <ahref="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression"class="external-link"target="_blank">вираз OpenAPI 3</a> (див. нижче), де можна використовувати змінні з параметрами та частини оригінального запиту, надісланого до вашого API.
- Шлях може містити [вираз OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) (див. нижче), де можна використовувати змінні з параметрами та частини оригінального запиту, надісланого до вашого API.
### Вираз шляху зворотного виклику { #the-callback-path-expression }
### Вираз шляху зворотного виклику { #the-callback-path-expression }
Шлях зворотного виклику може містити <ahref="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression"class="external-link"target="_blank">вираз OpenAPI 3</a>, який включає частини оригінального запиту, надісланого до вашого API.
Шлях зворотного виклику може містити [вираз OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression), який включає частини оригінального запиту, надісланого до вашого API.
Тепер ви можете запустити застосунок і перейти за адресою <ahref="http://127.0.0.1:8000/docs"class="external-link"target="_blank">http://127.0.0.1:8000/docs</a>.
Тепер ви можете запустити застосунок і перейти за адресою [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
Ви побачите вашу документацію з розділом «Callbacks» для вашої операції шляху, який показує, як має виглядати зовнішній API:
Ви побачите вашу документацію з розділом «Callbacks» для вашої операції шляху, який показує, як має виглядати зовнішній API:
Майте на увазі, що якщо ви повертаєте відповідь безпосередньо замість використання параметра `Response`, FastAPI поверне її напряму.
Майте на увазі, що якщо ви повертаєте відповідь безпосередньо замість використання параметра `Response`, FastAPI поверне її напряму.
@ -48,4 +48,4 @@
///
///
Щоб побачити всі доступні параметри та опції, перегляньте <ahref="https://www.starlette.dev/responses/#set-cookie"class="external-link"target="_blank">документацію в Starlette</a>.
Щоб побачити всі доступні параметри та опції, перегляньте [документацію в Starlette](https://www.starlette.dev/responses/#set-cookie).
# Повернення Response безпосередньо { #return-a-response-directly }
# Повернення Response безпосередньо { #return-a-response-directly }
Коли ви створюєте операцію шляху FastAPI, зазвичай ви можете повертати з неї будь-які дані: `dict`, `list`, модель Pydantic, модель бази даних тощо.
Коли ви створюєте операцію шляху **FastAPI**, зазвичай ви можете повертати з неї будь-які дані: `dict`, `list`, модель Pydantic, модель бази даних тощо.
Типово FastAPI автоматично перетворить це значення повернення на JSON, використовуючи `jsonable_encoder`, описаний у [Сумісному з JSON кодері](../tutorial/encoder.md){.internal-link target=_blank}.
Якщо ви оголосите [Модель відповіді](../tutorial/response-model.md), **FastAPI** використає її, щоб серіалізувати дані у JSON за допомогою Pydantic.
Потім, за лаштунками, він помістить ці дані, сумісні з JSON (наприклад, `dict`), у `JSONResponse`, який буде використано для надсилання відповіді клієнту.
Якщо ви не оголошуєте модель відповіді, **FastAPI** використає `jsonable_encoder`, описаний у [Сумісному з JSON кодері](../tutorial/encoder.md), і помістить результат у `JSONResponse`.
Але ви можете повертати `JSONResponse` безпосередньо з ваших операцій шляху.
Ви також можете створити `JSONResponse` безпосередньо і повернути його.
Це може бути корисним, наприклад, щоб повертати власні заголовки або кукі.
/// tip | Порада
Зазвичай ви отримаєте значно кращу продуктивність, використовуючи [Модель відповіді](../tutorial/response-model.md), ніж повертаючи `JSONResponse` безпосередньо, адже так дані серіалізуються Pydantic на Rust.
///
## Повернення `Response` { #return-a-response }
## Повернення `Response` { #return-a-response }
Насправді ви можете повертати будь-який `Response` або будь-який його підклас.
Ви можете повертати`Response` або будь-який його підклас.
/// tip | Порада
/// info | Інформація
`JSONResponse` сам є підкласом `Response`.
`JSONResponse` сам є підкласом `Response`.
///
///
І коли ви повертаєте `Response`, FastAPI передасть його безпосередньо.
І коли ви повертаєте `Response`, **FastAPI** передасть його безпосередньо.
Він не виконуватиме жодних перетворень даних за допомогою моделей Pydantic, не перетворюватиме вміст на будь-який тип тощо.
Він не виконуватиме жодних перетворень даних за допомогою моделей Pydantic, не перетворюватиме вміст на будь-який тип тощо.
Це дає вам багато гнучкості. Ви можете повертати будь-які типи даних, переписувати будь-які оголошення або перевірки даних тощо.
Це дає вам багато гнучкості. Ви можете повертати будь-які типи даних, переписувати будь-які оголошення або перевірки даних тощо.
Це також покладає на вас багато відповідальності. Ви маєте переконатися, що дані, які ви повертаєте, коректні, у правильному форматі, можуть бути серіалізовані тощо.
## Використання `jsonable_encoder` у `Response` { #using-the-jsonable-encoder-in-a-response }
## Використання `jsonable_encoder` у `Response` { #using-the-jsonable-encoder-in-a-response }
Оскільки FastAPI не вносить змін у `Response`, який ви повертаєте, вам потрібно впевнитися, що його вміст готовий.
Оскільки **FastAPI** не вносить змін у `Response`, який ви повертаєте, вам потрібно впевнитися, що його вміст готовий.
Наприклад, ви не можете покласти модель Pydantic у `JSONResponse`, не перетворивши її спочатку на `dict` з усіма типами даних (як-от `datetime`, `UUID` тощо), перетвореними на типи, сумісні з JSON.
Наприклад, ви не можете помістити модель Pydantic у `JSONResponse`, не перетворивши її спочатку на `dict` з усіма типами даних (як-от `datetime`, `UUID` тощо), перетвореними на типи, сумісні з JSON.
Для таких випадків ви можете використати `jsonable_encoder`, щоб перетворити ваші дані перед тим, як передати їх у відповідь:
Для таких випадків ви можете використати `jsonable_encoder`, щоб перетворити ваші дані перед тим, як передати їх у відповідь:
@ -40,13 +46,13 @@
Ви також можете використати `from starlette.responses import JSONResponse`.
Ви також можете використати `from starlette.responses import JSONResponse`.
FastAPI надає ті самі `starlette.responses` як `fastapi.responses` просто як зручність для вас, розробника. Але більшість доступних `Response` походять безпосередньо зі Starlette.
**FastAPI** надає ті самі `starlette.responses` як `fastapi.responses` просто як зручність для вас, розробника. Але більшість доступних відповідей походять безпосередньо зі Starlette.
///
///
## Повернення власного `Response` { #returning-a-custom-response }
## Повернення власного `Response` { #returning-a-custom-response }
Наведений вище приклад показує всі необхідні частини, але він ще не дуже корисний, адже ви могли просто повернути `item` безпосередньо, і FastAPI помістив би його у `JSONResponse`, перетворивши на `dict` тощо. Усе це відбувається за замовчуванням.
Наведений вище приклад показує всі необхідні частини, але він ще не дуже корисний, адже ви могли просто повернути `item` безпосередньо, і **FastAPI** помістив би його у `JSONResponse`, перетворивши на `dict` тощо. Усе це відбувається за замовчуванням.
Тепер подивімося, як це використати, щоб повернути власну відповідь.
Тепер подивімося, як це використати, щоб повернути власну відповідь.
@ -56,10 +62,22 @@ FastAPI надає ті самі `starlette.responses` як `fastapi.responses`
## Як працює модель відповіді { #how-a-response-model-works }
Коли ви оголошуєте [Модель відповіді - Тип, що повертається](../tutorial/response-model.md) в операції шляху, **FastAPI** використає її, щоб серіалізувати дані у JSON за допомогою Pydantic.
Оскільки це відбувається на боці Rust, продуктивність буде значно кращою, ніж якби це робилося звичайним Python і класом `JSONResponse`.
Коли використовується `response_model` або тип, що повертається, **FastAPI** не використовуватиме `jsonable_encoder` для перетворення даних (що було б повільніше) і не використовуватиме клас `JSONResponse`.
Натомість воно бере байти JSON, згенеровані Pydantic за допомогою моделі відповіді (або типу, що повертається), і повертає `Response` з відповідним медіа-типом для JSON (`application/json`) безпосередньо.
## Примітки { #notes }
## Примітки { #notes }
Коли ви повертаєте `Response` безпосередньо, його дані не перевіряються, не перетворюються (серіалізуються) і не документуються автоматично.
Коли ви повертаєте `Response` безпосередньо, його дані не перевіряються, не перетворюються (серіалізуються) і не документуються автоматично.
Але ви все ще можете задокументувати це, як описано в [Додаткових відповідях в OpenAPI](additional-responses.md){.internal-link target=_blank}.
Але ви все ще можете задокументувати це, як описано в [Додаткових відповідях в OpenAPI](additional-responses.md).
У подальших розділах ви побачите, як використовувати/оголошувати ці власні `Response`, водночас зберігаючи автоматичне перетворення даних, документацію тощо.
У подальших розділах ви побачите, як використовувати/оголошувати ці власні `Response`, водночас зберігаючи автоматичне перетворення даних, документацію тощо.
Якщо ви оголосили `response_model`, його все одно буде використано для фільтрації та перетворення поверненого обʼєкта.
Якщо ви оголосили `response_model`, його все одно буде використано для фільтрації та перетворення поверненого обʼєкта.
FastAPI використає цей *тимчасовий* обʼєкт відповіді, щоб витягти заголовки (а також кукі та код статусу) і помістить їх у кінцеву відповідь, яка міститиме повернуте вами значення, відфільтроване будь-яким `response_model`.
**FastAPI** використає цей *тимчасовий* обʼєкт відповіді, щоб витягти заголовки (а також кукі та код статусу) і помістить їх у кінцеву відповідь, яка міститиме повернуте вами значення, відфільтроване будь-яким `response_model`.
Також ви можете оголосити параметр `Response` у залежностях і встановлювати в них заголовки (та кукі).
Також ви можете оголосити параметр `Response` у залежностях і встановлювати в них заголовки (та кукі).
@ -20,7 +20,7 @@ FastAPI використає цей *тимчасовий* обʼєкт відп
Ви також можете додавати заголовки, коли повертаєте `Response` безпосередньо.
Ви також можете додавати заголовки, коли повертаєте `Response` безпосередньо.
Створіть відповідь, як описано в [Повернення Response безпосередньо](response-directly.md){.internal-link target=_blank}, і передайте заголовки як додатковий параметр:
Створіть відповідь, як описано в [Повернення Response безпосередньо](response-directly.md), і передайте заголовки як додатковий параметр:
@ -28,14 +28,14 @@ FastAPI використає цей *тимчасовий* обʼєкт відп
Ви також можете використати `from starlette.responses import Response` або `from starlette.responses import JSONResponse`.
Ви також можете використати `from starlette.responses import Response` або `from starlette.responses import JSONResponse`.
FastAPI надає ті самі `starlette.responses` як `fastapi.responses` просто для зручності для вас, розробника. Але більшість доступних типів відповідей походять безпосередньо зі Starlette.
**FastAPI** надає ті самі `starlette.responses` як `fastapi.responses` просто для зручності для вас, розробника. Але більшість доступних типів відповідей походять безпосередньо зі Starlette.
Оскільки `Response` часто використовують для встановлення заголовків і кукі, FastAPI також надає його як `fastapi.Response`.
Оскільки `Response` часто використовують для встановлення заголовків і кукі, **FastAPI** також надає його як `fastapi.Response`.
///
///
## Власні заголовки { #custom-headers }
## Власні заголовки { #custom-headers }
Майте на увазі, що власні закриті заголовки можна додавати <ahref="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers"class="external-link"target="_blank">за допомогою префікса `X-`</a>.
Майте на увазі, що власні пропрієтарні заголовки можна додавати [за допомогою префікса `X-`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).
Але якщо у вас є власні заголовки, які клієнт у браузері має бачити, вам потрібно додати їх у вашу конфігурацію CORS (докладніше в [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md){.internal-link target=_blank}), використовуючи параметр `expose_headers`, задокументований у <ahref="https://www.starlette.dev/middleware/#corsmiddleware"class="external-link"target="_blank">документації Starlette щодо CORS</a>.
Але якщо у вас є власні заголовки, які клієнт у браузері має бачити, вам потрібно додати їх у вашу конфігурацію CORS (докладніше в [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md)), використовуючи параметр `expose_headers`, задокументований у [документації Starlette щодо CORS](https://www.starlette.dev/middleware/#corsmiddleware).
Використайте залежність, щоб перевірити, чи правильні ім'я користувача та пароль.
Використайте залежність, щоб перевірити, чи правильні ім'я користувача та пароль.
Для цього використайте стандартний модуль Python <ahref="https://docs.python.org/3/library/secrets.html"class="external-link"target="_blank">`secrets`</a>, щоб перевірити ім'я користувача та пароль.
Для цього використайте стандартний модуль Python [`secrets`](https://docs.python.org/3/library/secrets.html), щоб перевірити ім'я користувача та пароль.
`secrets.compare_digest()` повинен отримувати `bytes` або `str`, що містить лише ASCII-символи (англійські), це означає, що він не працюватиме з символами на кшталт `á`, як у `Sebastián`.
`secrets.compare_digest()` повинен отримувати `bytes` або `str`, що містить лише ASCII-символи (англійські), це означає, що він не працюватиме з символами на кшталт `á`, як у `Sebastián`.
@ -46,7 +46,7 @@
```Python
```Python
if not (credentials.username == "stanleyjobson") or not (credentials.password == "swordfish"):
if not (credentials.username == "stanleyjobson") or not (credentials.password == "swordfish"):
Є кілька додаткових можливостей для роботи з безпекою, окрім тих, що розглянуті в [Навчальний посібник - Посібник користувача: Безпека](../../tutorial/security/index.md){.internal-link target=_blank}.
Є кілька додаткових можливостей для роботи з безпекою, окрім тих, що розглянуті в [Навчальний посібник - Посібник користувача: Безпека](../../tutorial/security/index.md).
/// tip | Порада
/// tip | Порада
Наступні розділи не обов'язково «просунуті».
Наступні розділи **не обов'язково «просунуті»**.
І можливо, що для вашого випадку використання рішення є в одному з них.
І можливо, що для вашого випадку використання рішення є в одному з них.
@ -14,6 +14,6 @@
## Спершу прочитайте навчальний посібник { #read-the-tutorial-first }
## Спершу прочитайте навчальний посібник { #read-the-tutorial-first }
У наступних розділах передбачається, що ви вже прочитали основний [Навчальний посібник - Посібник користувача: Безпека](../../tutorial/security/index.md){.internal-link target=_blank}.
У наступних розділах передбачається, що ви вже прочитали основний [Навчальний посібник - Посібник користувача: Безпека](../../tutorial/security/index.md).
Усі вони базуються на тих самих концепціях, але надають деякі додаткові можливості.
Усі вони базуються на тих самих концепціях, але надають деякі додаткові можливості.
@ -60,7 +60,7 @@ OAuth2 зі scopes - це механізм, який використовуют
## Загальний огляд { #global-view }
## Загальний огляд { #global-view }
Спочатку швидко подивімося на частини, що відрізняються від прикладів у головному **Навчальному посібнику - Керівництві користувача** для [OAuth2 з паролем (і хешуванням), Bearer з JWT-токенами](../../tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. Тепер із використанням OAuth2 scopes:
Спочатку швидко подивімося на частини, що відрізняються від прикладів у головному **Навчальному посібнику - Керівництві користувача** для [OAuth2 з паролем (і хешуванням), Bearer з JWT-токенами](../../tutorial/security/oauth2-jwt.md). Тепер із використанням OAuth2 scopes:
@ -271,4 +271,4 @@ OAuth2 зі scopes - це механізм, який використовуют
## `Security` у параметрі декоратора `dependencies` { #security-in-decorator-dependencies }
## `Security` у параметрі декоратора `dependencies` { #security-in-decorator-dependencies }
Так само як ви можете визначити `list` із `Depends` у параметрі `dependencies` декоратора (як пояснено в [Залежності в декораторах операцій шляху](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}), ви також можете використовувати там `Security` зі `scopes`.
Так само як ви можете визначити `list` із `Depends` у параметрі `dependencies` декоратора (як пояснено в [Залежності в декораторах операцій шляху](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md)), ви також можете використовувати там `Security` зі `scopes`.
А потім відкрийте документацію для підзастосунку за адресою <ahref="http://127.0.0.1:8000/subapi/docs"class="external-link"target="_blank">http://127.0.0.1:8000/subapi/docs</a>.
А потім відкрийте документацію для підзастосунку за адресою [http://127.0.0.1:8000/subapi/docs](http://127.0.0.1:8000/subapi/docs).
Ви побачите автоматичну документацію API для підзастосунку, що містить лише його власні _операції шляху_, усі з правильним префіксом підшляху `/subapi`:
Ви побачите автоматичну документацію API для підзастосунку, що містить лише його власні _операції шляху_, усі з правильним префіксом підшляху `/subapi`:
@ -64,4 +64,4 @@ $ fastapi dev main.py
Підзастосунок також може мати власні змонтовані підзастосунки, і все працюватиме коректно, оскільки FastAPI автоматично обробляє всі ці `root_path`.
Підзастосунок також може мати власні змонтовані підзастосунки, і все працюватиме коректно, оскільки FastAPI автоматично обробляє всі ці `root_path`.
Ви дізнаєтеся більше про `root_path` і як використовувати його явно в розділі [За представником](behind-a-proxy.md){.internal-link target=_blank}.
Ви дізнаєтеся більше про `root_path` і як використовувати його явно в розділі [За представником](behind-a-proxy.md).
## Деталі про об'єкт `Request` { #details-about-the-request-object }
## Деталі про об'єкт `Request` { #details-about-the-request-object }
Оскільки під капотом **FastAPI** - це **Starlette** з шаром інструментів зверху, ви можете за потреби використовувати <ahref="https://www.starlette.dev/requests/"class="external-link"target="_blank">об'єкт `Request`</a> Starlette безпосередньо.
Оскільки під капотом **FastAPI** - це **Starlette** з шаром інструментів зверху, ви можете за потреби використовувати об'єкт [`Request`](https://www.starlette.dev/requests/) Starlette безпосередньо.
Це також означає, що якщо ви отримуєте дані безпосередньо з об'єкта `Request` (наприклад, читаєте тіло), FastAPI не буде їх перевіряти, перетворювати або документувати (через OpenAPI для автоматичного інтерфейсу користувача API).
Це також означає, що якщо ви отримуєте дані безпосередньо з об'єкта `Request` (наприклад, читаєте тіло), FastAPI не буде їх перевіряти, перетворювати або документувати (через OpenAPI для автоматичного інтерфейсу користувача API).
Докладніше про <ahref="https://www.starlette.dev/requests/"class="external-link"target="_blank">об'єкт `Request` на офіційному сайті документації Starlette</a>.
Докладніше про [об'єкт [`Request`] на офіційному сайті документації Starlette](https://www.starlette.dev/requests/).
**<ahref="https://fastapicloud.com"class="external-link"target="_blank">FastAPI Cloud</a>** створено тим самим автором і командою, що стоять за **FastAPI**.
**[FastAPI Cloud](https://fastapicloud.com)** створено тим самим автором і командою, що стоять за **FastAPI**.
Воно спрощує процес **створення**, **розгортання** та **доступу** до API з мінімальними зусиллями.
Воно спрощує процес **створення**, **розгортання** та **доступу** до API з мінімальними зусиллями.
@ -16,9 +16,9 @@ FastAPI Cloud є основним спонсором і джерелом фін
У [попередньому розділі про HTTPS](https.md){.internal-link target=_blank} ми дізналися, як HTTPS забезпечує шифрування для вашого API.
У [попередньому розділі про HTTPS](https.md) ми дізналися, як HTTPS забезпечує шифрування для вашого API.
Ми також бачили, що HTTPS зазвичай надається компонентом, **зовнішнім** щодо вашого серверного застосунку, - **TLS Termination Proxy**.
Ми також бачили, що HTTPS зазвичай надається компонентом, **зовнішнім** щодо вашого серверного застосунку, - **TLS Termination Proxy**.
@ -190,9 +190,9 @@
### Процеси-працівники і порти { #worker-processes-and-ports }
### Процеси-працівники і порти { #worker-processes-and-ports }
Пам'ятаєте з документації [Про HTTPS](https.md){.internal-link target=_blank}, що на сервері лише один процес може слухати певну комбінацію порту та IP-адреси?
Пам'ятаєте з документації [Про HTTPS](https.md), що на сервері лише один процес може слухати певну комбінацію порту та IP-адреси?
Це досі так.
Это досі так.
Отже, щоб мати **кілька процесів** одночасно, має бути **єдиний процес, який слухає порт**, і який далі якимось чином передає комунікацію кожному процесу-працівнику.
Отже, щоб мати **кілька процесів** одночасно, має бути **єдиний процес, який слухає порт**, і який далі якимось чином передає комунікацію кожному процесу-працівнику.
@ -243,7 +243,7 @@
Не хвилюйтеся, якщо деякі пункти про **контейнери**, Docker чи Kubernetes поки що не дуже зрозумілі.
Не хвилюйтеся, якщо деякі пункти про **контейнери**, Docker чи Kubernetes поки що не дуже зрозумілі.
Я розповім більше про образи контейнерів, Docker, Kubernetes тощо в майбутньому розділі: [FastAPI у контейнерах - Docker](docker.md){.internal-link target=_blank}.
Я розповім більше про образи контейнерів, Docker, Kubernetes тощо в майбутньому розділі: [FastAPI у контейнерах - Docker](docker.md).
///
///
@ -281,7 +281,7 @@
/// tip | Порада
/// tip | Порада
Я наведу більш конкретні приклади для цього з контейнерами у майбутньому розділі: [FastAPI у контейнерах - Docker](docker.md){.internal-link target=_blank}.
Я наведу більш конкретні приклади для цього з контейнерами у майбутньому розділі: [FastAPI у контейнерах - Docker](docker.md).
# FastAPI у контейнерах - Docker { #fastapi-in-containers-docker }
# FastAPI у контейнерах - Docker { #fastapi-in-containers-docker }
Під час розгортання застосунків FastAPI поширений підхід - збирати образи контейнерів Linux. Зазвичай це робиться за допомогою <ahref="https://www.docker.com/"class="external-link"target="_blank">Docker</a>. Потім ви можете розгорнути цей образ контейнера кількома різними способами.
Під час розгортання застосунків FastAPI поширений підхід - збирати образи контейнерів Linux. Зазвичай це робиться за допомогою [Docker](https://www.docker.com/). Потім ви можете розгорнути цей образ контейнера кількома різними способами.
Використання контейнерів Linux має кілька переваг, зокрема безпека, відтворюваність, простота та інші.
Використання контейнерів Linux має кілька переваг, зокрема безпека, відтворюваність, простота та інші.
Docker був одним з основних інструментів для створення та керування образами контейнерів і контейнерами.
Docker був одним з основних інструментів для створення та керування образами контейнерів і контейнерами.
Існує публічний <ahref="https://hub.docker.com/"class="external-link"target="_blank">Docker Hub</a> з готовими офіційними образами для багатьох інструментів, середовищ, баз даних і застосунків.
Існує публічний [Docker Hub](https://hub.docker.com/) з готовими офіційними образами для багатьох інструментів, середовищ, баз даних і застосунків.
Наприклад, є офіційний <ahref="https://hub.docker.com/_/python"class="external-link"target="_blank">образ Python</a>.
Наприклад, є офіційний [образ Python](https://hub.docker.com/_/python).
І є багато інших образів для різних речей, як-от бази даних, наприклад для:
І є багато інших образів для різних речей, як-от бази даних, наприклад для:
* <ahref="https://hub.docker.com/_/redis"class="external-link"target="_blank">Redis</a> тощо.
* [Redis](https://hub.docker.com/_/redis) тощо.
Використовуючи готовий образ контейнера, дуже легко поєднувати та використовувати різні інструменти. Наприклад, щоб випробувати нову базу даних. У більшості випадків ви можете використати офіційні образи та просто налаштувати їх змінними оточення.
Використовуючи готовий образ контейнера, дуже легко поєднувати та використовувати різні інструменти. Наприклад, щоб випробувати нову базу даних. У більшості випадків ви можете використати офіційні образи та просто налаштувати їх змінними оточення.
@ -111,7 +111,7 @@ Docker був одним з основних інструментів для с
Найпоширеніший спосіб - мати файл `requirements.txt` з назвами пакетів і їхніми версіями, по одному на рядок.
Найпоширеніший спосіб - мати файл `requirements.txt` з назвами пакетів і їхніми версіями, по одному на рядок.
Звісно, ви застосуєте ті самі ідеї з [Про версії FastAPI](versions.md){.internal-link target=_blank}, щоб задати діапазони версій.
Звісно, ви застосуєте ті самі ідеї з [Про версії FastAPI](versions.md), щоб задати діапазони версій.
Наприклад, ваш `requirements.txt` може виглядати так:
Наприклад, ваш `requirements.txt` може виглядати так:
#### Використовуйте `CMD` - exec form { #use-cmd-exec-form }
#### Використовуйте `CMD` - exec form { #use-cmd-exec-form }
Інструкцію Docker <ahref="https://docs.docker.com/reference/dockerfile/#cmd"class="external-link"target="_blank">`CMD`</a> можна записати у двох формах:
Інструкцію Docker [`CMD`](https://docs.docker.com/reference/dockerfile/#cmd) можна записати у двох формах:
Обов’язково завжди використовуйте exec form, щоб FastAPI міг коректно завершувати роботу та щоб були викликані [події тривалості життя](../advanced/events.md){.internal-link target=_blank}.
Обов’язково завжди використовуйте exec form, щоб FastAPI міг коректно завершувати роботу та щоб були викликані [події тривалості життя](../advanced/events.md).
Докладніше про це можна прочитати в <ahref="https://docs.docker.com/reference/dockerfile/#shell-and-exec-form"class="external-link"target="_blank">документації Docker про shell та exec form</a>.
Докладніше про це можна прочитати в [документації Docker про shell та exec form](https://docs.docker.com/reference/dockerfile/#shell-and-exec-form).
Це може бути особливо помітно при використанні `docker compose`. Див. розділ FAQ Docker Compose для технічних деталей: <ahref="https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop"class="external-link"target="_blank">Чому мої сервіси потребують 10 секунд, щоб пересотворитися або зупинитися?</a>.
Це може бути особливо помітно при використанні `docker compose`. Див. розділ FAQ Docker Compose для технічних деталей: [Чому мої сервіси потребують 10 секунд, щоб пересотворитися або зупинитися?](https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop).
#### Структура директорій { #directory-structure }
#### Структура директорій { #directory-structure }
Ви маєте змогу перевірити це за URL вашого Docker-контейнера, наприклад: <ahref="http://192.168.99.100/items/5?q=somequery"class="external-link"target="_blank">http://192.168.99.100/items/5?q=somequery</a> або <ahref="http://127.0.0.1/items/5?q=somequery"class="external-link"target="_blank">http://127.0.0.1/items/5?q=somequery</a> (або еквівалент, використовуючи ваш Docker-хост).
Ви маєте змогу перевірити це за URL вашого Docker-контейнера, наприклад: [http://192.168.99.100/items/5?q=somequery](http://192.168.99.100/items/5?q=somequery) або [http://127.0.0.1/items/5?q=somequery](http://127.0.0.1/items/5?q=somequery) (або еквівалент, використовуючи ваш Docker-хост).
## Інтерактивна документація API { #interactive-api-docs }
## Інтерактивна документація API { #interactive-api-docs }
Тепер ви можете перейти на <ahref="http://192.168.99.100/docs"class="external-link"target="_blank">http://192.168.99.100/docs</a> або <ahref="http://127.0.0.1/docs"class="external-link"target="_blank">http://127.0.0.1/docs</a> (або еквівалент, використовуючи ваш Docker-хост).
Тепер ви можете перейти на [http://192.168.99.100/docs](http://192.168.99.100/docs) або [http://127.0.0.1/docs](http://127.0.0.1/docs) (або еквівалент, використовуючи ваш Docker-хост).
Ви побачите автоматичну інтерактивну документацію API (надається <ahref="https://github.com/swagger-api/swagger-ui"class="external-link"target="_blank">Swagger UI</a>):
Ви побачите автоматичну інтерактивну документацію API (надається [Swagger UI](https://github.com/swagger-api/swagger-ui)):
## Альтернативна документація API { #alternative-api-docs }
## Альтернативна документація API { #alternative-api-docs }
Також ви можете перейти на <ahref="http://192.168.99.100/redoc"class="external-link"target="_blank">http://192.168.99.100/redoc</a> або <ahref="http://127.0.0.1/redoc"class="external-link"target="_blank">http://127.0.0.1/redoc</a> (або еквівалент, використовуючи ваш Docker-хост).
Також ви можете перейти на [http://192.168.99.100/redoc](http://192.168.99.100/redoc) або [http://127.0.0.1/redoc](http://127.0.0.1/redoc) (або еквівалент, використовуючи ваш Docker-хост).
Ви побачите альтернативну автоматичну документацію (надається <ahref="https://github.com/Rebilly/ReDoc"class="external-link"target="_blank">ReDoc</a>):
Ви побачите альтернативну автоматичну документацію (надається [ReDoc](https://github.com/Rebilly/ReDoc)):
Поговорімо знову про деякі з тих самих [Концепцій розгортання](concepts.md){.internal-link target=_blank} у термінах контейнерів.
Поговорімо знову про деякі з тих самих [Концепцій розгортання](concepts.md) у термінах контейнерів.
Контейнери - це переважно інструмент для спрощення процесу збирання та розгортання застосунку, але вони не нав’язують конкретний підхід до обробки цих концепцій розгортання, і існує кілька можливих стратегій.
Контейнери - це переважно інструмент для спрощення процесу збирання та розгортання застосунку, але вони не нав’язують конкретний підхід до обробки цих концепцій розгортання, і існує кілька можливих стратегій.
Якщо зосередитись лише на образі контейнера для застосунку FastAPI (а згодом на запущеному контейнері), HTTPS зазвичай обробляється зовнішнім іншим інструментом.
Якщо зосередитись лише на образі контейнера для застосунку FastAPI (а згодом на запущеному контейнері), HTTPS зазвичай обробляється зовнішнім іншим інструментом.
Це може бути інший контейнер, наприклад з <ahref="https://traefik.io/"class="external-link"target="_blank">Traefik</a>, що обробляє HTTPS і автоматичне отримання сертифікатів.
Це може бути інший контейнер, наприклад з [Traefik](https://traefik.io/), що обробляє HTTPS і автоматичне отримання сертифікатів.
Якщо ви використовуєте Kubernetes, це, ймовірно, буде <ahref="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/"class="external-link"target="_blank">Init Container</a>.
Якщо ви використовуєте Kubernetes, це, ймовірно, буде [Init Container](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/).
Колись існував офіційний образ Docker для FastAPI: <ahref="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker"class="external-link"target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>. Але зараз він застарілий. ⛔️
Колись існував офіційний образ Docker для FastAPI: [tiangolo/uvicorn-gunicorn-fastapi](https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker). Але зараз він застарілий. ⛔️
Ймовірно, вам не слід використовувати цей базовий образ Docker (або будь-який інший подібний).
Ймовірно, вам не слід використовувати цей базовий образ Docker (або будь-який інший подібний).
Якщо ви використовуєте <ahref="https://github.com/astral-sh/uv"class="external-link"target="_blank">uv</a> для встановлення та керування вашим проєктом, ви можете скористатися їхнім <ahref="https://docs.astral.sh/uv/guides/integration/docker/"class="external-link"target="_blank">посібником Docker для uv</a>.
Якщо ви використовуєте [uv](https://github.com/astral-sh/uv) для встановлення та керування вашим проєктом, ви можете скористатися їхнім [посібником Docker для uv](https://docs.astral.sh/uv/guides/integration/docker/).
Ви можете розгорнути свій застосунок FastAPI на <ahref="https://fastapicloud.com"class="external-link"target="_blank">FastAPI Cloud</a> однією командою, приєднуйтесь до списку очікування, якщо ще ні. 🚀
Ви можете розгорнути свій застосунок FastAPI на [FastAPI Cloud](https://fastapicloud.com) **однією командою**, приєднуйтесь до списку очікування, якщо ще ні. 🚀
## Вхід { #login }
## Вхід { #login }
@ -20,7 +20,7 @@ You are logged in to FastAPI Cloud 🚀
## Розгортання { #deploy }
## Розгортання { #deploy }
Тепер розгорніть свій застосунок однією командою:
Тепер розгорніть свій застосунок **однією командою**:
<divclass="termy">
<divclass="termy">
@ -40,7 +40,7 @@ Deploying to FastAPI Cloud...
## Про FastAPI Cloud { #about-fastapi-cloud }
## Про FastAPI Cloud { #about-fastapi-cloud }
**<ahref="https://fastapicloud.com"class="external-link"target="_blank">FastAPI Cloud</a>** створено тим самим автором і командою, що стоїть за **FastAPI**.
**[FastAPI Cloud](https://fastapicloud.com)** створено тим самим автором і командою, що стоїть за **FastAPI**.
Він спрощує процес **створення**, **розгортання** та **доступу** до API з мінімальними зусиллями.
Він спрощує процес **створення**, **розгортання** та **доступу** до API з мінімальними зусиллями.
Щоб вивчити основи HTTPS з точки зору споживача, перегляньте <ahref="https://howhttps.works/"class="external-link"target="_blank">https://howhttps.works/</a>.
Щоб **вивчити основи HTTPS** з точки зору споживача, перегляньте [https://howhttps.works/](https://howhttps.works/).
Тепер, з точки зору розробника, ось кілька речей, які варто пам'ятати, розмірковуючи про HTTPS:
Тепер, з **точки зору розробника**, ось кілька речей, які варто пам'ятати, розмірковуючи про HTTPS:
* Для HTTPS сервер має мати «сертифікати», видані третьою стороною.
* Для HTTPS **сервер** має **мати «сертифікати»**, видані **третьою стороною**.
* Насправді ці сертифікати «отримуються» у третьої сторони, а не «генеруються».
* Насправді ці сертифікати **«отримуються»** у третьої сторони, а не **«генеруються»**.
* Сертифікати мають строк дії.
* Сертифікати мають **строк дії**.
* Їхній строк дії спливає.
* Їхній строк дії **спливає**.
* І тоді їх потрібно поновити, знову отримавши у третьої сторони.
* І тоді їх потрібно **поновити**, **знову отримавши** у третьої сторони.
* Шифрування з'єднання відбувається на рівні TCP.
* Шифрування з'єднання відбувається на **рівні TCP**.
* Це один шар нижче від HTTP.
* Це один шар **нижче від HTTP**.
* Тож обробка сертифіката та шифрування виконується до HTTP.
* Тож **обробка сертифіката та шифрування** виконується **до HTTP**.
* TCP не знає про «домени». Лише про IP-адреси.
* **TCP не знає про «домени»**. Лише про IP-адреси.
* Інформація про конкретний домен, який запитується, міститься в даних HTTP.
* Інформація про **конкретний домен**, який запитується, міститься в **даних HTTP**.
* Сертифікати HTTPS «засвідчують» певний домен, але протокол і шифрування працюють на рівні TCP, до того як відомо, з яким доменом маємо справу.
* **Сертифікати HTTPS** «засвідчують» **певний домен**, але протокол і шифрування працюють на рівні TCP, **до того як відомо**, з яким доменом маємо справу.
* Типово це означало б, що на одну IP-адресу можна мати лише один сертифікат HTTPS.
* **Типово**, це означало б, що на одну IP-адресу можна мати **лише один сертифікат HTTPS**.
* Неважливо, наскільки великий ваш сервер або наскільки малий кожен застосунок на ньому.
* Неважливо, наскільки великий ваш сервер або наскільки малий кожен застосунок на ньому.
* Однак для цього є рішення.
* Однак для цього є **рішення**.
* Є розширення протоколу TLS (який обробляє шифрування на рівні TCP, до HTTP), що називається <ahref="https://en.wikipedia.org/wiki/Server_Name_Indication"class="external-link"target="_blank"><abbrtitle="Server Name Indication - Ідентифікація імені сервера">SNI</abbr></a>.
* Є **розширення** протоколу **TLS** (який обробляє шифрування на рівні TCP, до HTTP), що називається **[<abbr title="Server Name Indication - Ідентифікація імені сервера">SNI</abbr>](https://en.wikipedia.org/wiki/Server_Name_Indication)**.
* Це розширення SNI дозволяє одному серверу (з однією IP-адресою) мати кілька сертифікатів HTTPS і обслуговувати кілька доменів/застосунків по HTTPS.
* Це розширення SNI дозволяє одному серверу (з **однією IP-адресою**) мати **кілька сертифікатів HTTPS** і обслуговувати **кілька доменів/застосунків через HTTPS**.
* Щоб це працювало, один-єдиний компонент (програма), що працює на сервері та слухає публічну IP-адресу, має мати всі сертифікати HTTPS на сервері.
* Щоб це працювало, один-єдиний компонент (програма), що працює на сервері та слухає **публічну IP-адресу**, має мати **всі сертифікати HTTPS** на сервері.
* Після отримання захищеного з'єднання протокол обміну все ще HTTP.
* **Після** отримання захищеного з'єднання протокол обміну **залишається HTTP**.
* Вміст зашифровано, хоча він надсилається протоколом HTTP.
* Вміст **зашифровано**, хоча він надсилається з використанням **протоколу HTTP**.
Поширена практика мати одну програму/HTTP-сервер, що працює на сервері (машині, хості тощо) і керує всіма частинами HTTPS: приймає зашифровані HTTPS-запити, надсилає розшифровані HTTP-запити до фактичного HTTP-застосунку, що працює на тому ж сервері (у нашому випадку застосунок FastAPI), отримує HTTP-відповідь від застосунку, шифрує її за допомогою відповідного сертифіката HTTPS і надсилає її назад клієнту через HTTPS. Такий сервер часто називають <ahref="https://en.wikipedia.org/wiki/TLS_termination_proxy"class="external-link"target="_blank"><strong>TLS Termination Proxy</strong></a>.
Поширена практика мати **одну програму/HTTP-сервер**, що працює на сервері (машині, хості тощо) і **керує всіма частинами HTTPS**: приймає **зашифровані HTTPS-запити**, надсилає **розшифровані HTTP-запити** до фактичного HTTP-застосунку, що працює на тому ж сервері (у нашому випадку застосунок **FastAPI**), отримує **HTTP-відповідь** від застосунку, **шифрує її** за допомогою відповідного **сертифіката HTTPS** і надсилає її назад клієнту через **HTTPS**. Такий сервер часто називають **[TLS Termination Proxy](https://en.wikipedia.org/wiki/TLS_termination_proxy)**.
Деякі варіанти, які ви можете використати як TLS Termination Proxy:
Деякі варіанти, які ви можете використати як TLS Termination Proxy:
@ -45,17 +45,17 @@
## Let's Encrypt { #lets-encrypt }
## Let's Encrypt { #lets-encrypt }
До Let's Encrypt ці сертифікати HTTPS продавалися довіреними третіми сторонами.
До Let's Encrypt ці **сертифікати HTTPS** продавалися довіреними третіми сторонами.
Процес отримання одного з таких сертифікатів був громіздким, вимагав чимало паперової роботи, а самі сертифікати були доволі дорогими.
Процес отримання одного з таких сертифікатів був громіздким, вимагав чимало паперової роботи, а самі сертифікати були доволі дорогими.
Але потім з'явився проєкт <ahref="https://letsencrypt.org/"class="external-link"target="_blank">Let's Encrypt</a>.
Але потім з'явився проєкт **[Let's Encrypt](https://letsencrypt.org/)**.
Це проєкт Linux Foundation. Він надає сертифікати HTTPS безкоштовно, в автоматизований спосіб. Ці сертифікати використовують усі стандартні криптографічні механізми безпеки і є короткостроковими (близько 3 місяців), тож безпека насправді краща завдяки зменшеній тривалості життя.
Це проєкт Linux Foundation. Він надає **сертифікати HTTPS безкоштовно**, в автоматизований спосіб. Ці сертифікати використовують усі стандартні криптографічні механізми безпеки і є короткостроковими (близько 3 місяців), тож **безпека насправді краща** завдяки зменшеній тривалості життя.
Домени безпечно перевіряються, а сертифікати генеруються автоматично. Це також дозволяє автоматизувати поновлення цих сертифікатів.
Домени безпечно перевіряються, а сертифікати генеруються автоматично. Це також дозволяє автоматизувати поновлення цих сертифікатів.
Ідея полягає в автоматизації отримання та поновлення цих сертифікатів, щоб ви могли мати безпечний HTTPS безкоштовно та назавжди.
Ідея полягає в автоматизації отримання та поновлення цих сертифікатів, щоб ви могли мати **безпечний HTTPS, безкоштовно і назавжди**.
## HTTPS для розробників { #https-for-developers }
## HTTPS для розробників { #https-for-developers }
@ -63,11 +63,11 @@
### Доменне ім'я { #domain-name }
### Доменне ім'я { #domain-name }
Ймовірно, все почнеться з того, що ви придбаєте якесь доменне ім'я. Потім ви налаштуєте його на сервері DNS (можливо, у вашого ж хмарного провайдера).
Ймовірно, все почнеться з того, що ви **придбаєте** якесь **доменне ім'я**. Потім ви налаштуєте його на сервері DNS (можливо, у вашого ж хмарного провайдера).
Ви, скоріш за все, отримаєте хмарний сервер (віртуальну машину) або щось подібне, і він матиме <dfntitle="З часом не змінюється. Не динамічний.">фіксовану</dfn> публічну IP-адресу.
Ви, скоріш за все, отримаєте хмарний сервер (віртуальну машину) або щось подібне, і він матиме <dfntitle="З часом не змінюється. Не динамічний.">фіксовану</dfn>**публічну IP-адресу**.
На сервері(ах) DNS ви налаштуєте запис («`A record`»), щоб спрямувати ваш домен на публічну IP-адресу вашого сервера.
На сервері(ах) DNS ви налаштуєте запис («`A record`»), щоб спрямувати **ваш домен** на публічну **IP-адресу вашого сервера**.
Ймовірно, ви зробите це лише один раз, уперше, коли все налаштовуватимете.
Ймовірно, ви зробите це лише один раз, уперше, коли все налаштовуватимете.
@ -81,136 +81,136 @@
Тепер зосередьмося на всіх власне частинах HTTPS.
Тепер зосередьмося на всіх власне частинах HTTPS.
Спочатку браузер звернеться до серверів DNS, щоб дізнатися, яка IP-адреса для домену, у цьому випадку `someapp.example.com`.
Спочатку браузер звернеться до **DNS-серверів**, щоб дізнатися, яка **IP-адреса для домену**, у цьому випадку `someapp.example.com`.
Сервери DNS повідомлять браузеру використати конкретну IP-адресу. Це буде публічна IP-адреса, яку використовує ваш сервер і яку ви налаштували на серверах DNS.
Сервери DNS повідомлять браузеру використати конкретну **IP-адресу**. Це буде публічна IP-адреса, яку використовує ваш сервер і яку ви налаштували на серверах DNS.
Ця взаємодія між клієнтом і сервером для встановлення з'єднання TLS називається TLS рукостисканням.
Ця взаємодія між клієнтом і сервером для встановлення з'єднання TLS називається **TLS рукостисканням**.
### TLS із розширенням SNI { #tls-with-sni-extension }
### TLS із розширенням SNI { #tls-with-sni-extension }
Лише один процес на сервері може слухати конкретний порт на конкретній IP-адресі. Інші процеси можуть слухати інші порти на тій самій IP-адресі, але лише один для кожної комбінації IP-адреси та порту.
**Лише один процес** на сервері може слухати конкретний **порт** на конкретній **IP-адресі**. Інші процеси можуть слухати інші порти на тій самій IP-адресі, але лише один для кожної комбінації IP-адреси та порту.
TLS (HTTPS) за замовчуванням використовує конкретний порт `443`. Отже, це порт, який нам потрібен.
TLS (HTTPS) за замовчуванням використовує конкретний порт `443`. Отже, це порт, який нам потрібен.
Оскільки лише один процес може слухати цей порт, процесом, що робитиме це, буде TLS Termination Proxy.
Оскільки лише один процес може слухати цей порт, процесом, що робитиме це, буде **TLS Termination Proxy**.
TLS Termination Proxy матиме доступ до одного або кількох сертифікатів TLS (сертифікатів HTTPS).
TLS Termination Proxy матиме доступ до одного або кількох **сертифікатів TLS** (сертифікатів HTTPS).
Використовуючи обговорене вище розширення SNI, TLS Termination Proxy перевірить, який із наявних сертифікатів TLS (HTTPS) слід використати для цього з'єднання, обравши той, що відповідає домену, очікуваному клієнтом.
Використовуючи **розширення SNI**, обговорене вище, TLS Termination Proxy перевірить, який із наявних сертифікатів TLS (HTTPS) слід використати для цього з'єднання, обравши той, що відповідає домену, очікуваному клієнтом.
У цьому випадку він використає сертифікат для `someapp.example.com`.
У цьому випадку він використає сертифікат для `someapp.example.com`.
Клієнт уже довіряє сутності, яка видала цей сертифікат TLS (у цьому випадку Let's Encrypt, але про це згодом), тож він може перевірити, що сертифікат дійсний.
Клієнт уже **довіряє** сутності, яка видала цей сертифікат TLS (у цьому випадку Let's Encrypt, але про це згодом), тож він може **перевірити**, що сертифікат дійсний.
Потім, використовуючи сертифікат, клієнт і TLS Termination Proxy узгоджують, як шифрувати решту TCP-комунікації. На цьому частина TLS рукостискання завершується.
Потім, використовуючи сертифікат, клієнт і TLS Termination Proxy **вирішать, як шифрувати** решту **TCP-комунікації**. На цьому частина **TLS рукостискання** завершується.
Після цього клієнт і сервер мають зашифроване TCP-з'єднання - саме це надає TLS. І тоді вони можуть використати це з'єднання, щоб почати власне HTTP-комунікацію.
Після цього клієнт і сервер мають **зашифроване TCP-з'єднання** - саме це надає TLS. І тоді вони можуть використати це з'єднання, щоб почати власне **HTTP-комунікацію**.
І це і є HTTPS: це звичайний HTTP усередині захищеного TLS-з'єднання замість чистого (незашифрованого) TCP-з'єднання.
І це і є **HTTPS**: це звичайний **HTTP** усередині **захищеного TLS-з'єднання** замість чистого (незашифрованого) TCP-з'єднання.
/// tip | Порада
/// tip | Порада
Зверніть увагу, що шифрування комунікації відбувається на рівні TCP, а не на рівні HTTP.
Зверніть увагу, що шифрування комунікації відбувається на **рівні TCP**, а не на рівні HTTP.
///
///
### HTTPS-запит { #https-request }
### HTTPS-запит { #https-request }
Тепер, коли клієнт і сервер (конкретно браузер і TLS Termination Proxy) мають зашифроване TCP-з'єднання, вони можуть почати HTTP-комунікацію.
Тепер, коли клієнт і сервер (конкретно браузер і TLS Termination Proxy) мають **зашифроване TCP-з'єднання**, вони можуть почати **HTTP-комунікацію**.
Отже, клієнт надсилає HTTPS-запит. Це просто HTTP-запит через зашифроване TLS-з'єднання.
Отже, клієнт надсилає **HTTPS-запит**. Це просто HTTP-запит через зашифроване TLS-з'єднання.
TLS Termination Proxy використає узгоджене шифрування, щоб розшифрувати запит, і передасть звичайний (розшифрований) HTTP-запит процесу, що запускає застосунок (наприклад, процесу з Uvicorn, який запускає застосунок FastAPI).
TLS Termination Proxy використає узгоджене шифрування, щоб **розшифрувати запит**, і передасть **звичайний (розшифрований) HTTP-запит** процесу, що запускає застосунок (наприклад, процесу з Uvicorn, який запускає застосунок FastAPI).
Потім TLS Termination Proxy зашифрує відповідь, використовуючи попередньо узгоджену криптографію (що почалася із сертифіката для `someapp.example.com`), і надішле її назад у браузер.
Потім TLS Termination Proxy **зашифрує відповідь**, використовуючи попередньо узгоджену криптографію (що почалася із сертифіката для `someapp.example.com`), і надішле її назад у браузер.
Далі браузер перевірить, що відповідь дійсна й зашифрована правильним криптографічним ключем тощо. Потім він розшифрує відповідь і обробить її.
Далі браузер перевірить, що відповідь дійсна й зашифрована правильним криптографічним ключем тощо. Потім він **розшифрує відповідь** і обробить її.
Клієнт (браузер) знатиме, що відповідь надходить від правильного сервера, тому що використовується узгоджена раніше криптографія з використанням сертифіката HTTPS.
Клієнт (браузер) знатиме, що відповідь надходить від правильного сервера, тому що використовується узгоджена раніше криптографія з використанням **сертифіката HTTPS**.
### Кілька застосунків { #multiple-applications }
### Кілька застосунків { #multiple-applications }
На тому самому сервері (або серверах) може бути кілька застосунків, наприклад інші програми API або база даних.
На тому самому сервері (або серверах) може бути **кілька застосунків**, наприклад інші програми API або база даних.
Лише один процес може обробляти конкретну IP-адресу і порт (TLS Termination Proxy у нашому прикладі), але інші застосунки/процеси також можуть працювати на сервері(ах), доки вони не намагаються використати ту саму комбінацію публічної IP-адреси й порту.
Лише один процес може обробляти конкретну IP-адресу і порт (TLS Termination Proxy у нашому прикладі), але інші застосунки/процеси також можуть працювати на сервері(ах), доки вони не намагаються використати ту саму **комбінацію публічної IP-адреси й порту**.
Таким чином, TLS Termination Proxy може обробляти HTTPS і сертифікати для кількох доменів, для кількох застосунків, а потім передавати запити до відповідного застосунку в кожному випадку.
Таким чином, TLS Termination Proxy може обробляти HTTPS і сертифікати для **кількох доменів**, для кількох застосунків, а потім передавати запити до відповідного застосунку в кожному випадку.
У певний момент у майбутньому строк дії кожного сертифіката спливе (приблизно через 3 місяці після його отримання).
У певний момент у майбутньому строк дії кожного сертифіката **спливе** (приблизно через 3 місяці після його отримання).
Потім інша програма (в деяких випадках це інша програма, а в деяких - той самий TLS Termination Proxy) зв'яжеться з Let's Encrypt і поновить сертифікат(и).
Потім інша програма (в деяких випадках це інша програма, а в деяких - той самий TLS Termination Proxy) зв'яжеться з Let's Encrypt і поновить сертифікат(и).
<imgsrc="/img/deployment/https/https.drawio.svg">
<imgsrc="/img/deployment/https/https.drawio.svg">
Сертифікати TLS пов'язані з доменним іменем, а не з IP-адресою.
**Сертифікати TLS** пов'язані **з доменним іменем**, а не з IP-адресою.
Тому, щоб поновити сертифікати, програма поновлення має довести авторитету (Let's Encrypt), що вона справді «володіє» і контролює цей домен.
Тому, щоб поновити сертифікати, програма поновлення має **довести** авторитету (Let's Encrypt), що вона справді **«володіє» і контролює цей домен**.
Щоб зробити це й задовольнити різні потреби застосунків, є кілька способів. Деякі популярні:
Щоб зробити це й задовольнити різні потреби застосунків, є кілька способів. Деякі популярні:
* Змінити деякі записи DNS.
* **Змінити деякі записи DNS**.
* Для цього програма поновлення має підтримувати API провайдера DNS, тож залежно від того, якого провайдера DNS ви використовуєте, це може бути або не бути варіантом.
* Для цього програма поновлення має підтримувати API провайдера DNS, тож залежно від того, якого провайдера DNS ви використовуєте, це може бути або не бути варіантом.
* Запуститися як сервер (принаймні під час процесу отримання сертифіката) на публічній IP-адресі, пов'язаній із доменом.
* **Запуститися як сервер** (принаймні під час процесу отримання сертифіката) на публічній IP-адресі, пов'язаній із доменом.
* Як ми казали вище, лише один процес може слухати конкретну IP-адресу та порт.
* Як ми казали вище, лише один процес може слухати конкретну IP-адресу та порт.
* Це одна з причин, чому дуже зручно, коли той самий TLS Termination Proxy також займається процесом поновлення сертифікатів.
* Це одна з причин, чому дуже зручно, коли той самий TLS Termination Proxy також займається процесом поновлення сертифікатів.
* Інакше вам, можливо, доведеться на мить зупинити TLS Termination Proxy, запустити програму поновлення, щоб отримати сертифікати, потім налаштувати їх у TLS Termination Proxy і перезапустити TLS Termination Proxy. Це неідеально, оскільки ваші застосунки будуть недоступні під час вимкнення TLS Termination Proxy.
* Інакше вам, можливо, доведеться на мить зупинити TLS Termination Proxy, запустити програму поновлення, щоб отримати сертифікати, потім налаштувати їх у TLS Termination Proxy і перезапустити TLS Termination Proxy. Це неідеально, оскільки ваші застосунки будуть недоступні під час вимкнення TLS Termination Proxy.
Увесь цей процес поновлення, паралельно з обслуговуванням застосунку, - одна з головних причин, чому ви можете захотіти мати окрему систему для обробки HTTPS за допомогою TLS Termination Proxy замість того, щоб просто використовувати сертифікати TLS безпосередньо з сервером застосунку (наприклад, Uvicorn).
Увесь цей процес поновлення, паралельно з обслуговуванням застосунку, - одна з головних причин, чому ви можете захотіти мати **окрему систему для обробки 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, домен тощо.
Так застосунок зможе знати свою публічну URL-адресу, чи використовує він HTTPS, домен тощо.
Наявність HTTPS дуже важлива і в більшості випадків критична. Більшість зусиль, які вам як розробнику доведеться докласти навколо HTTPS, полягають лише в розумінні цих концепцій і того, як вони працюють.
Наявність **HTTPS** дуже важлива і в більшості випадків **критична**. Більшість зусиль, які вам як розробнику доведеться докласти навколо HTTPS, полягають лише в **розумінні цих концепцій** і того, як вони працюють.
Але як тільки ви знаєте базову інформацію про HTTPS для розробників, ви можете легко комбінувати й налаштовувати різні інструменти, щоб керувати всім просто.
Але як тільки ви знаєте базову інформацію про **HTTPS для розробників**, ви можете легко комбінувати й налаштовувати різні інструменти, щоб керувати всім просто.
У деяких наступних розділах я покажу кілька конкретних прикладів налаштування HTTPS для застосунків FastAPI. 🔒
У деяких наступних розділах я покажу кілька конкретних прикладів налаштування **HTTPS** для застосунків **FastAPI**. 🔒
Ви можете розгорнути сервер самостійно, використовуючи комбінацію інструментів, можете скористатися **хмарним сервісом**, який виконує частину роботи за вас, або обрати інші варіанти.
Ви можете розгорнути сервер самостійно, використовуючи комбінацію інструментів, можете скористатися **хмарним сервісом**, який виконує частину роботи за вас, або обрати інші варіанти.
Наприклад, ми, команда, що стоїть за FastAPI, створили <ahref="https://fastapicloud.com"class="external-link"target="_blank">**FastAPI Cloud**</a>, щоб зробити розгортання застосунків FastAPI у хмарі якомога простішим і з тим самим досвідом розробки, що й під час роботи з FastAPI.
Наприклад, ми, команда, що стоїть за FastAPI, створили [**FastAPI Cloud**](https://fastapicloud.com), щоб зробити розгортання застосунків FastAPI у хмарі якомога простішим і з тим самим досвідом розробки, що й під час роботи з FastAPI.
Я покажу вам кілька основних концепцій, про які, ймовірно, варто пам'ятати під час розгортання **FastAPI**-застосунку (хоча більшість із них стосується будь-яких інших типів веб-застосунків).
Я покажу вам кілька основних концепцій, про які, ймовірно, варто пам'ятати під час розгортання **FastAPI**-застосунку (хоча більшість із них стосується будь-яких інших типів веб-застосунків).
* <ahref="https://hypercorn.readthedocs.io/"class="external-link"target="_blank">Hypercorn</a>: ASGI-сервер, сумісний з HTTP/2 і Trio, серед інших можливостей.
* [Hypercorn](https://hypercorn.readthedocs.io/): ASGI-сервер, сумісний з HTTP/2 і Trio, серед інших можливостей.
* <ahref="https://github.com/django/daphne"class="external-link"target="_blank">Daphne</a>: ASGI-сервер, створений для Django Channels.
* [Daphne](https://github.com/django/daphne): ASGI-сервер, створений для Django Channels.
* <ahref="https://github.com/emmett-framework/granian"class="external-link"target="_blank">Granian</a>: Rust HTTP-сервер для Python-застосунків.
* [Granian](https://github.com/emmett-framework/granian): Rust HTTP-сервер для Python-застосунків.
* <ahref="https://unit.nginx.org/howto/fastapi/"class="external-link"target="_blank">NGINX Unit</a>: NGINX Unit - легке й універсальне середовище виконання вебзастосунків.
* [NGINX Unit](https://unit.nginx.org/howto/fastapi/): NGINX Unit - легке й універсальне середовище виконання вебзастосунків.
## Серверна машина і серверна програма { #server-machine-and-server-program }
## Серверна машина і серверна програма { #server-machine-and-server-program }
@ -74,7 +74,7 @@ FastAPI використовує стандарт для побудови Python
Але ви також можете встановити ASGI-сервер вручну.
Але ви також можете встановити ASGI-сервер вручну.
Переконайтеся, що ви створили [віртуальне оточення](../virtual-environments.md){.internal-link target=_blank}, активували його, після чого можете встановити серверну програму.
Переконайтеся, що ви створили [віртуальне оточення](../virtual-environments.md), активували його, після чого можете встановити серверну програму.
Наприклад, щоб установити Uvicorn:
Наприклад, щоб установити Uvicorn:
@ -137,7 +137,7 @@ Uvicorn та інші сервери підтримують опцію `--reload
Опція `--reload` споживає значно більше ресурсів, є менш стабільною тощо.
Опція `--reload` споживає значно більше ресурсів, є менш стабільною тощо.
Вона дуже допомагає під час розробки, але її не слід використовувати в продакшні.
Вона дуже допомагає під час **розробки**, але її **не слід** використовувати в **продакшні**.
- **Реплікація (кількість процесів, що виконуються)**
- Пам'ять
- Пам'ять
- Попередні кроки перед запуском
- Попередні кроки перед запуском
@ -13,13 +13,13 @@
Під час розгортання застосунків ви, найімовірніше, захочете мати реплікацію процесів, щоб використовувати кілька ядер і обробляти більше запитів.
Під час розгортання застосунків ви, найімовірніше, захочете мати реплікацію процесів, щоб використовувати кілька ядер і обробляти більше запитів.
Як ви бачили в попередньому розділі про [Концепції розгортання](concepts.md){.internal-link target=_blank}, існує кілька стратегій, які можна використовувати.
Як ви бачили в попередньому розділі про [Концепції розгортання](concepts.md), існує кілька стратегій, які можна використовувати.
Тут я покажу, як використовувати Uvicorn із процесами-працівниками за допомогою команди `fastapi` або безпосередньо команди `uvicorn`.
Тут я покажу, як використовувати Uvicorn із процесами-працівниками за допомогою команди `fastapi` або безпосередньо команди `uvicorn`.
/// info | Інформація
/// info | Інформація
Якщо ви використовуєте контейнери, наприклад з Docker або Kubernetes, я розповім про це більше в наступному розділі: [FastAPI у контейнерах - Docker](docker.md){.internal-link target=_blank}.
Якщо ви використовуєте контейнери, наприклад з Docker або Kubernetes, я розповім про це більше в наступному розділі: [FastAPI у контейнерах - Docker](docker.md).
Зокрема, під час запуску в Kubernetes вам, найімовірніше, не варто використовувати працівників, натомість запускати один процес Uvicorn на контейнер. Але про це я розповім пізніше в тому розділі.
Зокрема, під час запуску в Kubernetes вам, найімовірніше, не варто використовувати працівників, натомість запускати один процес Uvicorn на контейнер. Але про це я розповім пізніше в тому розділі.
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Started server process <b>[</b><fontcolor="#34E2E2"><b>27368</b></font><b>]</b>
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Started server process <b>[</b><fontcolor="#34E2E2"><b>27368</b></font><b>]</b>
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Started server process <b>[</b><fontcolor="#34E2E2"><b>27369</b></font><b>]</b>
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Started server process <b>[</b><fontcolor="#34E2E2"><b>27369</b></font><b>]</b>
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Started server process <b>[</b><fontcolor="#34E2E2"><b>27370</b></font><b>]</b>
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Started server process <b>[</b><fontcolor="#34E2E2"><b>27370</b></font><b>]</b>
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Started server process <b>[</b><fontcolor="#34E2E2"><b>27367</b></font><b>]</b>
<spanstyle="background-color="#007166"><fontcolor="#D3D7CF"> INFO </font></span> Started server process <b>[</b><fontcolor="#34E2E2"><b>27367</b></font><b>]</b>
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Waiting for application startup.
<spanstyle="background-color="#007166"><fontcolor="#D3D7CF"> INFO </font></span> Waiting for application startup.
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Waiting for application startup.
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Waiting for application startup.
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Waiting for application startup.
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Waiting for application startup.
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Waiting for application startup.
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Waiting for application startup.
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Application startup complete.
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Application startup complete.
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Application startup complete.
<spanstyle="background-color="#007166"><fontcolor="#D3D7CF"> INFO </font></span> Application startup complete.
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Application startup complete.
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Application startup complete.
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Application startup complete.
<spanstyle="background-color:#007166"><fontcolor="#D3D7CF"> INFO </font></span> Application startup complete.
Із наведеного вище списку концепцій розгортання, використання працівників головним чином допоможе з частиною про реплікацію і трохи з перезапусками, але про інше все ще треба подбати:
Із наведеного вище списку концепцій розгортання, використання працівників головним чином допоможе з частиною про реплікацію і трохи з перезапусками, але про інше все ще треба подбати:
- Безпека - HTTPS
- **Безпека - HTTPS**
- Запуск під час старту
- **Запуск під час старту**
- ***Перезапуски***
- ***Перезапуски***
- Реплікація (кількість процесів, що виконуються)
- Реплікація (кількість процесів, що виконуються)
- Пам'ять
- **Пам'ять**
- Попередні кроки перед запуском
- **Попередні кроки перед запуском**
## Контейнери і Docker { #containers-and-docker }
## Контейнери і Docker { #containers-and-docker }
У наступному розділі про [FastAPI у контейнерах - Docker](docker.md){.internal-link target=_blank} я поясню кілька стратегій, які ви можете використати для інших концепцій розгортання.
У наступному розділі про [FastAPI у контейнерах - Docker](docker.md) я поясню кілька стратегій, які ви можете використати для інших концепцій розгортання.
Я покажу, як побудувати власний образ з нуля для запуску одного процесу Uvicorn. Це простий процес і, ймовірно, саме те, що потрібно при використанні розподіленої системи керування контейнерами, такої як Kubernetes.
Я покажу, як побудувати власний образ з нуля для запуску одного процесу Uvicorn. Це простий процес і, ймовірно, саме те, що потрібно при використанні розподіленої системи керування контейнерами, такої як Kubernetes.
Нові можливості додаються часто, помилки регулярно виправляються, а код постійно поліпшується.
Нові можливості додаються часто, помилки регулярно виправляються, а код постійно поліпшується.
Тому поточні версії все ще `0.x.x`, це відображає те, що кожна версія потенційно може містити несумісні зміни. Це відповідає правилам <ahref="https://semver.org/"class="external-link"target="_blank">Семантичного версіонування</a>.
Тому поточні версії все ще `0.x.x`, це відображає те, що кожна версія потенційно може містити несумісні зміни. Це відповідає правилам [Семантичного версіонування](https://semver.org/).
Ви можете створювати продакшн-застосунки з **FastAPI** вже зараз (і, ймовірно, робите це вже певний час), просто переконайтеся, що ви використовуєте версію, яка коректно працює з рештою вашого коду.
Ви можете створювати продакшн-застосунки з **FastAPI** вже зараз (і, ймовірно, робите це вже певний час), просто переконайтеся, що ви використовуєте версію, яка коректно працює з рештою вашого коду.
Ви можете переглянути доступні версії (наприклад, щоб перевірити поточну останню) в [Примітках до випусків](../release-notes.md){.internal-link target=_blank}.
Ви можете переглянути доступні версії (наприклад, щоб перевірити поточну останню) в [Примітках до випусків](../release-notes.md).
## Про версії { #about-versions }
## Про версії { #about-versions }
@ -66,7 +66,7 @@ fastapi>=0.45.0,<0.46.0
Ви повинні додати тести для вашого застосунку.
Ви повинні додати тести для вашого застосунку.
З **FastAPI** це дуже легко (завдяки Starlette), перегляньте документацію: [Тестування](../tutorial/testing.md){.internal-link target=_blank}
З **FastAPI** це дуже легко (завдяки Starlette), перегляньте документацію: [Тестування](../tutorial/testing.md)
Після того як у вас є тести, ви можете оновити версію **FastAPI** до новішої і переконатися, що весь ваш код працює правильно, запустивши тести.
Після того як у вас є тести, ви можете оновити версію **FastAPI** до новішої і переконатися, що весь ваш код працює правильно, запустивши тести.
До версії FastAPI `0.122.0`, коли інтегровані засоби безпеки повертали клієнту помилку після невдалої автентифікації, вони використовували HTTP код статусу `403 Forbidden`.
До версії FastAPI `0.122.0`, коли інтегровані засоби безпеки повертали клієнту помилку після невдалої автентифікації, вони використовували HTTP код статусу `403 Forbidden`.
Починаючи з версії FastAPI `0.122.0`, вони використовують більш доречний HTTP код статусу `401 Unauthorized` і повертають змістовний заголовок `WWW-Authenticate` у відповіді, відповідно до специфікацій HTTP, <ahref="https://datatracker.ietf.org/doc/html/rfc7235#section-3.1"class="external-link"target="_blank">RFC 7235</a>, <ahref="https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized"class="external-link"target="_blank">RFC 9110</a>.
Починаючи з версії FastAPI `0.122.0`, вони використовують більш доречний HTTP код статусу `401 Unauthorized` і повертають змістовний заголовок `WWW-Authenticate` у відповіді, відповідно до специфікацій HTTP, [RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235#section-3.1), [RFC 9110](https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized).
Але якщо з якоїсь причини ваші клієнти залежать від старої поведінки, ви можете повернутися до неї, переписавши метод `make_not_authenticated_error` у ваших класах безпеки.
Але якщо з якоїсь причини ваші клієнти залежать від старої поведінки, ви можете повернутися до неї, переписавши метод `make_not_authenticated_error` у ваших класах безпеки.
## Про безпеку, API та документацію { #about-security-apis-and-docs }
## Про безпеку, API та документацію { #about-security-apis-and-docs }
Приховування інтерфейсів документації у продукційному середовищі *не має* бути способом захисту вашого API.
Приховування інтерфейсів документації у продукційному середовищі не має бути способом захисту вашого API.
Це не додає жодної додаткової безпеки вашому API, *операції шляху* й надалі будуть доступні там, де вони є.
Це не додає жодної додаткової безпеки вашому API, операції шляху й надалі будуть доступні там, де вони є.
Якщо у вашому коді є вразливість, вона залишиться.
Якщо у вашому коді є вразливість, вона залишиться.
Приховування документації лише ускладнює розуміння того, як взаємодіяти з вашим API, і може ускладнити для вас його налагодження у продакшні. Це можна вважати просто формою <ahref="https://en.wikipedia.org/wiki/Security_through_obscurity"class="external-link"target="_blank">Безпека через неясність</a>.
Приховування документації лише ускладнює розуміння того, як взаємодіяти з вашим API, і може ускладнити для вас його налагодження у продакшні. Це можна вважати просто формою [Безпека через неясність](https://en.wikipedia.org/wiki/Security_through_obscurity).
Якщо ви хочете захистити ваш API, є кілька кращих дій, які ви можете зробити, наприклад:
Якщо ви хочете захистити ваш API, є кілька кращих дій, які ви можете зробити, наприклад:
Ви можете налаштувати додаткові <ahref="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/"class="external-link"target="_blank">параметри Swagger UI</a>.
Ви можете налаштувати додаткові [параметри Swagger UI](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/).
Щоб їх налаштувати, передайте аргумент `swagger_ui_parameters` під час створення об’єкта додатка `FastAPI()` або до функції `get_swagger_ui_html()`.
Щоб їх налаштувати, передайте аргумент `swagger_ui_parameters` під час створення об’єкта додатка `FastAPI()` або до функції `get_swagger_ui_html()`.
@ -50,7 +50,7 @@ FastAPI містить деякі параметри конфігурації з
## Інші параметри Swagger UI { #other-swagger-ui-parameters }
## Інші параметри Swagger UI { #other-swagger-ui-parameters }
Щоб побачити всі можливі налаштування, які ви можете використовувати, прочитайте офіційну <ahref="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/"class="external-link"target="_blank">документацію щодо параметрів Swagger UI</a>.
Щоб побачити всі можливі налаштування, які ви можете використовувати, прочитайте офіційну [документацію щодо параметрів Swagger UI](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/).
## Налаштування лише для JavaScript { #javascript-only-settings }
## Налаштування лише для JavaScript { #javascript-only-settings }
@ -54,7 +54,7 @@ Swagger UI впорається з цим «за лаштунками», але
### Перевірте { #test-it }
### Перевірте { #test-it }
Тепер ви маєте змогу відкрити документацію за <ahref="http://127.0.0.1:8000/docs"class="external-link"target="_blank">http://127.0.0.1:8000/docs</a> і перезавантажити сторінку, вона завантажить ці ресурси з нового CDN.
Тепер ви маєте змогу відкрити документацію за [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) і перезавантажити сторінку, вона завантажить ці ресурси з нового CDN.
## Самохостинг JavaScript і CSS для документації { #self-hosting-javascript-and-css-for-docs }
## Самохостинг JavaScript і CSS для документації { #self-hosting-javascript-and-css-for-docs }
@ -93,12 +93,12 @@ Swagger UI впорається з цим «за лаштунками», але
Запустіть ваш застосунок і перейдіть до <ahref="http://127.0.0.1:8000/static/redoc.standalone.js"class="external-link"target="_blank">http://127.0.0.1:8000/static/redoc.standalone.js</a>.
Запустіть ваш застосунок і перейдіть до [http://127.0.0.1:8000/static/redoc.standalone.js](http://127.0.0.1:8000/static/redoc.standalone.js).
Ви маєте побачити дуже довгий файл JavaScript для **ReDoc**.
Ви маєте побачити дуже довгий файл JavaScript для **ReDoc**.
@ -180,6 +180,6 @@ Swagger UI впорається з цим «за лаштунками», але
### Перевірте UI зі статичними файлами { #test-static-files-ui }
### Перевірте UI зі статичними файлами { #test-static-files-ui }
Тепер ви маєте змогу вимкнути WiFi, відкрити документацію за <ahref="http://127.0.0.1:8000/docs"class="external-link"target="_blank">http://127.0.0.1:8000/docs</a> і перезавантажити сторінку.
Тепер ви маєте змогу вимкнути WiFi, відкрити документацію за [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) і перезавантажити сторінку.
І навіть без Інтернету ви зможете побачити документацію для вашого API і взаємодіяти з ним.
І навіть без Інтернету ви зможете побачити документацію для вашого API і взаємодіяти з ним.
- Перетворення не-JSON тіл запитів на JSON (наприклад, <ahref="https://msgpack.org/index.html"class="external-link"target="_blank">`msgpack`</a>).
- Перетворення не-JSON тіл запитів на JSON (наприклад, [`msgpack`](https://msgpack.org/index.html)).
- Розпакування тіл запитів, стиснених gzip.
- Розпакування тіл запитів, стиснених gzip.
- Автоматичне логування всіх тіл запитів.
- Автоматичне логування всіх тіл запитів.
@ -32,7 +32,7 @@
/// tip | Порада
/// tip | Порада
Це навчальний приклад, щоб продемонструвати принцип роботи. Якщо вам потрібна підтримка Gzip, скористайтеся вбудованим [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware){.internal-link target=_blank}.
Це навчальний приклад, щоб продемонструвати принцип роботи. Якщо вам потрібна підтримка Gzip, скористайтеся вбудованим [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware).
///
///
@ -66,7 +66,7 @@
І саме ці дві сутності - `scope` та `receive` - потрібні для створення нового екземпляра `Request`.
І саме ці дві сутності - `scope` та `receive` - потрібні для створення нового екземпляра `Request`.
Щоб дізнатися більше про `Request`, перегляньте <ahref="https://www.starlette.dev/requests/"class="external-link"target="_blank">документацію Starlette про запити</a>.
Щоб дізнатися більше про `Request`, перегляньте [документацію Starlette про запити](https://www.starlette.dev/requests/).
///
///
@ -82,7 +82,7 @@
/// tip | Порада
/// tip | Порада
Щоб розв’язати це саме завдання, скоріш за все, простіше використати `body` у користувацькому обробнику `RequestValidationError` ([Обробка помилок](../tutorial/handling-errors.md#use-the-requestvalidationerror-body){.internal-link target=_blank}).
Щоб розв’язати це саме завдання, скоріш за все, простіше використати `body` у користувацькому обробнику `RequestValidationError` ([Обробка помилок](../tutorial/handling-errors.md#use-the-requestvalidationerror-body)).
Але цей приклад усе ще корисний і показує, як взаємодіяти з внутрішніми компонентами.
Але цей приклад усе ще корисний і показує, як взаємодіяти з внутрішніми компонентами.
Використовуючи наведене вище, ви можете скористатися тією ж утилітарною функцією для генерації схеми OpenAPI і переписати потрібні частини.
Використовуючи наведене вище, ви можете скористатися тією ж утилітарною функцією для генерації схеми OpenAPI і переписати потрібні частини.
Наприклад, додаймо <ahref="https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo"class="external-link"target="_blank">розширення OpenAPI для ReDoc для додавання власного логотипа</a>.
Наприклад, додаймо [розширення OpenAPI ReDoc для додавання власного логотипа](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo).
### Звичайний **FastAPI** { #normal-fastapi }
### Звичайний **FastAPI** { #normal-fastapi }
@ -75,6 +75,6 @@
### Перевірте { #check-it }
### Перевірте { #check-it }
Коли ви перейдете за адресою <ahref="http://127.0.0.1:8000/redoc"class="external-link"target="_blank">http://127.0.0.1:8000/redoc</a>, побачите, що використовується ваш власний логотип (у цьому прикладі логотип **FastAPI**):
Коли ви перейдете за адресою [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc), побачите, що використовується ваш власний логотип (у цьому прикладі логотип **FastAPI**):
## Фільтрування даних - Безпека { #filter-data-security }
## Фільтрування даних - Безпека { #filter-data-security }
Щоб гарантувати, що ви не повертаєте більше даних, ніж слід, прочитайте документацію [Навчальний посібник - Модель відповіді - Тип повернення](../tutorial/response-model.md){.internal-link target=_blank}.
Щоб гарантувати, що ви не повертаєте більше даних, ніж слід, прочитайте документацію [Навчальний посібник - Модель відповіді - Тип повернення](../tutorial/response-model.md).
## Оптимізувати продуктивність відповіді - Модель відповіді - Тип повернення { #optimize-response-performance-response-model-return-type }
Щоб оптимізувати продуктивність під час повернення даних JSON, використовуйте тип повернення або модель відповіді, таким чином Pydantic виконуватиме серіалізацію в JSON на боці Rust, без проходження через Python. Докладніше читайте в документації [Навчальний посібник - Модель відповіді - Тип повернення](../tutorial/response-model.md).
Щоб додати мітки до ваших *операцій шляху* та згрупувати їх в інтерфейсі документації, прочитайте документацію [Навчальний посібник - Налаштування операції шляху - Мітки](../tutorial/path-operation-configuration.md#tags){.internal-link target=_blank}.
Щоб додати мітки до ваших *операцій шляху* та згрупувати їх в інтерфейсі документації, прочитайте документацію [Навчальний посібник - Налаштування операції шляху - Мітки](../tutorial/path-operation-configuration.md#tags).
## Короткий опис і опис - OpenAPI { #documentation-summary-and-description-openapi }
## Короткий опис і опис - OpenAPI { #documentation-summary-and-description-openapi }
Щоб додати короткий опис і опис до ваших *операцій шляху* і показати їх в інтерфейсі документації, прочитайте документацію [Навчальний посібник - Налаштування операції шляху - Короткий опис і опис](../tutorial/path-operation-configuration.md#summary-and-description){.internal-link target=_blank}.
Щоб додати короткий опис і опис до ваших *операцій шляху* і показати їх в інтерфейсі документації, прочитайте документацію [Навчальний посібник - Налаштування операції шляху - Короткий опис і опис](../tutorial/path-operation-configuration.md#summary-and-description).
## Опис відповіді в документації - OpenAPI { #documentation-response-description-openapi }
## Опис відповіді в документації - OpenAPI { #documentation-response-description-openapi }
Щоб визначити опис відповіді, що відображається в інтерфейсі документації, прочитайте документацію [Навчальний посібник - Налаштування операції шляху - Опис відповіді](../tutorial/path-operation-configuration.md#response-description){.internal-link target=_blank}.
Щоб визначити опис відповіді, що відображається в інтерфейсі документації, прочитайте документацію [Навчальний посібник - Налаштування операції шляху - Опис відповіді](../tutorial/path-operation-configuration.md#response-description).
Щоб позначити *операцію шляху* як застарілу і показати це в інтерфейсі документації, прочитайте документацію [Навчальний посібник - Налаштування операції шляху - Позначення як застаріле](../tutorial/path-operation-configuration.md#deprecate-a-path-operation){.internal-link target=_blank}.
Щоб позначити *операцію шляху* як застарілу і показати це в інтерфейсі документації, прочитайте документацію [Навчальний посібник - Налаштування операції шляху - Позначення як застаріле](../tutorial/path-operation-configuration.md#deprecate-a-path-operation).
## Перетворити будь-які дані на сумісні з JSON { #convert-any-data-to-json-compatible }
## Перетворити будь-які дані на сумісні з JSON { #convert-any-data-to-json-compatible }
Щоб перетворити будь-які дані на сумісні з JSON, прочитайте документацію [Навчальний посібник - Кодувальник, сумісний з JSON](../tutorial/encoder.md){.internal-link target=_blank}.
Щоб перетворити будь-які дані на сумісні з JSON, прочитайте документацію [Навчальний посібник - Кодувальник, сумісний з JSON](../tutorial/encoder.md).
Щоб додати метадані до вашої схеми OpenAPI, зокрема ліцензію, версію, контактні дані тощо, прочитайте документацію [Навчальний посібник - Метадані та URL документації](../tutorial/metadata.md){.internal-link target=_blank}.
Щоб додати метадані до вашої схеми OpenAPI, зокрема ліцензію, версію, контактні дані тощо, прочитайте документацію [Навчальний посібник - Метадані та URL документації](../tutorial/metadata.md).
## Власний URL OpenAPI { #openapi-custom-url }
## Власний URL OpenAPI { #openapi-custom-url }
Щоб налаштувати URL OpenAPI (або прибрати його), прочитайте документацію [Навчальний посібник - Метадані та URL документації](../tutorial/metadata.md#openapi-url){.internal-link target=_blank}.
Щоб налаштувати URL OpenAPI (або прибрати його), прочитайте документацію [Навчальний посібник - Метадані та URL документації](../tutorial/metadata.md#openapi-url).
Щоб оновити URL, які використовуються для автоматично згенерованих інтерфейсів користувача документації, прочитайте документацію [Навчальний посібник - Метадані та URL документації](../tutorial/metadata.md#docs-urls){.internal-link target=_blank}.
Щоб оновити URL, які використовуються для автоматично згенерованих інтерфейсів користувача документації, прочитайте документацію [Навчальний посібник - Метадані та URL документації](../tutorial/metadata.md#docs-urls).
* З <ahref="https://github.com/ciscorn/starlette-graphene3"class="external-link"target="_blank">starlette-graphene3</a>
* З [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3)
## GraphQL зі Strawberry { #graphql-with-strawberry }
## GraphQL зі Strawberry { #graphql-with-strawberry }
Якщо вам потрібен або ви хочете використовувати GraphQL, <ahref="https://strawberry.rocks/"class="external-link"target="_blank">Strawberry</a> - рекомендована бібліотека, адже її дизайн найближчий до дизайну FastAPI; усе базується на анотаціях типів.
Якщо вам потрібен або ви хочете використовувати GraphQL, [Strawberry](https://strawberry.rocks/) - рекомендована бібліотека, адже її дизайн найближчий до дизайну FastAPI; усе базується на анотаціях типів.
Залежно від вашого сценарію використання ви можете надати перевагу іншій бібліотеці, але якби ви запитали мене, я, ймовірно, порадив би спробувати Strawberry.
Залежно від вашого сценарію використання ви можете надати перевагу іншій бібліотеці, але якби ви запитали мене, я, ймовірно, порадив би спробувати Strawberry.
@ -37,24 +37,24 @@ GraphQL розв’язує деякі дуже специфічні сцена
Більше про Strawberry ви можете дізнатися в <ahref="https://strawberry.rocks/"class="external-link"target="_blank">документації Strawberry</a>.
Більше про Strawberry ви можете дізнатися в [документації Strawberry](https://strawberry.rocks/).
І також <ahref="https://strawberry.rocks/docs/integrations/fastapi"class="external-link"target="_blank">документацію про Strawberry з FastAPI</a>.
І також [документацію про Strawberry з FastAPI](https://strawberry.rocks/docs/integrations/fastapi).
## Застарілий `GraphQLApp` зі Starlette { #older-graphqlapp-from-starlette }
## Застарілий `GraphQLApp` зі Starlette { #older-graphqlapp-from-starlette }
Попередні версії Starlette містили клас `GraphQLApp` для інтеграції з <ahref="https://graphene-python.org/"class="external-link"target="_blank">Graphene</a>.
Попередні версії Starlette містили клас `GraphQLApp` для інтеграції з [Graphene](https://graphene-python.org/).
Його вилучено з Starlette як застарілий, але якщо у вас є код, що його використовував, ви можете легко мігрувати на <ahref="https://github.com/ciscorn/starlette-graphene3"class="external-link"target="_blank">starlette-graphene3</a>, який покриває той самий сценарій використання та має майже ідентичний інтерфейс.
Його вилучено з Starlette як застарілий, але якщо у вас є код, що його використовував, ви можете легко мігрувати на [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3), який покриває той самий сценарій використання та має майже ідентичний інтерфейс.
/// tip | Порада
/// tip | Порада
Якщо вам потрібен GraphQL, я все ж рекомендую звернути увагу на <ahref="https://strawberry.rocks/"class="external-link"target="_blank">Strawberry</a>, адже він базується на анотаціях типів, а не на власних класах і типах.
Якщо вам потрібен GraphQL, я все ж рекомендую звернути увагу на [Strawberry](https://strawberry.rocks/), адже він базується на анотаціях типів, а не на власних класах і типах.
///
///
## Дізнайтеся більше { #learn-more }
## Дізнайтеся більше { #learn-more }
Ви можете дізнатися більше про GraphQL в <ahref="https://graphql.org/"class="external-link"target="_blank">офіційній документації GraphQL</a>.
Ви можете дізнатися більше про GraphQL в [офіційній документації GraphQL](https://graphql.org/).
Також ви можете почитати більше про кожну з цих бібліотек за наведеними посиланнями.
Також ви можете почитати більше про кожну з цих бібліотек за наведеними посиланнями.
Якщо ви хочете **вивчити FastAPI** у структурований спосіб (рекомендується), натомість прочитайте [Навчальний посібник - Посібник користувача](../tutorial/index.md){.internal-link target=_blank} розділ за розділом.
Якщо ви хочете **вивчити FastAPI** у структурований спосіб (рекомендується), натомість прочитайте [Навчальний посібник - Посібник користувача](../tutorial/index.md) розділ за розділом.
Переконайтеся, що у вашій програмі є [тести](../tutorial/testing.md){.internal-link target=_blank} і що ви запускаєте їх у системі безперервної інтеграції (CI).
Переконайтеся, що у вашій програмі є [тести](../tutorial/testing.md) і що ви запускаєте їх у системі безперервної інтеграції (CI).
Так ви зможете виконати оновлення і впевнитися, що все працює як очікується.
Так ви зможете виконати оновлення і впевнитися, що все працює як очікується.
У багатьох випадках, якщо ви використовуєте звичайні моделі Pydantic без налаштувань, більшу частину процесу міграції з Pydantic v1 на Pydantic v2 можна автоматизувати.
У багатьох випадках, якщо ви використовуєте звичайні моделі Pydantic без налаштувань, більшу частину процесу міграції з Pydantic v1 на Pydantic v2 можна автоматизувати.
Ви можете скористатися <ahref="https://github.com/pydantic/bump-pydantic"class="external-link"target="_blank">`bump-pydantic`</a> від тієї ж команди Pydantic.
Ви можете скористатися [`bump-pydantic`](https://github.com/pydantic/bump-pydantic) від тієї ж команди Pydantic.
Цей інструмент допоможе автоматично змінити більшість коду, який потрібно змінити.
Цей інструмент допоможе автоматично змінити більшість коду, який потрібно змінити.
Ви можете ознайомитися з базами даних, SQL і SQLModel у <ahref="https://sqlmodel.tiangolo.com/"class="external-link"target="_blank">документації SQLModel</a>. 🤓
Ви можете ознайомитися з базами даних, SQL і SQLModel у [документації SQLModel](https://sqlmodel.tiangolo.com/). 🤓
Є невеликий <ahref="https://sqlmodel.tiangolo.com/tutorial/fastapi/"class="external-link"target="_blank">навчальний посібник про використання SQLModel з FastAPI</a>. ✨
Є невеликий [навчальний посібник про використання SQLModel з FastAPI](https://sqlmodel.tiangolo.com/tutorial/fastapi/). ✨
Цей навчальний посібник містить розділ про <ahref="https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/"class="external-link"target="_blank">тестування баз даних SQL</a>. 😎
Цей навчальний посібник містить розділ про [тестування баз даних SQL](https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/). 😎
@ -57,7 +57,7 @@ FastAPI додав підтримку `Annotated` (і почав її реком
Якщо у вас старіша версія, ви отримаєте помилки при спробі використати `Annotated`.
Якщо у вас старіша версія, ви отримаєте помилки при спробі використати `Annotated`.
Переконайтеся, що ви [Оновіть версію FastAPI](../../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} щонайменше до 0.95.1 перед використанням `Annotated`.
Переконайтеся, що ви [Оновіть версію FastAPI](../../deployment/versions.md#upgrading-the-fastapi-versions) щонайменше до 0.95.1 перед використанням `Annotated`.
Якщо ви не впевнені, перегляньте розділ [Async: *"In a hurry?"*](../../async.md#in-a-hurry){.internal-link target=_blank} про `async` і `await` у документації.
Якщо ви не впевнені, перегляньте розділ [Async: *"In a hurry?"*](../../async.md#in-a-hurry) про `async` і `await` у документації.