FastAPI превращает типизированные функции Python в HTTP-эндпоинты и сразу показывает их в интерактивной документации. Соберём маленький API задач: GET возвращает список, POST принимает JSON, Pydantic проверяет поля, а Swagger UI позволяет выполнить запрос прямо из браузера.
API является договором между программами. Клиент отправляет метод, путь и данные, сервер проверяет запрос и возвращает статус с JSON. В FastAPI этот договор виден в коде: декоратор задаёт метод и путь, модель Pydantic описывает тело, а аннотации типов становятся схемой OpenAPI.
GET /tasks возвращает текущий список и не изменяет состояние.
POST /tasks принимает JSON, проверяет title и добавляет id на сервере.
Страница /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 | Статус и схема совпали |
У проекта есть один главный маршрут: получить входные данные, проверить их, выполнить действие и показать результат. Если каждый этап можно проверить отдельно, ошибка перестаёт быть загадкой.

От входных данных до видимого результата. Валидация заканчивается до вызова бизнес-функции
Создаём 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, а модели задают границу входа и выхода. Благодаря этому ошибка формата отделена от бизнес-логики.

Что отличает устойчивый проект от случайного успеха. Схема делает вход и выход видимыми
Откуда берётся валидация и документация
При запуске 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 запускает их подходящим способом.
Проверяем 200, 201 и ошибку 422
В /docs выполните четыре запроса по порядку: пустой GET, правильный POST, повторный GET и POST с пустым title. Запишите статусы. Затем добавьте GET /tasks/{task_id}. Если id не найден, выбрасывайте HTTPException(status_code=404). Проверьте существующую и отсутствующую задачу. После этого создайте tests/test_api.py с TestClient.
- Откройте /docs и выполните пустой GET /tasks.
- Создайте задачу через POST и проверьте статус 201.
- Отправьте пустой title и найдите поле ошибки в JSON 422.
- Добавьте GET /tasks/{id} с ответом 404 для отсутствующей записи.
- Напишите автоматический тест на создание и чтение.
- Перезапустите сервер и объясните, почему список снова пуст.
- GET и POST возвращают разные правильные статусы.
- Неверное тело отклоняется до функции.
- OpenAPI показывает обе схемы.
- Тест повторяется с чистым состоянием.
Первый API готов, когда контракт можно доказать четырьмя запросами: прочитать пустой список, создать объект, прочитать его и получить предсказуемую ошибку на неверных данных.

Четыре проверки перед следующим шагом. Правильная ошибка является частью API
Готовим API к следующему уровню
Дальше подключите SQLite или Postgres через отдельный слой репозитория, но не меняйте HTTP-контракт сразу. Затем добавьте PATCH для done, DELETE и пагинацию. Авторизацию подключайте после того, как можете объяснить границу данных: кто владелец задачи и где это проверяется. Для развёртывания не используйте dev-сервер как окончательную конфигурацию.
Как изучить тему в Кодике
В Кодике сначала повторите функции, классы и списки Python. Затем разберите JSON и методы HTTP. Когда эти части знакомы, декоратор @app.post становится простой связью между запросом и обычной функцией.
| Шаг | Что изучить в Кодике | Мини-проверка |
|---|---|---|
| 1 | Функции и списки Python | Добавить TaskRead в обычный список |
| 2 | Классы и типы | Описать TaskCreate и TaskRead |
| 3 | HTTP и JSON | Различить GET, POST, 200, 201 и 422 |
| 4 | FastAPI routes | Выполнить запросы через /docs |
| 5 | Автоматические тесты | Проверить контракт через TestClient |
Не пытайтесь запомнить весь API. В тренажёре Кодика сначала воспроизведите чистую логику без библиотеки, затем восстановите подключение и обработку ошибок. Финальный тест: объяснить проект по памяти и добавить одну свою функцию.
Используйте POST для новой записи и возвращайте понятный статус 201.
Модель Pydantic документирует поля и отклоняет неверные данные до логики.
Он исчезает при перезапуске и не подходит нескольким процессам. Явно зафиксируйте ограничение.
Сначала используйте обычный def. Переходите на async для неблокирующих библиотек и проверяйте, что внутри нет тяжёлой синхронной работы.
Что получится в итоге

API принимает POST с проверенным JSON, отвечает 201, показывает контракт в /docs и возвращает созданную задачу последующим GET-запросом.
Почему неверный title даёт 422 до create_task?
Pydantic валидирует тело по TaskCreate, и FastAPI не вызывает функцию при нарушении схемы.
Для чего нужен response_model?
Он фиксирует и документирует форму ответа, а также помогает не возвращать лишние поля.
Почему список tasks не является базой?
Он живёт в памяти одного процесса, исчезает после перезапуска и не синхронизируется между экземплярами.
Как понять, что проект действительно работает?
Проверьте основной сценарий, неверный ввод, повторный запуск и один граничный случай. Затем объясните путь данных своими словами.
Можно ли начать с готового кода из статьи?
Да. Добейтесь результата, измените одно правило и соберите ключевой файл заново без копирования.
Функции, классы и типы закрепите в курсе Python. Сторону браузера сравните со статьёй про GET и POST через Fetch API.
Окружение настройте по материалу про uv, а типичную проблему браузерного клиента разберите в статье про CORS.