CRUD как HTTP-контракт

Полное и частичное обновление

Содержание курса

Полное описание переоборудованной переговорной

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

Roomly устроена так, что каждая переговорная хранится под собственным идентификатором, и этот идентификатор остаётся неизменным даже тогда, когда само помещение меняется до неузнаваемости. Чтобы обновить карточку, недостаточно подправить отдельные детали: новое описание должно целиком встать на место прежнего, вытеснив его без остатка. Если какие-то необязательные сведения не включены в новое описание, система не будет молча достраивать карточку из старых данных — она примет именно то, что передал менеджер, и ничего сверх этого.

Прежде чем принять замену, система проверяет, что все обязательные сведения присутствуют и соответствуют установленным правилам. Если что-то не так, прежняя карточка остаётся нетронутой. Отдельного внимания заслуживает ситуация, когда менеджер указывает комнату, которой в системе нет: вместо молчаливого создания новой записи система должна явно сообщить об отсутствии такой комнаты. Убедившись, что замена прошла успешно, менеджер может тут же запросить карточку и увидеть в ней именно то описание, которое он только что передал.

Что уже дано

Это самостоятельный файл main.py для браузерного редактора: код ваших прежних решений не переносится автоматически. Модели Address, RoomIn, RoomOut, верхнеуровневый app, пустой rooms_db и начальный next_id уже в файле. Это отдельное упражнение на полную карточку из урока11, а не объединение всех прежних каталогов и фильтров. POST, GET и get_room_or_404 уже работают. PUT пока возвращает старую карточку: дополните только это действие; PATCH в этой лабе не нужен.

Служебный переходник выполняется перед файлом, но не создаёт app или данные. Он только передаёт запросы и результаты между приложением и скрытой проверкой; менять его не нужно.

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

Реализуйте полную замену существующей комнаты через PUT /api/rooms/{room_id} с моделью RoomIn и ответом200/RoomOut. Перед заменой используйте готовый get_room_or_404(room_id). Сохраните выбранный серверный id, замените name, capacity и весь address новым описанием. comment принимает новое значение; если его нет в теле PUT, результат содержит comment: null, а не прежний комментарий. Последующий GET возвращает сохранённый результат; остальные комнаты остаются прежними. Новые значения могут совпадать со старыми.

Готовая 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 не подменяют серверные данные.

Пропуск обязательного поля и недопустимое тело дают422 до изменения любой записи; прежние поля не дополняют неполное тело PUT. Корректный PUT по отсутствующему целочисленному id возвращает404/{"detail":"Room not found"} и не создаёт запись. Нечисловой path-параметр даёт стандартный422. POST продолжает создавать записи с201. Все запросы последовательны, в одном запуске. DELETE, PATCH, база данных и сохранность после перезапуска не требуются.

Ввод и вывод

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

Если у созданной комнаты id=1, PUT /api/rooms/1 с {"name":"Липа","capacity":8,"address":{"city":"Омск","street":"Лесная"}} возвращает200 и эту полную карточку с id: 1, comment: null. GET по тому же id возвращает такой же результат.

О данных в ответах

Используйте учебные данные. Не вставляйте пароли, токены, ключи доступа, паспортные и банковские данные, а также персональные данные других людей. Политика обработки данных.

РешениеPython · Python 3.12 (web: FastAPI, SQLAlchemy, pytest)
Как проверяется решение

Проверяются функции и их результаты. Собственный запуск выполняет ваш код без авторских тестов. Интерактивный запуск не влияет на оценку. Лимит сессии — 5 минут, процессорного времени — 10 секунд.

Отправьте решение, чтобы увидеть результаты тестов.