Урок курса
Path-параметры и типы
FastAPI для начинающих: API с базой данных и тестамиВ прошлом уроке мы зарегистрировали маршрут GET /api/rooms и получили список комнат одним декоратором. Теперь добавим второй маршрут, который принимает конкретный идентификатор прямо в URL.
Значение из пути и аннотация int
Когда нужно обратиться к конкретному ресурсу — не ко всему списку, а к одной комнате — принято помещать идентификатор прямо в путь: /api/rooms/3. Чтобы FastAPI понял, что 3 — это переменная, а не фиксированный текст, соответствующий сегмент пути оборачивают в фигурные скобки.
@app.get("/api/rooms/{room_id}")
def get_room(room_id):
return {"room_id": room_id}
Имя внутри скобок — room_id — должно совпадать с именем аргумента функции. Для GET /api/rooms/3 FastAPI извлечёт строку "3" из URL и передаст её в room_id. Именно строку: без аннотации типа никакого преобразования нет, и обработчик вернёт {"room_id": "3"}.
Добавим аннотацию:
@app.get("/api/rooms/{room_id}")
def get_room(room_id: int):
return {"room_id": room_id}
Теперь тот же запрос GET /api/rooms/3 вернёт {"room_id": 3} — уже число. FastAPI прочитал строку "3" из пути, преобразовал её в int и только затем вызвал функцию. Сам Python этого не делает: обычная аннотация типа не превращает аргумент автоматически. Преобразование — работа FastAPI, выполняется до входа в тело функции.
Неверный тип: ответ 422 до обработчика
Раз преобразование происходит до вызова функции, FastAPI может отклонить запрос ещё на входе — если значение не удаётся привести к нужному типу.
Отправьте GET /api/rooms/abc к маршруту с room_id: int. Строка "abc" не превращается в целое число, и функция get_room вообще не запускается. В ответ придёт статус 422 Unprocessable Entity и JSON с описанием проблемы:
{
"detail": [
{
"type": "int_parsing",
"loc": ["path", "room_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "abc"
}
]
}
Поле loc показывает источник: "path" — значит, ошибка в сегменте пути, "room_id" — конкретный параметр. Это удобно, когда параметров несколько и нужно быстро найти виновника.
422 отличается от ошибки, которая возникла бы внутри функции. Здесь тело обработчика не выполнялось вовсе: FastAPI остановил запрос до него. Это граница между некорректным входом и логикой приложения.

Поиск по id: существующий ключ и KeyError
Допустим, у нас есть каталог из двух переговорных комнат, хранящийся в словаре с целочисленными ключами:
from fastapi import FastAPI
app = FastAPI()
rooms_by_id = {
1: {"id": 1, "name": "Лондон", "floor": 2},
2: {"id": 2, "name": "Берлин", "floor": 3},
}
@app.get("/api/rooms")
def list_rooms():
return list(rooms_by_id.values())
@app.get("/api/rooms/{room_id}")
def get_room(room_id: int):
return rooms_by_id[room_id]
GET /api/rooms/1 вернёт {"id": 1, "name": "Лондон", "floor": 2}. FastAPI преобразует "1" в 1, функция обращается к словарю по ключу 1 — всё работает.
GET /api/rooms/abc — 422 ещё до словаря, как разобрали выше.
GET /api/rooms/999 — интереснее. Строка "999" успешно преобразуется в int, проверка типа пройдена. Но ключа 999 в rooms_by_id нет. Python выбросит KeyError, FastAPI не поймает его автоматически, и клиент получит 500 Internal Server Error.
Вот принципиальное различие: аннотация int гарантирует только форму значения — что оно целое число. Она ничего не знает о содержимом словаря. Проверка типа и проверка существования записи — два независимых шага. Первый делает FastAPI, второй — ваш код.
Задача 1
Маршрут объявлен как @app.get("/api/rooms/{room_id}") с функцией def get_room(room_id: int). Клиент отправляет запрос GET /api/rooms/5. Какое значение и какого типа получит функция-обработчик в аргументе room_id?
Задача 2
Маршрут объявлен как GET /api/rooms/{room_id}, а аргумент — room_id: int. Что произойдёт при запросе GET /api/rooms/abc?
Задача 3
Переговорная по идентификатору
Roomly — небольшой сервис для управления переговорными комнатами в офисе. Все переговорные уже загружены в единый словарь rooms_by_id, и общий список доступен любому желающему через уже работающий маршрут каталога. Однако просматривать каждый раз весь список ради одной комнаты неудобно: нужен способ обратиться к конкретной переговорной напрямую, зная только её числовой идентификатор.
Именно для этого требуется отдельный маршрут, который принимает идентификатор как часть адреса и возвращает сведения об одной выбранной переговорной. Оба маршрута — и каталог, и запрос по идентификатору — работают с одним и тем же rooms_by_id, никакого дополнительного хранилища или дублирующего списка в системе нет.
Если в адресе вместо числа оказывается произвольная строка или иное нечисловое значение, FastAPI самостоятельно отклоняет такой запрос ещё до того, как управление достигает обработчика. Для существующего целочисленного идентификатора маршрут возвращает данные нужной переговорной из общего словаря.
Что уже дано
В редакторе открыт самодостаточный main.py с объектом верхнего уровня app, единым словарём rooms_by_id и рабочим маршрутом списка GET /api/rooms. Оба маршрута этой лабораторной должны читать только rooms_by_id; второго списка или хранилища нет. Перед файлом выполняется видимый служебный переходник проверки: он определяет функции для запросов и чтения состояния, но не создаёт приложение или данные каталога. Менять переходник не нужно.
Что нужно сделать
Самостоятельно объявите декоратор и функцию-обработчик для GET /api/rooms/{room_id}. Имя переменного сегмента должно совпадать с именем аргумента, а room_id должен быть аннотирован как int. Для существующего идентификатора верните соответствующий словарь из rooms_by_id. В лабораторной проверяются только существующие целочисленные id; поведение для отсутствующего целочисленного id не задаётся.
Ввод и вывод
stdin не используется. Печатать через print в stdout ничего не нужно. После вашего кода проверяющая система читает объекты верхнего уровня app и rooms_by_id и отправляет запросы через TestClient. Она проверяет статусы и JSON-ответы; нечисловое значение в path должно быть автоматически отклонено FastAPI статусом 422 до вызова обработчика.
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Задачи к уроку
- Path-параметры и типы — задача по FastAPI
Какое значение и какого типа получит функция-обработчик в аргументе roomid? Проверьте ответ в задаче из бесплатного курса FastAPI.
Продолжить с сохранением прогресса
Перейдите к уроку в учебном кабинете.
