Залежності¶
🌐 Переклад ШІ та людьми
Цей переклад виконано ШІ під керівництвом людей. 🤝
Можливі помилки через неправильне розуміння початкового змісту або неприродні формулювання тощо. 🤖
Ви можете покращити цей переклад, допомігши нам краще спрямовувати AI LLM.
FastAPI має дуже потужну, але інтуїтивну систему Впровадження залежностей.
Вона створена так, щоб бути дуже простою у використанні та щоб полегшити будь-якому розробнику інтеграцію інших компонентів з FastAPI.
Що таке «Впровадження залежностей»¶
У програмуванні «Впровадження залежностей» означає, що існує спосіб для вашого коду (у цьому випадку ваших функцій операцій шляху) задекларувати речі, які йому потрібні для роботи: «залежності».
А потім ця система (у цьому випадку FastAPI) подбає про все необхідне, щоб надати вашому коду ці потрібні залежності («інжектувати» залежності).
Це дуже корисно, коли вам потрібно:
- Мати спільну логіку (одна й та сама логіка знову і знову).
- Ділитися з’єднаннями з базою даних.
- Примусово застосовувати безпеку, автентифікацію, вимоги до ролей тощо.
- І багато іншого...
Все це з мінімізацією дублювання коду.
Перші кроки¶
Розгляньмо дуже простий приклад. Він буде таким простим, що поки що не дуже корисним.
Але так ми зможемо зосередитися на тому, як працює система Впровадження залежностей.
Створіть залежність або «залежний»¶
Спочатку зосередьмося на залежності.
Це просто функція, яка може приймати ті самі параметри, що й функція операції шляху:
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
return commons
@app.get("/users/")
async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
return commons
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
return commons
@app.get("/users/")
async def read_users(commons: dict = Depends(common_parameters)):
return commons
Ось і все.
2 рядки.
І вона має ту саму форму та структуру, що й усі ваші функції операцій шляху.
Можете думати про неї як про функцію операції шляху без «декоратора» (без @app.get("/some-path")).
І вона може повертати будь-що.
У цьому випадку ця залежність очікує:
- Необов’язковий параметр запиту
qтипуstr. - Необов’язковий параметр запиту
skipтипуint, за замовчуванням0. - Необов’язковий параметр запиту
limitтипуint, за замовчуванням100.
Потім вона просто повертає dict, що містить ці значення.
Інформація
FastAPI додав підтримку Annotated (і почав її рекомендувати) у версії 0.95.0.
Якщо у вас старіша версія, ви отримаєте помилки при спробі використати Annotated.
Переконайтеся, що ви Оновіть версію FastAPI щонайменше до 0.95.1 перед використанням Annotated.
Імпортуйте Depends¶
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
return commons
@app.get("/users/")
async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
return commons
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
return commons
@app.get("/users/")
async def read_users(commons: dict = Depends(common_parameters)):
return commons
Оголосіть залежність у «залежному»¶
Так само, як ви використовуєте Body, Query тощо з параметрами вашої функції операції шляху, використовуйте Depends з новим параметром:
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
return commons
@app.get("/users/")
async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
return commons
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
return commons
@app.get("/users/")
async def read_users(commons: dict = Depends(common_parameters)):
return commons
Хоча ви використовуєте Depends у параметрах вашої функції так само, як Body, Query тощо, Depends працює трохи інакше.
Ви передаєте в Depends лише один параметр.
Цей параметр має бути чимось на кшталт функції.
Ви її не викликаєте безпосередньо (не додавайте дужки в кінці), ви просто передаєте її як параметр у Depends().
І ця функція приймає параметри так само, як і функції операцій шляху.
Порада
У наступному розділі ви побачите, які ще «речі», окрім функцій, можна використовувати як залежності.
Щоразу, коли надходить новий запит, FastAPI подбає про:
- Виклик вашої функції-залежності («залежного») з правильними параметрами.
- Отримання результату з вашої функції.
- Присвоєння цього результату параметру у вашій функції операції шляху.
graph TB
common_parameters(["common_parameters"])
read_items["/items/"]
read_users["/users/"]
common_parameters --> read_items
common_parameters --> read_users
Таким чином ви пишете спільний код один раз, а FastAPI подбає про його виклик для ваших операцій шляху.
Перевірте
Зверніть увагу, що вам не потрібно створювати спеціальний клас і передавати його кудись у FastAPI, щоб «зареєструвати» його чи щось подібне.
Ви просто передаєте його в Depends, і FastAPI знає, що робити далі.
Спільне використання залежностей Annotated¶
У наведених вище прикладах видно невелике дублювання коду.
Коли вам потрібно використати залежність common_parameters(), доводиться писати весь параметр з анотацією типу та Depends():
commons: Annotated[dict, Depends(common_parameters)]
Але оскільки ми використовуємо Annotated, ми можемо зберегти це значення Annotated у змінній і використовувати його в кількох місцях:
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
CommonsDep = Annotated[dict, Depends(common_parameters)]
@app.get("/items/")
async def read_items(commons: CommonsDep):
return commons
@app.get("/users/")
async def read_users(commons: CommonsDep):
return commons
Порада
Це просто стандартний Python, це називається «псевдонім типу» і насправді не є специфічним для FastAPI.
Але оскільки FastAPI базується на стандартах Python, включно з Annotated, ви можете використати цей трюк у своєму коді. 😎
Залежності продовжать працювати як очікується, і найкраще те, що інформація про типи буде збережена, а це означає, що ваш редактор зможе й надалі надавати автозаповнення, помилки в рядку тощо. Те саме і для інших інструментів, як-от mypy.
Це буде особливо корисно у великій кодовій базі, де ви використовуєте одні й ті самі залежності знову і знову в багатьох операціях шляху.
Бути async чи не бути async¶
Оскільки залежності також викликатимуться FastAPI (так само, як і ваші функції операцій шляху), під час визначення ваших функцій діють ті самі правила.
Ви можете використовувати async def або звичайний def.
І ви можете оголошувати залежності з async def всередині звичайних функцій операцій шляху з def, або залежності з def всередині функцій операцій шляху з async def тощо.
Це не має значення. FastAPI знатиме, що робити.
Примітка
Якщо ви не впевнені, перегляньте розділ Async: "In a hurry?" про async і await у документації.
Інтегровано з OpenAPI¶
Усі декларації запитів, перевірки та вимоги ваших залежностей (і субзалежностей) будуть інтегровані в ту саму схему OpenAPI.
Тож інтерактивна документація також міститиме всю інформацію з цих залежностей:

