Перейти к содержанию

Ограничения и внутренности

Честный список того, что вне области видимости, и почему — плюс немного о внутреннем устройстве.

Версии FastAPI

Зависимость: fastapi >=0.115,!=0.137.*,!=0.138.*.

FastAPI 0.137 ввёл ленивую модель роутинга (_IncludedRouter-дерево вместо копирования роутов), но поддержанный итератор iter_route_contexts появился только в 0.139. В промежутке 0.1370.138 вложенные include_router нечем корректно обойти, поэтому эти версии исключены на уровне зависимости. Остаются два рабочих режима:

  • ≤ 0.136 — старый жадный include_router (плоский обход routes);
  • ≥ 0.139 — ленивый роутинг с iter_route_contexts.

CI-checker выбирает нужный режим автоматически (call-time getattr + fallback на плоский обход).

Ограничения обходчика

auto=True и check_raises используют один AST-обходчик. Он консервативен и никогда не исполняет ваш код — отсюда область видимости.

Понимает:

  • raise X(...), raise X, raise X(...) from e;
  • raise внутри if/try-except/match;
  • хелперы, вызванные по имени (в том числе кросс-модульные), до заданной глубины;
  • фабричный паттерн get_or_404(error=X) (класс ошибки как аргумент вызова);
  • ошибки, захваченные в замыкании;
  • эндпоинты-partial, functools.wraps-цепочки, callable-инстансы, класс-зависимости (через __init__);
  • всё дерево Depends (security-схемы пропускаются).

Не видит (документированные ложные пропуски):

  • локальный dataflow: err = NotFoundError; raise err(...);
  • цепочки методов на объектах: self.service.raise_it();
  • динамическую диспетчеризацию (raise из значения в словаре и т.п.);
  • голые стрим-возвраты -> Annotated[AsyncIterator[X], Raises[...]].

Ложные пропуски безопасны для CI

Из-за них overdeclared остаётся провалом по умолчанию. Если у вас динамические raise, которые обходчик не видит, — задекларируйте их явно через Raises или используйте check_raises(app, allow_overdeclared=True).

Плоские тела ответа

Своя модель ответа расширяется только плоско (поля рядом с code/detail). Вложенные конверты (data: ErrorResponse[T]) не поддерживаются — pydantic не умеет дискриминировать union по вложенному полю. Подробно — в Кастомизации.

Полу-приватные функции FastAPI

auto=True реконструирует дерево зависимостей на регистрации через fastapi.dependencies.utils.get_dependant / get_parameterless_sub_dependant. Это публичные (без подчёркивания) функции, которые сам FastAPI импортирует в routing.py, но они не задокументированы как стабильный API. Импорт спрятан в try/except ImportError — при смене внутреннего API обход мягко деградирует до «только эндпоинт» (ошибки зависимостей не попадут в auto, но пакет продолжит работать).

Область видимости Raises на роуте

  • Маркер Raises на роутере, не пропущенном через with_errors, инертен: ничего не инъектируется и ничего не падает. CI-checker читает аннотации напрямую, поэтому такой дрейф всё равно ловит.
  • Оборачивайте роутер до регистрации роутов — иначе они не дооснащаются.

Дальше: Справочник API — сигнатуры из docstring-ов.