Sunday, 23 November 2025

Dockerization of the above Tutorial

FastAPI + PostgreSQL + Docker — Full CRUD Tutorial

🚀 FastAPI + PostgreSQL + Docker — Full CRUD Tutorial (Production Ready)

Welcome to the most complete hands-on FastAPI tutorial for students! This guide will show you how to build a real CRUD API using:

  • FastAPI
  • PostgreSQL (real database)
  • SQLAlchemy ORM
  • Alembic migrations
  • Docker & Docker Compose

🐳 Why Docker? (Simple Explanation)

Docker allows you to package your entire FastAPI project and PostgreSQL database in one portable environment.

Benefits for Students:

  • No need to separately install PostgreSQL.
  • No database configuration headaches.
  • The whole app runs using ONE command: docker-compose up --build
  • Everyone in the class runs the same environment.

What Docker Compose Does

ServiceDescription
dbRuns PostgreSQL database in a container
apiRuns FastAPI server inside its own container

This is modern industry practice — and perfect for teaching!

📁 Project Structure


project/
│── app/
│   │── main.py
│   │── database.py
│   │── models.py
│   │── schemas.py
│   │── crud.py
│   │── __init__.py
│── Dockerfile
│── docker-compose.yml
│── requirements.txt

1️⃣ database.py — Database Connection


from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, declarative_base

DATABASE_URL = "postgresql://postgres:postgres@db:5432/fastapi_db"

engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(bind=engine, autocommit=False, autoflush=False)

Base = declarative_base()

2️⃣ models.py — SQLAlchemy ORM Model


from sqlalchemy import Column, Integer, String, Float, Boolean
from .database import Base

class Item(Base):
    __tablename__ = "items"

    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, index=True)
    price = Column(Float)
    description = Column(String, nullable=True)
    in_stock = Column(Boolean, default=True)

3️⃣ schemas.py — Pydantic Models


from pydantic import BaseModel

class ItemBase(BaseModel):
    name: str
    price: float
    description: str | None = None
    in_stock: bool = True

class ItemCreate(ItemBase):
    pass

class Item(ItemBase):
    id: int
    class Config:
        orm_mode = True

4️⃣ crud.py — All CRUD Operations


from sqlalchemy.orm import Session
from . import models, schemas

def create_item(db: Session, item: schemas.ItemCreate):
    db_item = models.Item(**item.dict())
    db.add(db_item)
    db.commit()
    db.refresh(db_item)
    return db_item

def get_items(db: Session):
    return db.query(models.Item).all()

def get_item(db: Session, id: int):
    return db.query(models.Item).filter(models.Item.id == id).first()

def update_item(db: Session, id: int, new_data: schemas.ItemCreate):
    item = db.query(models.Item).filter(models.Item.id == id).first()
    if item:
        for k, v in new_data.dict().items():
            setattr(item, k, v)
        db.commit()
        db.refresh(item)
    return item

def delete_item(db: Session, id: int):
    item = db.query(models.Item).filter(models.Item.id == id).first()
    if item:
        db.delete(item)
        db.commit()
    return item

5️⃣ main.py — FastAPI Routes


from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.orm import Session

from . import models, schemas, crud
from .database import engine, SessionLocal

# Create tables
models.Base.metadata.create_all(bind=engine)

app = FastAPI(title="FastAPI + Postgres CRUD")

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

@app.post("/items/", response_model=schemas.Item)
def create(item: schemas.ItemCreate, db: Session = Depends(get_db)):
    return crud.create_item(db, item)

@app.get("/items/", response_model=list[schemas.Item])
def read_all(db: Session = Depends(get_db)):
    return crud.get_items(db)

@app.get("/items/{id}", response_model=schemas.Item)
def read_one(id: int, db: Session = Depends(get_db)):
    item = crud.get_item(db, id)
    if not item:
        raise HTTPException(404, "Item not found")
    return item

@app.put("/items/{id}", response_model=schemas.Item)
def update(id: int, item: schemas.ItemCreate, db: Session = Depends(get_db)):
    updated = crud.update_item(db, id, item)
    if not updated:
        raise HTTPException(404, "Item not found")
    return updated

@app.delete("/items/{id}")
def delete(id: int, db: Session = Depends(get_db)):
    deleted = crud.delete_item(db, id)
    if not deleted:
        raise HTTPException(404, "Item not found")
    return {"message": "Deleted successfully"}

🐳 Dockerfile


FROM python:3.11

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY ./app ./app

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

🐳 docker-compose.yml


version: "3.9"

services:
  db:
    image: postgres:15
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: fastapi_db
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data

  api:
    build: .
    ports:
      - "8000:8000"
    depends_on:
      - db

volumes:
  pgdata:

📦 requirements.txt


fastapi
uvicorn
sqlalchemy
psycopg2-binary
pydantic

▶ How to Run Everything

1️⃣ Build + Start all containers

docker-compose up --build

2️⃣ Open your browser

http://127.0.0.1:8000/docs

✔ Ready for CRUD ✔ Auto docs ✔ Real PostgreSQL ✔ Production ready

No comments:

Post a Comment

FAST API - Intro

 https://fastapi-hha68n1.gamma.site/