Урок курса

Проект FastAPI и первый GET

FastAPI для начинающих: API с базой данных и тестами

В прошлом уроке мы разобрали, как JSON оформляется в теле HTTP-ответа и что означает заголовок Content-Type: application/json. Теперь сделаем шаг от чтения чужих ответов к написанию собственного: создадим проект FastAPI, напишем первый маршрут и получим рабочий ответ 200 с JSON.

Папка проекта, venv и установка пакетов

Прежде всего нужна отдельная папка для проекта. Создайте папку fastapi-demo и откройте в ней терминал.

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

python -m venv venv

В папке fastapi-demo появится подпапка venv. Теперь нужно установить в это окружение два пакета: FastAPI и Uvicorn.

FastAPI связывает входящие HTTP-запросы с Python-функциями.

Uvicorn — это сервер: он принимает сетевые соединения и передаёт их приложению.

Вместо того чтобы активировать окружение, можно обратиться к его Python-интерпретатору напрямую. В PowerShell:

.\venv\Scripts\python.exe -m pip install fastapi uvicorn

На macOS/Linux:

venv/bin/python -m pip install fastapi uvicorn

Этот способ работает в PowerShell без изменения политики выполнения скриптов — Activate.ps1 при этом не запускается вовсе.

Если вы всё же хотите активировать окружение (в cmd — venv\Scripts\activate.bat, на macOS/Linux — source venv/bin/activate), команды установки и запуска станут короче: достаточно писать просто python вместо полного пути к интерпретатору.

После установки папка venv/Lib/site-packages (или venv/lib/python3.x/site-packages на macOS/Linux) содержит fastapi и uvicorn. Больше ничего настраивать не нужно.

Файл main.py и объект приложения

Создайте файл main.py прямо в папке fastapi-demo — рядом с папкой venv, а не внутри неё. Структура выглядит так:

fastapi-demo/
├── venv/
└── main.py

В main.py сначала нужен импорт:

from fastapi import FastAPI

Эта строка делает доступным класс FastAPI из установленного пакета. Затем создаём объект приложения:

app = FastAPI()

Здесь FastAPI — класс, FastAPI() — вызов его конструктора, app — переменная, в которой хранится созданный объект. На этом объекте будут регистрироваться маршруты.

Имя переменной app — не магическое слово языка, а просто соглашение. Важно оно при запуске через Uvicorn: запись main:app означает «возьми модуль main (файл main.py без расширения) и найди в нём переменную app». Если назвать переменную application, запись стала бы main:application. Пока используем app — так короче и понятнее.

Декоратор связывает GET с Python-функцией

Чтобы FastAPI знал, какую функцию вызывать при запросе GET /api/rooms, используется декоратор. Декоратор — это строка над функцией, начинающаяся с @. Она передаёт функцию другому коду ещё в момент определения, до любых запросов.

@app.get("/api/rooms") регистрирует в объекте app связь: метод GET плюс путь /api/rooms → функция, которая написана сразу под декоратором. Имя функции при этом не задаёт URL.

Вот полный main.py для каталога переговорных:

from fastapi import FastAPI

app = FastAPI()

@app.get("/api/rooms")
def list_rooms():
    return [{"id": 1, "name": "Лондон", "floor": 2}]

Когда приходит запрос GET /api/rooms, FastAPI вызывает list_rooms(). Функция возвращает обычный Python-список со словарём внутри. FastAPI автоматически сериализует его в JSON и добавляет заголовок Content-Type: application/json. Код ответа по умолчанию — 200.

Путь /api/rooms выбран произвольно для этого примера — никакого особого смысла в FastAPI он не несёт. Можно было написать /rooms или /v1/rooms; декоратор зарегистрирует любую строку пути.

В предыдущем уроке мы разбирали JSON как формат в теле HTTP-ответа. Здесь FastAPI делает эту работу сам: вы возвращаете Python-данные, а список становится JSON-массивом [{"id":1,"name":"Лондон","floor":2}] в теле ответа.

Запись main:app указывает на модуль main.py и объект app. Декоратор app.get связывает GET /api/rooms с list_rooms. Функция возвращает список со словарём; FastAPI преобразует его в JSON-ответ со статусом 200.
main:app выбирает объект app из main.py. Декоратор связывает запрос с функцией, а FastAPI превращает её результат в JSON.

Uvicorn: запуск, reload и остановка

Сохранённый main.py — это просто файл. Сам по себе он не слушает никакой порт и не принимает запросы. Чтобы получить работающий сервер, нужен Uvicorn.

Откройте терминал в папке fastapi-demo (там, где лежит main.py) и выполните:

.\venv\Scripts\python.exe -m uvicorn main:app --reload

На macOS/Linux:

venv/bin/python -m uvicorn main:app --reload

Если окружение активировано, достаточно:

python -m uvicorn main:app --reload

Uvicorn импортирует app из main.py и начинает слушать http://127.0.0.1:8000. В терминале появятся строки вроде:

INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process

Флаг --reload заставляет Uvicorn следить за изменениями файлов. Когда вы сохраните отредактированный main.py, сервер перезапустится автоматически — перезапускать его вручную не придётся.

Терминал занят процессом сервера. Чтобы отправить запрос, откройте браузер и перейдите по адресу:

http://127.0.0.1:8000/api/rooms

Браузер покажет JSON-массив. Если нужно выполнить другие команды в терминале, откройте второй терминал — не останавливайте сервер.

Пока оставьте сервер работающим — он нужен для проверки /docs ниже. Когда закончите проверку, вернитесь в терминал с Uvicorn и нажмите Ctrl+C: сервер завершит работу, порт освободится.

Статус, JSON и заголовки в /docs

При работающем Uvicorn откройте в браузере второй адрес:

http://127.0.0.1:8000/docs

Это Swagger UI — интерактивная страница документации, которую FastAPI строит автоматически на основе зарегистрированных маршрутов. Никаких дополнительных настроек не нужно.

На странице виден маршрут GET /api/rooms. Раскройте его кликом, нажмите Try it out, затем Execute. Swagger UI отправит настоящий HTTP-запрос к вашему серверу и покажет результат прямо на странице.

Вы увидите три вещи:

  • Code — код ответа. Для нашего маршрута это 200.
  • Response body — тело ответа в виде JSON: [{"id": 1, "name": "Лондон", "floor": 2}].
  • Response headers — заголовки, среди которых content-type: application/json.

Это те же данные, что возвращает прямой запрос к /api/rooms в браузере, только в /docs статус и заголовки видны явно — браузер их обычно скрывает.

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

Какой main.py зарегистрирует GET /api/rooms, после чего маршрут появится в /docs?

Продолжить с проверкой и прогрессом

Откройте интерактивный раннер с заданиями урока.

Перейти к интерактивному уроку