БэкендPython

FastAPI для начинающих: создаём первый API с GET и POST

Создаём API списка задач на FastAPI, принимаем JSON через Pydantic, возвращаем корректный статус 201 и проверяем GET и POST в автоматической документации.

Кодик

Автор

6 мин чтения

FastAPI превращает типизированные функции Python в HTTP-эндпоинты и сразу показывает их в интерактивной документации. Соберём маленький API задач: GET возвращает список, POST принимает JSON, Pydantic проверяет поля, а Swagger UI позволяет выполнить запрос прямо из браузера.

API является договором между программами. Клиент отправляет метод, путь и данные, сервер проверяет запрос и возвращает статус с JSON. В FastAPI этот договор виден в коде: декоратор задаёт метод и путь, модель Pydantic описывает тело, а аннотации типов становятся схемой OpenAPI.

1Читаем

GET /tasks возвращает текущий список и не изменяет состояние.

2Создаём

POST /tasks принимает JSON, проверяет title и добавляет id на сервере.

3Исследуем

Страница /docs показывает параметры, схемы ответов и кнопку Execute.

Как HTTP-запрос попадает в функцию Python

Приложение создаёт объект FastAPI и два path operation. GET /tasks просто возвращает список. POST /tasks получает TaskCreate, где title является строкой длиной от 1 до 80 символов. Сервер сам выдаёт id и возвращает TaskRead со статусом 201 Created. response_model сообщает, какую структуру обещает ответ.

ЭтапЧто происходитПризнак результата
ЗапросКлиент отправляет метод, путь и JSONМаршрут найден
ПроверкаPydantic валидирует тело по TaskCreateПолучен объект или 422
ЛогикаФункция читает или добавляет задачуСостояние изменилось ожидаемо
ОтветFastAPI сериализует модель в JSONСтатус и схема совпали

У проекта есть один главный маршрут: получить входные данные, проверить их, выполнить действие и показать результат. Если каждый этап можно проверить отдельно, ошибка перестаёт быть загадкой.

Путь HTTP-запроса в FastAPI
От входных данных до видимого результата. Валидация заканчивается до вызова бизнес-функции

GET читает, POST создаёт. Метод является частью договора. Не прячьте создание данных в GET-путь: браузеры, кеши и роботы могут повторять такие запросы. В учебном API используйте привычную семантику с самого начала.

Создаём GET и POST в одном приложении

Создайте проект: uv init fastapi-lab, затем uv add "fastapi[standard]". Сохраните код как main.py и запустите uv run fastapi dev main.py. Терминал покажет адрес приложения и документации. Откройте http://127.0.0.1:8000/docs, раскройте POST /tasks, нажмите Try it out и отправьте JSON {"title":"Повторить функции"}.

from fastapi import FastAPI, status
from pydantic import BaseModel, Field

app = FastAPI(title="Study Tasks API")


class TaskCreate(BaseModel):
    title: str = Field(min_length=1, max_length=80)


class TaskRead(TaskCreate):
    id: int
    done: bool = False


tasks: list[TaskRead] = []


@app.get("/tasks", response_model=list[TaskRead])
def list_tasks() -> list[TaskRead]:
    return tasks


@app.post("/tasks", response_model=TaskRead, status_code=status.HTTP_201_CREATED)
def create_task(payload: TaskCreate) -> TaskRead:
    task = TaskRead(id=len(tasks) + 1, title=payload.title)
    tasks.append(task)
    return task
Что должно произойти после запуска
  • GET /tasks сначала отвечает 200 и пустым JSON-массивом.
  • POST с корректным title отвечает 201 и объектом с id и done=false.
  • Повторный GET возвращает созданную задачу внутри списка.
  • POST с пустой строкой получает 422 до выполнения create_task.

Функции остаются обычным Python, но декораторы связывают их с HTTP, а модели задают границу входа и выхода. Благодаря этому ошибка формата отделена от бизнес-логики.

Произвольный dict и типизированный контракт
Что отличает устойчивый проект от случайного успеха. Схема делает вход и выход видимыми

Откуда берётся валидация и документация

При запуске ASGI-сервер принимает TCP-соединение и передаёт запрос FastAPI. Роутер сопоставляет метод и путь. Если маршрут найден, зависимости и параметры собираются, а JSON превращается в TaskCreate. Pydantic проверяет типы и ограничения Field. Только после успешной валидации вызывается create_task.

ЧастьОтветственностьЧто проверить
DecoratorСвязывает функцию с методом и путёмGET и POST не перепутаны
Pydantic modelПроверяет тело запросаПустой title даёт 422
FunctionВыполняет логику приложенияНе знает детали сокета
response_modelФиксирует форму ответаЛишние поля не утекли
OpenAPIОписывает контракт для инструментов/docs соответствует коду

