Зависимости (Depends) в FastAPI

Зависимости (Depends) в FastAPI FastAPI

Привет! FastAPI предоставляет мощный механизм внедрения зависимостей через Depends. Это позволяет разделять логику, переиспользовать код и делать приложение чище.

В этой статье мы разберём:

  • Что такое зависимости
  • Базовое использование Depends
  • Внедрение зависимостей
  • Глобальные и эндпоинт-зависимости
  • Практические примеры (БД, аутентификация)

Что нужно знать перед началом

Для этого урока тебе понадобится:

  • Установленный FastAPI
  • Базовое понимание функций и классов

Совет: Зависимости помогают избежать дублирования кода и упрощают тестирование.

Основная часть

Что такое зависимости

Зависимости — это механизм, который позволяет внедрять общую логику в эндпоинты.

Пример без зависимости:

from fastapi import FastAPI

app = FastAPI()

@app.get("/users/")
def get_users(q: str = None, page: int = 1, limit: int = 10):
    # Много повторяющегося кода
    return {"query": q, "page": page, "limit": limit}

@app.get("/items/")
def get_items(q: str = None, page: int = 1, limit: int = 10):
    # Тот же код
    return {"query": q, "page": page, "limit": limit}

С зависимостью:

from fastapi import FastAPI, Depends

app = FastAPI()

def common_parameters(q: str = None, page: int = 1, limit: int = 10):
    return {"q": q, "page": page, "limit": limit}

@app.get("/users/")
def get_users(params: dict = Depends(common_parameters)):
    return {"users": [], **params}

@app.get("/items/")
def get_items(params: dict = Depends(common_parameters)):
    return {"items": [], **params}

Совет: Зависимости позволяют вынести общую логику в отдельные функции.

Базовое использование

from fastapi import FastAPI, Depends

app = FastAPI()

def get_token():
    return "secret-token"

@app.get("/secure/")
def secure_endpoint(token: str = Depends(get_token)):
    return {"token": token}

Совет: Depends вызывается при каждом запросе.

Зависимости с параметрами

def get_user_by_id(user_id: int):
    return {"id": user_id, "name": f"Пользователь {user_id}"}

@app.get("/users/{user_id}")
def get_user(user_data: dict = Depends(get_user_by_id)):
    return user_data

Вложенные зависимости

def get_db_connection():
    return {"host": "localhost", "database": "test"}

def get_user_repository(db: dict = Depends(get_db_connection)):
    return {"users": [{"id": 1, "name": "Анна"}], "db": db}

@app.get("/users/")
def get_users(repo: dict = Depends(get_user_repository)):
    return repo

Глобальные зависимости

from fastapi import FastAPI, Depends

app = FastAPI(dependencies=[Depends(verify_token)])

def verify_token():
    return {"verified": True}

@app.get("/protected/")
def protected_endpoint():
    return {"message": "Доступ разрешён"}

Пример с аутентификацией

from fastapi import FastAPI, Depends, HTTPException, status

app = FastAPI()

users_db = {
    "admin": {"password": "secret", "role": "admin"},
    "user": {"password": "123", "role": "user"}
}

def get_current_user(username: str, password: str):
    if username not in users_db:
        raise HTTPException(status_code=401, detail="Пользователь не найден")
    if users_db[username]["password"] != password:
        raise HTTPException(status_code=401, detail="Неверный пароль")
    return {"username": username, "role": users_db[username]["role"]}

@app.post("/login")
def login(username: str, password: str):
    user = get_current_user(username, password)
    return {"message": "Успешный вход", "user": user}

@app.get("/admin/")
def admin_endpoint(user: dict = Depends(get_current_user)):
    if user["role"] != "admin":
        raise HTTPException(status_code=403, detail="Недостаточно прав")
    return {"message": "Добро пожаловать, администратор!"}

Пример с базой данных

from fastapi import FastAPI, Depends

app = FastAPI()

def get_db():
    return {"connection": "DB connected"}

def get_user_service(db: dict = Depends(get_db)):
    return {"users": [{"id": 1, "name": "Анна"}], "db": db}

@app.get("/users/")
def get_users(service: dict = Depends(get_user_service)):
    return service

Полный пример

from fastapi import FastAPI, Depends, HTTPException, status

app = FastAPI()

# Зависимости для БД
def get_db():
    return {"db": "connected", "data": [{"id": 1, "name": "Анна"}]}

# Зависимость для аутентификации
def verify_token(authorization: str = None):
    if not authorization or not authorization.startswith("Bearer "):
        raise HTTPException(status_code=401, detail="Токен не предоставлен")
    token = authorization.split(" ")[1]
    if token != "secret":
        raise HTTPException(status_code=401, detail="Неверный токен")
    return {"user": "admin"}

# Зависимость для пагинации
def common_parameters(q: str = None, page: int = 1, limit: int = 10):
    return {"q": q, "page": page, "limit": limit}

@app.get("/public/")
def public_endpoint():
    return {"message": "Публичный эндпоинт"}

@app.get("/private/")
def private_endpoint(auth: dict = Depends(verify_token)):
    return {"message": "Приватный эндпоинт", "user": auth}

@app.get("/users/")
def get_users(
    db: dict = Depends(get_db),
    params: dict = Depends(common_parameters)
):
    return {"db": db, **params}

@app.get("/items/")
def get_items(
    db: dict = Depends(get_db),
    params: dict = Depends(common_parameters)
):
    return {"items": [], "db": db, **params}

Задачи для закрепления

Задача 1. Создай зависимость для аутентификации.

Задача 2. Создай зависимость для подключения к БД.

Задача 3. Используй зависимости в эндпоинте.

Задача 4. Создай вложенную зависимость.

Задача 5. Создай глобальную зависимость.

Ответы:

Задача 1.

def verify_token(token: str):
    if token != "secret":
        raise HTTPException(status_code=401)
    return {"user": "admin"}

Задача 2.

def get_db():
    return {"db": "connected"}

Задача 3.

@app.get("/users/")
def get_users(db: dict = Depends(get_db)):
    return db

Задача 4.

def get_user_repo(db: dict = Depends(get_db)):
    return {"users": [], "db": db}

Задача 5.

app = FastAPI(dependencies=[Depends(verify_token)])

Нюансы и подводные камни

  • Depends внедряет зависимости в эндпоинты.
  • Зависимости могут быть вложенными.
  • Глобальные зависимости применяются ко всем эндпоинтам.
  • Зависимости вызываются при каждом запросе.
  • Можно использовать Depends с параметрами.
  • Зависимости упрощают тестирование и переиспользование кода.
  • Depends работает с асинхронными функциями.

Частые ошибки и как их избежать

Ошибка 1: Забыл импортировать Depends

from fastapi import Depends

Ошибка 2: Неправильное использование Depends

item: dict = Depends(func)

Ошибка 3: Глобальные зависимости без Depends

app = FastAPI(dependencies=[Depends(func)])

Шпаргалка

Что нужноКак пишется
Базовая зависимостьdef func(): return ...
Внедрение зависимостиitem: dict = Depends(func)
Глобальная зависимостьapp = FastAPI(dependencies=[Depends(func)])
Вложенная зависимостьdef nested(db: dict = Depends(get_db)):

Заключение

Сегодня мы:

  • Изучили механизм Depends
  • Создавали зависимости для общих задач
  • Использовали вложенные и глобальные зависимости
  • Применяли для аутентификации и БД

КВИЗ

Что дальше?

Оцените статью
IMI-DS - PYTHON LERNEN
Содержание
Оглавление ×