Depends в FastAPI: как вынести общие параметры каталога
Каталог товаров и каталог комнат используют одинаковые limit и offset. Сначала параметры копируют в два обработчика, потом в одном меняют допустимый предел, а второй забывают. Клиент получает разные правила на соседних экранах. Общая зависимость позволяет держать этот договор в одном месте.
Зависимость получает данные так же, как маршрут
Функция, подключённая через Depends, может принимать Query, Header и другие зависимости. FastAPI сам разбирает её аргументы, проверяет ограничения и передаёт результат обработчику. Обычный ручной вызов такой функции не запускает механизм извлечения HTTP-данных: специальные значения в аннотациях понимает именно FastAPI.
Вынесем в page_params только разбор страницы. Получение записей оставим каждому маршруту. Так общая часть не превращается в универсальный обработчик с десятком флагов. Возвращаемая dataclass содержит уже проверенные целые числа; маршруты используют их без повторных проверок.
Подключение и настоящая HTTP-проверка
Для запуска установите FastAPI и HTTPX. Annotated сохраняет Python-тип результата зависимости и отдельно показывает FastAPI способ его получить. Оба маршрута используют один тип PageDep, поэтому их ограничения совпадают.
Сохраните весь блок в файл и запустите Python 3.11+ в отдельном окружении с пакетами fastapi, httpx. Для моделей используется Pydantic v2; отдельный сервер для TestClient не нужен.
from dataclasses import dataclass
from typing import Annotated
from fastapi import FastAPI, Depends, Query
from fastapi.testclient import TestClient
@dataclass
class Page:
limit: int
offset: int
def page_params(limit: Annotated[int, Query(ge=1, le=50)] = 10,
offset: Annotated[int, Query(ge=0)] = 0):
return Page(limit, offset)
PageDep = Annotated[Page, Depends(page_params)]
app = FastAPI()
@app.get("/products")
def products(page: PageDep):
return {"resource": "products", "limit": page.limit, "offset": page.offset}
@app.get("/rooms")
def rooms(page: PageDep):
return {"resource": "rooms", "limit": page.limit, "offset": page.offset}
with TestClient(app) as client:
for path in ("/products", "/rooms"):
r = client.get(path, params={"limit": 7, "offset": 14})
assert r.status_code == 200
assert r.json()["limit"] == 7 and r.json()["offset"] == 14
assert client.get(path + "?limit=51").status_code == 422
assert client.get(path + "?offset=-1").status_code == 422
print("shared HTTP parameter contract checked on both routes")Как не потерять границу ответственности
Не открывайте сессию базы внутри page_params: ей не нужны подключения для разбора двух чисел. Сложная зависимость быстро становится скрытым сервисом, который трудно подменить и протестировать. Если нужно прочитать настройки максимального размера из конфигурации, добавьте небольшую отдельную зависимость настроек и явно отразите этот выбор.
Значения запроса появятся в OpenAPI у каждого маршрута, хотя объявлены в одном месте. Проверьте /docs: limit и offset должны остаться query-параметрами. Если вместо параметров появилось обязательное тело GET, посмотрите, как описан ваш класс или Pydantic-модель зависимости. Явная функция с Query помогает начать с предсказуемого варианта.
Как использовать это в тестах проекта
Проверка двух маршрутов обнаруживает расхождение при рефакторинге. Отдельный прямой вызов page_params полезен для обычной логики, но не подтверждает HTTP-валидацию: он не знает о запросе. В регрессионном тесте достаточно нескольких значимых границ, а не повторения всех целых чисел допустимого диапазона.
Зависимость удобно подменять, когда тест проверяет бизнес-операцию с заранее выбранной страницей. При этом хотя бы один тест должен оставить исходную зависимость и проверить реальное извлечение Query. Иначе весь набор способен проходить даже после случайного удаления нужных аннотаций.
Следующая практика
Открытый урок Depends поможет вынести получение общего значения из обработчика. После базового задания подключите одну функцию разбора страницы к двум каталогам и проверьте одинаковые ограничения query-параметров. Откройте практику зависимостей FastAPI.
В бесплатном курсе FastAPI зависимости затем используются рядом с базой и текущим пользователем. Пройдите эти шаги, чтобы увидеть, как один приём связывает общие параметры и ресурсы приложения. Откройте программу курса.
Продолжить на практике
- FastAPI для начинающих: API с базой данных и тестами ↗
Соберёте свой первый полноценный backend на FastAPI: с базой данных, регистрацией, JWT-авторизацией и автотестами. 34 коротких урока и 140 заданий с проверкой — бесплатно.
