REST API для управления задачами с JWT-авторизацией. Учебный пет-проект: написан за один вечер, чтобы показать уверенное владение FastAPI, SQLAlchemy 2.0, PostgreSQL и Docker.
- 🔐 JWT-авторизация — регистрация, логин, защищённые эндпоинты
- 👤 Привязка задач к пользователю — каждый видит только свои задачи
- 📝 Полный CRUD — создание, чтение, обновление, удаление задач
- 🔍 Фильтры и пагинация — по статусу, приоритету,
skip/limit - 🗄 PostgreSQL 16 через SQLAlchemy 2.0 (typed Mapped API)
- 🔄 Alembic — миграции схемы БД
- 🐳 Docker + docker-compose — запуск одной командой
- 📖 Автогенерируемая документация — Swagger UI из коробки
- 🧪 13 тестов (pytest) — авторизация и CRUD
- ⚙️ CI/CD (GitHub Actions) — автозапуск тестов
| Слой | Технология |
|---|---|
| Web-фреймворк | FastAPI 0.115 |
| ORM | SQLAlchemy 2.0 |
| Миграции | Alembic 1.14 |
| База данных | PostgreSQL 16 |
| Валидация | Pydantic v2 + pydantic-settings |
| Аутентификация | JWT (python-jose) + bcrypt (passlib) |
| ASGI-сервер | Uvicorn |
| Тестирование | pytest 8.3 + httpx |
| CI/CD | GitHub Actions |
| Контейнеризация | Docker + docker-compose |
- Docker Desktop
- Git
git clone https://github.com/SmailsZX/task-tracker-api.git
cd task-tracker-api
cp .env.example .env
docker compose up --buildЧерез 1–2 минуты API будет доступен:
- 📖 Swagger UI — http://localhost:8000/docs
- 📄 ReDoc — http://localhost:8000/redoc
- ❤️ Healthcheck — http://localhost:8000/health
Проект использует Alembic для управления схемой БД.
alembic upgrade headПосле изменения моделей (app/models.py):
alembic revision --autogenerate -m "описание изменений"
alembic upgrade headalembic downgrade -1 # на одну миграцию назад
alembic downgrade base # откатить всёalembic/
├── versions/ # Файлы миграций
└── env.py # Конфигурация (URL из .env)
Проект покрыт тестами (pytest) — 13 тестов.
pytest tests/ -vАвторизация (tests/test_auth.py):
- ✅ Регистрация пользователя
- ✅ Регистрация с дублирующимся email
- ✅ Успешный логин (JWT)
- ✅ Логин с неверным паролем
- ✅ Получение текущего пользователя (
/auth/me) - ✅ Доступ без токена (401)
Задачи (tests/test_tasks.py):
- ✅ Создание задачи
- ✅ Получение списка задач
- ✅ Фильтрация по статусу
- ✅ Обновление задачи (PATCH)
- ✅ Удаление задачи
- ✅ Задача не найдена (404)
- ✅ Доступ без токена (401)
- SQLite в памяти — тесты не зависят от PostgreSQL.
- Фикстуры (
conftest.py):client— тестовый клиент с чистой БД для каждого теста.auth_client— клиент с JWT-токеном.
- Изоляция — каждый тест получает чистую БД.
def test_create_task(auth_client):
response = auth_client.post(
"/tasks",
json={"title": "Тестовая задача", "priority": "high"},
)
assert response.status_code == 201
assert response.json()["title"] == "Тестовая задача"| Метод | Путь | Описание | Auth |
|---|---|---|---|
POST |
/auth/register |
Регистрация нового пользователя | ❌ |
POST |
/auth/login |
Получить JWT-токен | ❌ |
GET |
/auth/me |
Информация о текущем пользователе | 🔒 |
| Метод | Путь | Описание | Auth |
|---|---|---|---|
GET |
/tasks |
Список задач (фильтры, пагинация) | 🔒 |
POST |
/tasks |
Создать задачу | 🔒 |
GET |
/tasks/{id} |
Получить задачу по ID | 🔒 |
PATCH |
/tasks/{id} |
Обновить задачу | 🔒 |
DELETE |
/tasks/{id} |
Удалить задачу | 🔒 |
| Метод | Путь | Описание |
|---|---|---|
GET |
/health |
Healthcheck |
Параметры фильтрации GET /tasks:
status—todo/in_progress/donepriority—low/medium/highskip— пропустить N записей (по умолчанию 0)limit— вернуть N записей (по умолчанию 20, максимум 100)
curl -X POST http://localhost:8000/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"secret123"}'curl -X POST http://localhost:8000/auth/login \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=user@example.com&password=secret123"Ответ:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer"
}TOKEN="вставь access_token сюда"
curl -X POST http://localhost:8000/tasks \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"Сделать апгрейд","description":"FastAPI + JWT + Docker","priority":"high"}'curl "http://localhost:8000/tasks?status=todo&priority=high&limit=10" \
-H "Authorization: Bearer $TOKEN"task-tracker-api/
├── app/
│ ├── main.py # Точка входа FastAPI
│ ├── config.py # Настройки через pydantic-settings
│ ├── database.py # Engine, SessionLocal, Base
│ ├── models.py # SQLAlchemy-модели (User, Task)
│ ├── schemas.py # Pydantic-схемы
│ ├── security.py # bcrypt + JWT-хелперы
│ ├── deps.py # Зависимости (get_db, get_current_user)
│ └── routers/
│ ├── auth.py # /auth/*
│ └── tasks.py # /tasks/*
├── alembic/ # Миграции (Alembic)
│ ├── versions/ # Файлы миграций
│ └── env.py # Конфигурация
├── tests/ # Тесты (pytest)
│ ├── conftest.py
│ ├── test_auth.py
│ └── test_tasks.py
├── .github/workflows/ # CI (GitHub Actions)
│ └── tests.yml
├── docs/ # Скриншоты Swagger UI
├── Dockerfile
├── docker-compose.yml
├── alembic.ini
├── requirements.txt
├── .env.example
└── README.md
- Пароли хешируются bcrypt (не sha256 — медленный + salt из коробки)
- JWT содержит
sub(email) иexp(60 минут по умолчанию) SECRET_KEYвынесен в переменные окружения (.envв.gitignore)- Все защищённые эндпоинты требуют
Authorization: Bearer <token> - Пользователь видит и редактирует только свои задачи (
owner_id == current_user.id)
- pytest + httpx — тесты на auth и CRUD (13 тестов)
- GitHub Actions — CI: pytest на каждый push
- Alembic — миграции вместо
Base.metadata.create_all - Пагинация с total —
{items: [...], total: N} - Rate limit на
/auth/loginчерез slowapi - Refresh-токены — длинные сессии без релогина
- Почему
bcrypt==4.0.1?passlib 1.7.4несовместим сbcrypt 4.1+— падает на внутреннем тесте сValueError: password cannot be longer than 72 bytes. Пин версии — самое простое решение. В проде лучше взятьargon2или валидировать длину пароля в Pydantic-схеме. - Alembic и ENUM. При
alembic downgrade baseENUM-типы (taskstatus,taskpriority) не удаляются автоматически. Если нужно откатить всё — удали их вручную:DROP TYPE IF EXISTS taskstatus CASCADE;
MIT — используй свободно.