Задача курса

FastAPI APIRouter: разнесите маршруты по модулям

Курс «FastAPI для начинающих: API с базой данных и тестами» · урок «APIRouter и границы модулей»

Условие

Перестройка Roomly без сломанных обращений

Команда Roomly занимается сервисом управления переговорными комнатами, и со временем стало очевидно: логика работы с карточками комнат оказалась слишком тесно переплетена с остальными частями приложения. Это не мешало пользователям, но превращало внутреннее устройство кода в неудобную смесь, которую сложно читать и ещё сложнее развивать. Команда приняла решение навести порядок — выделить всё, что касается переговорных, в самостоятельно организованную часть сервиса.

Суть перестройки состоит не в том, чтобы изменить поведение системы, а в том, чтобы сохранить его полностью при улучшенной внутренней структуре. Коллеги, которые создают новые карточки комнат, просматривают их, полностью заменяют содержимое, вносят точечные правки или удаляют ненужные записи, не должны замечать никаких перемен: те же адреса, те же ответы при успехе, те же сообщения, когда что-то указано неверно или запись не найдена.

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

Что уже дано

Весь исходный код виден в одном редакторе: app, Address/RoomIn/RoomOut/RoomPatch, пустое хранилище rooms_db, счётчик next_id, поиск get_room_or_404 и шесть рабочих обработчиков. Меняется регистрация группы, готовую CRUD-логику переписывать не нужно. Это самостоятельная браузерная лаба на APIRouter; настоящий перенос в два модуля выполняется отдельно в checkpoint. Файлы строками создавать не требуется.

Переходник только выполняет локальные HTTP-запросы и передаёт JSON-метаданные регистрации. Он не создаёт app, router или данные. Помимо HTTP-ответов проверяется именно регистрация общей группы APIRouter и её обработчиков в app; это отдельная проверка структуры, не вывод о ней по одним ответам HTTP.

Что нужно сделать

Объедините все шесть обработчиков в публичный router типа APIRouter и подключите его к публичному app через include_router. Группа должна быть пригодна для подключения; не оставляйте вместо неё отдельные дубли тех же маршрутов на app. Выберите место общего префикса, а в декораторах используйте пути относительно группы. Имена обработчиков свободны.

Сохраните прямые адреса без обязательного перенаправления: GET списка и POST на /api/rooms, GET/PUT/PATCH/DELETE одной комнаты на /api/rooms/{room_id}. Список содержит полные карточки в порядке добавления. POST создаёт новую запись и возвращает201; GET и PUT/PATCH —200; DELETE —204 без тела. Отсутствующий id получает404 с detail="Room not found", неверный тип path — стандартный422.

PUT целиком заменяет входные поля, сохраняя id; пропущенный comment становится null. Даже повтор одинакового полного PUT успешен. PATCH изменяет только переданные name/capacity; {} ничего не меняет. Явный null в любом из них при существующей записи даёт422 с detail="Fields cannot be null" до любых изменений. Несколько комнат не должны влиять друг на друга; после удаления остальные операции продолжают работать.

Готовая RoomIn принимает обязательные name (строка длиной2–50), capacity (целое1–50) и address (объект с обязательными строками city, street). comment — необязательная строка или null, default — None. Сохраните эту валидацию: неверное тело получает стандартный422, включая путь вложенного поля. Публичная карточка содержит ровно id, name, capacity, address, comment; internal_note наружу не попадает. Лишние входные поля игнорируются; клиентские id и internal_note не подменяют серверные данные.

Ввод и вывод

stdin не используется. Печатать через print в stdout ничего не нужно. После выполнения файла проверяющая система обращается к верхнеуровневому app: публичный переходник вызывает TestClient внутри процесса приложения и передаёт результат скрытой проверке. Запускать Uvicorn, сеть, клиентский скрипт или pytest не требуется.

После POST /api/rooms с {"name":"Липа","capacity":4,"address":{"city":"Омск","street":"Мира"}} ответ201 содержит серверный id. GET списка включает эту карточку; DELETE по её id возвращает204, а следующий GET по тому же id —404.

Попробуйте решить

РешениеPython
Без регистрации · результат не сохраняется
FastAPI APIRouter: разнесите маршруты по модулям