Просте використання¶
Якщо придивитися, функції операцій шляху оголошуються для використання щоразу, коли збігаються шлях та операція, а потім FastAPI подбає про виклик функції з правильними параметрами, витягуючи дані із запиту.
Насправді всі (або більшість) вебфреймворків працюють так само.
Ви ніколи не викликаєте ці функції безпосередньо. Їх викликає ваш фреймворк (у цьому випадку FastAPI).
За допомогою системи впровадження залежностей ви також можете вказати FastAPI, що ваша функція операції шляху також «залежить» від чогось, що має бути виконано до вашої функції операції шляху, і FastAPI подбає про виконання цього та «інжектування» результатів.
Інші поширені терміни для цієї самої ідеї «впровадження залежностей»:
- ресурси
- провайдери
- сервіси
- інжектовані об’єкти
- компоненти
Плагіни FastAPI¶
Інтеграції та «плагіни» можна будувати за допомогою системи Впровадження залежностей. Але насправді немає потреби створювати «плагіни», оскільки, використовуючи залежності, можна оголосити безмежну кількість інтеграцій та взаємодій, які стають доступними для ваших функцій операцій шляху.
І залежності можна створювати дуже просто та інтуїтивно, що дозволяє вам просто імпортувати потрібні пакунки Python і інтегрувати їх з вашими функціями API за кілька рядків коду, буквально.
Ви побачите приклади цього в наступних розділах, про реляційні та NoSQL бази даних, безпеку тощо.
Сумісність FastAPI¶
Простота системи впровадження залежностей робить FastAPI сумісним з:
- усіма реляційними базами даних
- NoSQL базами даних
- зовнішніми пакунками
- зовнішніми API
- системами автентифікації та авторизації
- системами моніторингу використання API
- системами інжекції даних у відповідь
- тощо.
Просто і потужно¶
Хоча ієрархічна система впровадження залежностей дуже проста у визначенні та використанні, вона все ще дуже потужна.
Ви можете визначати залежності, які своєю чергою можуть визначати власні залежності.
Зрештою будується ієрархічне дерево залежностей, і система Впровадження залежностей подбає про розв’язання всіх цих залежностей (і їхніх субзалежностей) та надання (інжектування) результатів на кожному кроці.
Наприклад, припустімо, у вас є 4 кінцеві точки API (операції шляху):
/items/public//items/private//users/{user_id}/activate/items/pro/
тоді ви могли б додати різні вимоги до дозволів для кожної з них лише за допомогою залежностей і субзалежностей:
graph TB
current_user(["current_user"])
active_user(["active_user"])
admin_user(["admin_user"])
paying_user(["paying_user"])
public["/items/public/"]
private["/items/private/"]
activate_user["/users/{user_id}/activate"]
pro_items["/items/pro/"]
current_user --> active_user
active_user --> admin_user
active_user --> paying_user
current_user --> public
active_user --> private
admin_user --> activate_user
paying_user --> pro_items
Інтегровано з OpenAPI¶
Усі ці залежності, декларуючи свої вимоги, також додають параметри, перевірки тощо до ваших операцій шляху.
FastAPI подбає про додавання всього цього до схеми OpenAPI, щоб це відображалося в інтерактивних системах документації.