Список tasks подходит только для лаборатории. Несколько процессов будут иметь разные списки, а перезапуск всё удалит. Настоящее приложение хранит данные в базе и выдаёт id независимо от длины списка. Синхронные def допустимы: FastAPI запускает их подходящим способом.

Документация не заменяет тест. Swagger UI удобно исследовать руками, но повторяемая проверка должна запускаться автоматически. Добавьте TestClient и зафиксируйте статусы, JSON и ошибочный запрос.

Проверяем 200, 201 и ошибку 422

В /docs выполните четыре запроса по порядку: пустой GET, правильный POST, повторный GET и POST с пустым title. Запишите статусы. Затем добавьте GET /tasks/{task_id}. Если id не найден, выбрасывайте HTTPException(status_code=404). Проверьте существующую и отсутствующую задачу. После этого создайте tests/test_api.py с TestClient.

Проверка своими руками
  1. Откройте /docs и выполните пустой GET /tasks.
  2. Создайте задачу через POST и проверьте статус 201.
  3. Отправьте пустой title и найдите поле ошибки в JSON 422.
  4. Добавьте GET /tasks/{id} с ответом 404 для отсутствующей записи.
  5. Напишите автоматический тест на создание и чтение.
  6. Перезапустите сервер и объясните, почему список снова пуст.
Готово, если выполняются все пункты
  • GET и POST возвращают разные правильные статусы.
  • Неверное тело отклоняется до функции.
  • OpenAPI показывает обе схемы.
  • Тест повторяется с чистым состоянием.

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

Четыре проверки первого API
Четыре проверки перед следующим шагом. Правильная ошибка является частью API

Готовим API к следующему уровню

Дальше подключите SQLite или Postgres через отдельный слой репозитория, но не меняйте HTTP-контракт сразу. Затем добавьте PATCH для done, DELETE и пагинацию. Авторизацию подключайте после того, как можете объяснить границу данных: кто владелец задачи и где это проверяется. Для развёртывания не используйте dev-сервер как окончательную конфигурацию.

Как изучить тему в Кодике

В Кодике сначала повторите функции, классы и списки Python. Затем разберите JSON и методы HTTP. Когда эти части знакомы, декоратор @app.post становится простой связью между запросом и обычной функцией.

ШагЧто изучить в КодикеМини-проверка
1Функции и списки PythonДобавить TaskRead в обычный список
2Классы и типыОписать TaskCreate и TaskRead
3HTTP и JSONРазличить GET, POST, 200, 201 и 422
4FastAPI routesВыполнить запросы через /docs
5Автоматические тестыПроверить контракт через TestClient

Не пытайтесь запомнить весь API. В тренажёре Кодика сначала воспроизведите чистую логику без библиотеки, затем восстановите подключение и обработку ошибок. Финальный тест: объяснить проект по памяти и добавить одну свою функцию.

Создание выполняется через GET

Используйте POST для новой записи и возвращайте понятный статус 201.

Вход принимается как произвольный dict

Модель Pydantic документирует поля и отклоняет неверные данные до логики.

Учебный список принимают за базу

Он исчезает при перезапуске и не подходит нескольким процессам. Явно зафиксируйте ограничение.

async добавлен без понимания

Сначала используйте обычный def. Переходите на async для неблокирующих библиотек и проверяйте, что внутри нет тяжёлой синхронной работы.

Сверьтесь с первичным источником. Команды, версии и ограничения примера проверяйте по официальной документации FastAPI: First Steps. Если интерфейс изменился, первичная документация важнее старого скриншота.

Что получится в итоге

Готовый результат: FastAPI для начинающих: создаём первый API с GET и POST
API принимает POST с проверенным JSON, отвечает 201, показывает контракт в /docs и возвращает созданную задачу последующим GET-запросом.

Короткие ответы
Почему неверный title даёт 422 до create_task?

Pydantic валидирует тело по TaskCreate, и FastAPI не вызывает функцию при нарушении схемы.

Для чего нужен response_model?

Он фиксирует и документирует форму ответа, а также помогает не возвращать лишние поля.

Почему список tasks не является базой?

Он живёт в памяти одного процесса, исчезает после перезапуска и не синхронизируется между экземплярами.

Как понять, что проект действительно работает?

Проверьте основной сценарий, неверный ввод, повторный запуск и один граничный случай. Затем объясните путь данных своими словами.

Можно ли начать с готового кода из статьи?

Да. Добейтесь результата, измените одно правило и соберите ключевой файл заново без копирования.

Закрепите HTTP на двух маршрутах, затем подключайте базу

Функции, классы и типы закрепите в курсе Python. Сторону браузера сравните со статьёй про GET и POST через Fetch API.

Окружение настройте по материалу про uv, а типичную проблему браузерного клиента разберите в статье про CORS.