APIRouter — это класс FastAPI для выноса группы маршрутов в отдельный файл. Создаёте router = APIRouter(), вешаете на него эндпоинты через @router.get(...), а в главном файле подключаете к приложению одной строкой app.include_router(router). Так монолитный main.py распадается на модули по зонам ответственности.

from fastapi import APIRouter

router = APIRouter()

@router.get("/users/")
async def read_users():
    return [{"username": "Rick"}, {"username": "Morty"}]

Обновлено в 2026 году. Все параметры и примеры сверены с официальной документацией FastAPI.

Коротко, что вы получите из статьи:

  • чем APIRouter отличается от FastAPI() и когда пора дробить приложение;
  • как задать общий prefix, tags, dependencies и responses сразу на весь роутер;
  • рабочую структуру каталога routers/ для среднего проекта;
  • как вкладывать роутер в роутер и раздавать версии API (/api/v1, /api/v2);
  • сравнение «один файл против роутеров» в таблице и ответы на частые вопросы.

Что такое APIRouter и зачем разбивать приложение

APIRouter работает как «мини-приложение»: у него есть свои методы .get(), .post(), .put(), .delete(), но сам он не запускается — его подключают к основному экземпляру FastAPI. Разница простая: FastAPI() — это корень, который принимает запросы и держит документацию; APIRouter() — переносной набор маршрутов, который вы собираете отдельно и вставляете в корень.

Пока эндпоинтов пять-десять, один main.py терпимо. Проблемы начинаются, когда в файле сотни строк: пользователи, заказы, оплата и админка лежат вперемешку, каждый merge упирается в конфликты, а найти нужный обработчик получается только поиском по тексту. Роутеры режут это по домену: users.py, items.py, admin.py — каждый со своими маршрутами и зависимостями.

Дополнительный бонус — переиспользование. Роутер не привязан к конкретному приложению, поэтому его можно подключить к другому проекту, отдать как часть библиотеки или подключить дважды под разными префиксами. Тестировать группу маршрутов тоже проще: изолированный файл роутера легче покрыть модульными тестами, чем разбираться, что задевает изменение в общем main.py.

Вывод: дробить стоит не «для красоты», а когда один файл перестаёт помещаться в голову и мешает командной работе.

ОНЛАЙН-ПРАКТИКУМ
ЗАПУСК нейросети DEEPSEEK R1 ЛОКАЛЬНО НА СВОЕМ КОМПЬЮТЕРЕ
ЧТО БУДЕТ НА ОБУЧЕНИИ?
  • ПОКАЖЕМ, КАК РАЗВЕРНУТЬ МОДЕЛЬ нейросети DEEPSEEK R1 ПРЯМО НА СВОЁМ КОМПЬЮТЕРЕ
  • Где и как применять? Потестируем модель после установки на разных задачах
  • Как дообучить модель под себя?

Как создать роутер в FastAPI

Роутер создаётся импортом APIRouter и одной строкой. Дальше эндпоинты вешаются на него точно так же, как раньше вешались на app — меняется только имя объекта в декораторе.

# routers/users.py
from fastapi import APIRouter

router = APIRouter()

@router.get("/users/", tags=["users"])
async def read_users():
    return [{"username": "Rick"}, {"username": "Morty"}]

@router.get("/users/{username}", tags=["users"])
async def read_user(username: str):
    return {"username": username}

Обратите внимание: пути внутри роутера начинаются со слэша (/users/), а общий префикс к ним добавится позже, при подключении. Это позволяет писать эндпоинты, не думая о том, под каким корнем они в итоге окажутся.

Вывод: файл роутера — обычный Python-модуль, где вместо app используется router.

Подключение через include_router

Роутер сам по себе не отвечает на запросы. Чтобы FastAPI начал его видеть, роутер подключают к приложению методом include_router(). FastAPI разберёт все операции пути из роутера и добавит их в общую маршрутизацию и в OpenAPI-схему — интерактивная документация подхватит их автоматически.

# main.py
from fastapi import FastAPI
from routers import users, items

app = FastAPI()

app.include_router(users.router)
app.include_router(items.router)

@app.get("/")
async def root():
    return {"message": "Hello Bigger Applications!"}

Здесь два роутера подключены к одному приложению. Каждый живёт в своём файле, а main.py остаётся тонким: он только собирает части вместе. Добавляете новый домен — создаёте файл и дописываете ещё одну строку include_router.

