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 ПРЯМО НА СВОЁМ КОМПЬЮТЕРЕ
- Где и как применять? Потестируем модель после установки на разных задачах
- Как дообучить модель под себя?
Как создать роутер в 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 — самая частая причина ошибок импорта.
Несколько роутеров в одном приложении

Собираем всё вместе. В 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/notificationsFastAPI включит операции пути вложенного роутера в маршрутизацию и 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 и узнай, как пользоваться функционалом остальных ИИ в одном
- УЧАСТВОВАТЬ ЗА 0 РУБ.
- Расскажем, как получить подписку
- ПОКАЖЕМ, КАК РАЗВЕРНУТЬ МОДЕЛЬ нейросеть DEEPSEEK R1 ПРЯМО НА СВОЁМ КОМПЬЮТЕРЕ