Material

FastAPI project

Independent task: wallet service on FastAPI and SQLAlchemy

Create a new public repository or a separate project folder. The task is completed from scratch and does not depend on branches or the results of previous homework.

Service context

The service is responsible only for the wallet domain: storing the balance and transfers between wallets. The user is represented by an external user_uid: UUID; there is no user entity of its own. Authentication and authorization are not covered in this tutorial. Locally, the service runs as a standalone application. For production, a trust model, protection against gateway bypass, and verification of operation rights would be separately required.

Minimal environment: Python, FastAPI, SQLAlchemy 2.x, Alembic, PostgreSQL, pytest and Docker Compose. Instructions for installation, running migrations and tests should be in the README.

Tasks:

  1. SQLAlchemy.

Work out the architecture of money transfer service models. You need to create a wallet entity and a “transaction”/transfer entity. Wallets are tied to users (user_uid: UUID, uuid from another system).
Work through implementation limitations.

What we use:

  1. Lecture :)
  2. SQLAlchemy models https://docs.sqlalchemy.org/en/20/orm/quickstart.html#declare-models
  3. Alembic migrations.
  4. https://alembic.sqlalchemy.org/en/latest/tutorial.html (doc) What to do:
  5. Make a list of possible questions and suggestions for solutions to problems
  6. For example: “Can the wallet balance go negative?” - "No". Then we consider restrictions at the database level and correct processing of competitive operations.
  7. All unclear things should be clarified with us (we are training to formulate requirements)
  8. Implement entities and migration.
  9. Consider what indexes and constraints are needed.
  10. Add Alembic migration.
  11. FastAPI handlers. Implement handles for obtaining the wallet balance (separately by user_uid, separately by wallet_id). Implement a handle for transferring money from one wallet to another
  12. Implement handles
  13. GET /wallet/{id} — getting the wallet balance. Consider validation; if the wallet is missing, return it 404 Not Found.
  14. GET /users/{user_uid}/wallet
  15. POST or PUT /wallet/transaction — justify the choice of method, resource URI and idempotency model.
  16. Cover all scenarios with tests
  17. Think about and implement idempotent money transfer
  18. Think about and implement competitive money transfer Useful to learn:
  19. Sergey's original course on FastAPI
  20. Handle testing
  21. Testing - FastAPI
  22. Row locks and isolation levels for concurrent changes
  23. Lecture :)
  24. PostgreSQL: explicit locking
  25. SQLAlchemy: SELECT … FOR UPDATE Additional tasks:
  26. Add Redis to Docker Compose.
  27. Add caching of the GET operation for obtaining a balance and consider invalidating the cache during translation.

Examples of services

An example of implementing a simple service with handles:

  • GitHub - takentui/backend: Simple backend example

Readiness criteria

  • a project is launched from scratch using the README and PostgreSQL is raised via Docker Compose;
  • Alembic applies migrations to an empty database;
  • wallet and transfer models contain reasonable types, constraints, indexes and connections;
  • API returns correct 2xx, 404 and 409/422 for selected error scenarios;
  • the transfer is performed in one transaction and does not allow a negative balance for competitive requests;
  • repeating the request with the same idempotency key does not create a second translation;
  • tests check for successful transfer, insufficient funds, missing wallet, idempotency key repeat and competitive debit;
  • secrets and local .env are not in the repository; safe present .env.example;
  • the additional Redis cache, if implemented, is not a source of truth and is invalidated after translation.