Порядок подключения роутеров влияет только на порядок разделов в документации /docs, но не на саму маршрутизацию: пути сопоставляются по совпадению, а не по очерёдности регистрации. Через include_router подключают и роутеры из сторонних пакетов — например, готовые модули аутентификации, — если библиотека отдаёт объект APIRouter.

Вывод: include_router() — это «вставка» модуля маршрутов в приложение; без неё роутер мёртв.

Префикс, теги, зависимости и responses на уровне роутера

Главная экономия от роутеров — общие настройки задаются один раз на всю группу, а не копируются в каждый эндпоинт. Их можно указать двумя способами: при создании APIRouter(...) либо при вызове include_router(...).

from fastapi import APIRouter, Depends

router = APIRouter(
    prefix="/items",
    tags=["items"],
    dependencies=[Depends(get_token_header)],
    responses={404: {"description": "Not found"}},
)

Что делает каждый параметр:

  • prefix="/items" — добавляет /items в начало всех путей роутера. Важно: префикс пишется без завершающего слэша.
  • tags=["items"] — вешает тег на все операции, они сгруппируются в Swagger UI под общим заголовком.
  • dependencies=[Depends(get_token_header)] — применяет зависимость (проверку токена, доступа, сессии) ко всем маршрутам сразу.
  • responses={404: {"description": "Not found"}} — описывает общие варианты ответа для документации.

Те же параметры принимает и include_router(). Это удобно, когда роутер универсальный, а настройки зависят от места подключения:

app.include_router(
    admin.router,
    prefix="/admin",
    tags=["admin"],
    dependencies=[Depends(get_token_header)],
    responses={418: {"description": "I'm a teapot"}},
)

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

Вывод: prefix, tags, dependencies и responses на роутере убирают дублирование — авторизацию и общие ответы задаёте один раз.

Структура проекта с каталогом routers/

Официальная документация FastAPI предлагает раскладывать среднее приложение так: пакет app с точкой входа, отдельный модуль зависимостей и подпакет routers с файлом на каждый домен.

.
├── app
│   ├── __init__.py       # делает "app" Python-пакетом
│   ├── main.py           # точка входа, собирает роутеры
│   ├── dependencies.py   # общие зависимости
│   └── routers
│       ├── __init__.py   # делает "routers" подпакетом
│       ├── items.py      # роутер товаров
│       └── users.py      # роутер пользователей
└── internal
    ├── __init__.py
    └── admin.py          # внутренняя админка

Ключевой момент, на котором спотыкаются новички: в каждой папке обязателен файл __init__.py, иначе Python не считает каталог пакетом и импорт вида from .routers import items упадёт с ошибкой. Файлы могут быть пустыми — важно само их наличие.

Вывод: один домен — один файл в routers/; забытый __init__.py — самая частая причина ошибок импорта.

Несколько роутеров в одном приложении

Поток запроса в FastAPI с несколькими роутерами: от входящего HTTP до обработчика через include_router
Поток запроса в FastAPI с несколькими роутерами: от входящего HTTP до обработчика через include_router

Собираем всё вместе. В main.py импортируем модули из подпакета и подключаем их — часть с общими настройками, часть без.

# app/main.py
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users

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

app.include_router(users.router)
app.include_router(items.router)
app.include_router(
    admin.router,
    prefix="/admin",
    tags=["admin"],
    dependencies=[Depends(get_token_header)],
    responses={418: {"description": "I'm a teapot"}},
)

@app.get("/")
async def root():
    return {"message": "Hello Bigger Applications!"}

Здесь видно два уровня зависимостей: get_query_token объявлена на всём приложении и сработает на любом запросе, а get_token_header — только на маршрутах админки. Такой каскад удобно строить именно на роутерах.

Вывод: приложение собирается из независимых роутеров, а зависимости навешиваются послойно — на приложение, на роутер, на эндпоинт.

Вложенные роутеры: роутер внутри роутера

Роутер можно подключить не только к приложению, но и к другому роутеру — тем же методом include_router(). Это нужно, когда у большого домена есть подразделы: например, у users появляются users/settings и users/sessions.

from fastapi import APIRouter

router = APIRouter(prefix="/users")
settings_router = APIRouter(prefix="/settings")

