A simple and clean FastAPI backend for managing personal expenses with user authentication, category management, and comprehensive expense tracking.
- π JWT Authentication - Secure user registration and login with Argon2 password hashing
- π€ User Management - User registration, authentication
- π Category Management - Create, list, and delete expense categories
- π° Expense Tracking - Full CRUD operations for expenses with:
- Multiple currency support (EUR, USD)
- Pagination and filtering
- Amount range queries
- Category-based filtering
- π Reporting - Summary views by category and month
- π Optimistic Locking - Prevents concurrent update conflicts
- β Comprehensive Testing - Full test coverage with pytest
- ποΈ SQLite Database - Easy setup with SQLAlchemy ORM
- Python 3.12+
- uv package manager
- Clone the repository
git clone https://github.com/ContentGardeningStudio/expenses-api
cd expenses-api- Create virtual environment
uv venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate- Install dependencies
uv sync- Run the application
fastapi dev src/expenses_api/main.py- Access the API
- API: http://127.0.0.1:8000
- Interactive docs: http://127.0.0.1:8000/docs
- Alternative docs: http://127.0.0.1:8000/redoc
expenses-api/
βββ src/expenses_api/
β βββ main.py # FastAPI application entry point
β βββ database.py # Database configuration
β βββ models.py # SQLAlchemy models
β βββ schemas.py # Pydantic schemas
β βββ crud.py # Database operations
β βββ security.py # Authentication & password hashing
β βββ settings.py # Configuration management
β βββ deps.py # Dependency injection
β βββ seed.py # Database seeding script
β βββ routers/
β βββ auth.py # Authentication endpoints
β βββ categories.py # Category endpoints
β βββ expenses.py # Expense endpoints
βββ tests/
β βββ conftest.py # Test fixtures
β βββ test_crud.py # CRUD logic tests
β βββ test_routers.py # API endpoint tests
βββ pyproject.toml # Project dependencies
βββ README.md
βββ CONTRIBUTING.md
POST /auth/register
Content-Type: application/json
{
"username": "johndoe",
"password": "securepass123"
}POST /auth/token
Content-Type: application/x-www-form-urlencoded
username=johndoe&password=securepass123Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer"
}Include the token in all protected endpoints:
Authorization: Bearer <your_access_token>| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| GET | /categories |
List all categories | β |
| POST | /categories |
Create a new category | β |
| DELETE | /categories/{id} |
Delete a category | β |
Create Category Example:
POST /categories
{
"name": "Groceries"
}| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| GET | /expenses |
List expenses (paginated) | β |
| GET | /expenses/{id} |
Get expense by ID | β |
| POST | /expenses |
Create a new expense | β |
| DELETE | /expenses/{id} |
Delete an expense | β |
Create Expense Example:
POST /expenses
{
"category_id": 1,
"amount": "125.50",
"currency": "EUR",
"name": "Weekly groceries"
}List Expenses with Filters:
GET /expenses?page=1&size=20&category_id=1&min_amount=50&max_amount=200Query Parameters:
page- Page number (default: 1)size- Items per page (default: 50, max: 200)category_id- Filter by categorymin_amount- Minimum amount filtermax_amount- Maximum amount filter
Run the test suite:
# Run all tests
pytest
# Run with coverage
pytest --cov=expenses_api
# Run specific test file
pytest tests/test_routers.py
# Run with verbose output
pytest -vTest Coverage Includes:
- β User registration and authentication
- β JWT token generation and validation
- β Category CRUD operations
- β Expense CRUD operations
- β Pagination and filtering
- β Optimistic locking
- β Error handling
- β Database constraints
The database is automatically created on first run. Tables:
users- User accountscategories- Expense categoriesexpenses- Expense records
python -m expenses_api.seedThis creates:
- 15 random categories
- 200 sample expenses
Create a .env file in the project root:
# Database
DATABASE_URL=sqlite:///./expenses.db
# Security
SECRET_KEY=your-secret-key-change-this-in-production
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=30
# Debug
DEBUG=True| Technology | Purpose |
|---|---|
| FastAPI | Modern web framework |
| SQLAlchemy | ORM for database operations |
| Pydantic | Data validation |
| Argon2 | Password hashing |
| Python-JOSE | JWT token handling |
| Pytest | Testing framework |
| UV | Fast dependency management |
| SQLite | Lightweight database |
- Base project structure
- User authentication
- Categories & expenses CRUD
- Database initialization
- Comprehensive tests
- Custom error handling
- Enhanced validation rules
- Advanced pagination
- Structured logging
- Environment configuration
- Date range filtering
- Monthly/yearly reports
- Soft delete functionality
- CSV/Excel export
- Expense summaries
- User-specific data isolation
- Role-based permissions
- User β Categories β Expenses hierarchy
- Docker containerization
- Production server setup (Gunicorn + Uvicorn)
- Cloud deployment (Railway, Render, Fly.io)
- CI/CD pipeline
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
Steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is open source and available under the MIT License.
Leonel Noan
Email: leonelnoan@contentgardening.com
- FastAPI for the excellent framework
- SQLAlchemy for robust ORM capabilities
- The Python community for amazing tools
- π§ Email: leonelnoan@contentgardening.com
- π Issues: GitHub Issues
- π Documentation: http://127.0.0.1:8000/docs
Happy expense tracking! π°π