Материал

FastAPI project

Самостоятельное задание: сервис кошельков на FastAPI и SQLAlchemy

Создайте новый публичный репозиторий или отдельную папку проекта. Задание выполняется с нуля и не зависит от веток или результатов предыдущих домашних работ.

Контекст сервиса

Сервис отвечает только за домен кошельков: хранение баланса и переводы между кошельками. Пользователь представлен внешним user_uid: UUID; собственной сущности пользователя нет. Аутентификация и авторизация не входят в это учебное задание. Локально сервис запускается как самостоятельное приложение. Для production отдельно потребовались бы trust model, защита от обхода gateway и проверка прав на операцию.

Минимальное окружение: Python, FastAPI, SQLAlchemy 2.x, Alembic, PostgreSQL, pytest и Docker Compose. Инструкции установки, запуска миграций и тестов должны находиться в README.

Задачи:

  1. SQLAlchemy.

Проработать архитектуру моделей сервиса по переводу денег. Нужно сделать сущность кошелек и сущность “транзакция”/перевод. Кошельки привязаны к пользователям (user_uid: UUID, uuid из другой системы).
Проработать ограничения реализации.

Чем пользуемся:

  1. Лекция :)
  2. SQLAlchemy модели https://docs.sqlalchemy.org/en/20/orm/quickstart.html#declare-models
  3. Alembic migrations.
  4. https://alembic.sqlalchemy.org/en/latest/tutorial.html (doc) Что сделать:
  5. Составить список возможных вопросов и предложения решения проблем
  6. Например: «Может ли баланс кошелька уходить в минус?» — «Нет». Тогда рассматриваем ограничение на уровне БД и корректную обработку конкурентных операций.
  7. Все непонятные вещи уточнить у нас (тренируемся формировать требования)
  8. Реализовать сущности и миграцию.
  9. Обдумать, какие нужны индексы и ограничения.
  10. Добавить миграцию Alembic.
  11. FastAPI handlers. Реализовать ручки получения баланса кошелька (отдельно по user_uid, отдельно по wallet_id). Реализовать ручку с переводом денег с одного кошелька на другой
  12. Реализовать ручки
  13. GET /wallet/{id} — получение баланса кошелька. Учесть валидацию; если кошелёк отсутствует, вернуть 404 Not Found.
  14. GET /users/{user_uid}/wallet
  15. POST или PUT /wallet/transaction — обосновать выбор метода, URI ресурса и модель идемпотентности.
  16. Покрыть тестами все сценарии
  17. Подумать и реализовать идемпотентный перевод денег
  18. Подумать и реализовать конкурентный перевод денег Полезно изучить:
  19. Авторский курс Сергея по FastAPI
  20. Тестирование ручек
  21. Testing - FastAPI
  22. Блокировки строк и уровни изоляции для конкурентных изменений
  23. Лекция 🙂
  24. PostgreSQL: explicit locking
  25. SQLAlchemy: SELECT … FOR UPDATE Дополнительные задания:
  26. Добавить Redis в Docker Compose.
  27. Добавить кэширование GET-операции получения баланса и продумать инвалидацию кэша при переводе.

Примеры сервисов

Пример реализации простого сервиса с ручками:

  • GitHub - takentui/backend: Simple backend example

Критерии готовности

  • проект с нуля запускается по README и поднимает PostgreSQL через Docker Compose;
  • Alembic применяет миграции к пустой базе;
  • модели кошелька и перевода содержат обоснованные типы, constraints, indexes и связи;
  • API возвращает корректные 2xx, 404 и 409/422 для выбранных ошибочных сценариев;
  • перевод выполняется в одной транзакции и не допускает отрицательного баланса при конкурентных запросах;
  • повтор запроса с тем же idempotency key не создаёт второй перевод;
  • тесты проверяют успешный перевод, недостаток средств, отсутствующий кошелёк, повтор idempotency key и конкурентное списание;
  • секреты и локальный .env не находятся в репозитории; присутствует безопасный .env.example;
  • дополнительный Redis-кэш, если реализован, не является источником истины и инвалидируется после перевода.