@settings_router.get("/notifications")
async def get_notifications():
    return {"email": True}

router.include_router(settings_router)
# итоговый путь: /users/settings/notifications

FastAPI включит операции пути вложенного роутера в маршрутизацию и OpenAPI независимо от того, сделали вы это до или после подключения родительского роутера к приложению. Префиксы при этом складываются слева направо.

Вывод: вложенные роутеры дают древовидную структуру URL без ручной склейки путей.

Версионирование API через префиксы

Один и тот же роутер можно подключить несколько раз с разными префиксами. Это самый дешёвый способ раздать API под несколькими версиями и не ломать старых клиентов при выкатке новой.

app.include_router(router, prefix="/api/v1")
app.include_router(router, prefix="/api/latest")

Так одни и те же обработчики становятся доступны и по /api/v1, и по /api/latest. Когда логика версий начнёт расходиться, вы просто разведёте их по отдельным файлам-роутерам — переход будет плавным, без переписывания клиентов.

Вывод: версионирование в FastAPI начинается с одной строки — повторного include_router с новым префиксом.

Один файл или роутеры: когда что

Роутеры — не догма. Для прототипа на три эндпоинта они добавят лишних папок без пользы. Ориентир — размер и число людей в проекте.

Критерий Монолитный main.py Несколько APIRouter
Порог применения прототип, до ~10 эндпоинтов средний и крупный проект
Навигация по коду всё в одном файле, поиск текстом файл на домен, находится сразу
Общие настройки (auth, теги) копируются в каждый эндпоинт задаются раз на роутер
Командная работа конфликты при merge разные файлы — меньше конфликтов
Версионирование API вручную и с дублированием повторный include_router с префиксом
Порог входа ниже, старт быстрее нужно понимать пакеты и импорты

Вывод: начинайте с одного файла, переходите на роутеры, когда появляются домены, версии или второй разработчик.

Разобраться с FastAPI, асинхронностью и структурой backend-проекта с нуля можно на профильных курсах по Python-разработке — от первого эндпоинта до продакшн-приложения.

Частые вопросы

Чем APIRouter отличается от FastAPI?

FastAPI() — это само приложение, которое запускается и принимает запросы. APIRouter() — переносной набор маршрутов, который сам не запускается, а подключается к приложению через include_router(). Методы (.get(), .post()) у них одинаковые.

Обязателен ли prefix при подключении роутера?

Нет. Без префикса маршруты роутера попадут в корень приложения. Префикс нужен, когда вы хотите вынести группу под общий путь (/admin, /api/v1) или подключить один роутер несколько раз.

Как повесить авторизацию на все маршруты роутера?

Через параметр dependencies при создании APIRouter(...) или при вызове include_router(...): dependencies=[Depends(get_token_header)]. Зависимость сработает на каждом эндпоинте группы, дублировать её в декораторах не нужно.

Почему падает импорт from .routers import items?

Скорее всего, в каталоге routers нет файла __init__.py. Без него Python не считает папку пакетом. Файл может быть пустым — важно, чтобы он существовал в каждой папке пакета.

Можно ли вкладывать роутер в роутер?

Да. Метод include_router() работает и на объекте APIRouter, а не только на FastAPI. Префиксы вложенных роутеров складываются, что даёт древовидные URL вроде /users/settings/notifications. Подробнее — в официальной документации FastAPI.

Большой практикум
ЗАМЕНИ ВСЕ НЕЙРОСЕТИ НА ОДНУ — PERPLEXITY
ПОКАЖЕМ НА КОНКРЕТНЫХ КЕЙСАХ
  • Освой нейросеть Perplexity и узнай, как пользоваться функционалом остальных ИИ в одном
  • УЧАСТВОВАТЬ ЗА 0 РУБ.
  • Расскажем, как получить подписку
Участвовать бесплатно
ОНЛАЙН-ПРАКТИКУМ
ЗАПУСК нейросети DEEPSEEK R1 ЛОКАЛЬНО НА СВОЕМ КОМПЬЮТЕРЕ
ЧТО БУДЕТ НА ОБУЧЕНИИ?
  • ПОКАЖЕМ, КАК РАЗВЕРНУТЬ МОДЕЛЬ нейросеть DEEPSEEK R1 ПРЯМО НА СВОЁМ КОМПЬЮТЕРЕ
Участвовать бесплатно